Calcite 原理解析

Apache Calcite 是獨立于存儲與執(zhí)行的SQL解析、優(yōu)化引擎驶兜,廣泛應(yīng)用于各種離線维费、搜索果元、實時查詢引擎,如Drill犀盟、Hive而晒、Kylin、Solr阅畴、flink倡怎、Samza等。本文結(jié)合hive中基于代價的優(yōu)化贱枣,解析calcite優(yōu)化引擎的實現(xiàn)原理监署。


Calcite架構(gòu)
??Calcite架構(gòu)圖如下,其中Operator Expressions 是查詢樹在calcite中的表示纽哥,可以直接通過calcite的SQL Parser解析得到钠乏,也可以通過Expressions Builder由Data Processing System中的查詢樹(本文對應(yīng)hive中的AST)轉(zhuǎn)換得到。Query Optimizer 根據(jù)Pluggable Rules對Operator Expressions進(jìn)行優(yōu)化春塌,其中會用到Metadata Providers提供的信息進(jìn)行代價計算等操作晓避。


Hive CBO
??本文中Data Processing System就是hive,本文主要解析hive如何利用calcite進(jìn)行基于代價的優(yōu)化(cost based optimization /CBO)只壳。Hive CBO的主要實現(xiàn)代碼在CalcitePlanner 這個類中, CalcitePlanner 繼承自SemanticAnalyzer俏拱,重寫了genOPTree 方法,由AST 生成 Operator Tree 吼句。其中CalcitePlanner.CalcitePlannerAction.genLogicalPlan 函數(shù)對應(yīng)上圖中的Expressions Builder锅必,把hive中的AST轉(zhuǎn)換成calcite 中的Operator Expressions,也就是節(jié)點為RelNode的查詢樹惕艳。這個過程這里不展開搞隐,繼續(xù)往下看。在CalcitePlanner.CalcitePlannerAction.HepPlan會對輸入的basePlan根據(jù)rules進(jìn)行優(yōu)化远搪,返回優(yōu)化過的plan劣纲,代碼如下:


??這里hive使用calcite的HepPlanner作為優(yōu)化引擎(另一個選擇是VolcanoPlanner),可以看到向planner輸入原始的查詢樹终娃、Metadata Providers、Rules蒸甜,調(diào)用findBestExp()棠耕,返回優(yōu)化后的查詢樹。與上面的架構(gòu)圖對應(yīng)柠新。下面我們來詳細(xì)分析這幾個部分是如何交互窍荧,完成優(yōu)化的。


主要數(shù)據(jù)結(jié)構(gòu)
??下圖列出了calcite中主要的相關(guān)接口和類恨憎,以及其中比較重要的成員蕊退。


??RelOptCluster 為查詢優(yōu)化過程中的環(huán)境信息郊楣,包含RelOptPlanner、MetadataFactory等信息瓤荔,MetadataFactory可以看成RelMetadataProvider的一個工廠净蚤,calcite中MetadataFactoryImpl實現(xiàn)了MetadataFactory接口,其利用Guava Cache對RelMetadataProvider進(jìn)行緩存输硝。
??RelNode代表了Operator Expressions中的一個節(jié)點今瀑,往往以根節(jié)點代表整個查詢樹。函數(shù)getCluster()可以得到當(dāng)前cluster点把。
RelOptRule表示優(yōu)化規(guī)則橘荠,是抽象類,calcite實現(xiàn)了很多優(yōu)化規(guī)則郎逃,用戶也可以實現(xiàn)自己的規(guī)則哥童。其中有兩個重要的函數(shù):matches(RelOptRuleCall) 判斷規(guī)則是否匹配當(dāng)前RelNode;當(dāng)匹配的時候會調(diào)用onMatch(RelOptRuleCall)褒翰。
??RelMetadataProvider是如何獲得relational expressions的matadata的接口贮懈,只有一個函數(shù) apply(...),這么說可能不是很明了影暴,下文的例子會詳細(xì)講错邦。
??HepPlanner就是根據(jù)rules進(jìn)行優(yōu)化的類,其成員mainProgram可以看成根據(jù)rules等信息生成的優(yōu)化策略型宙,會具體指導(dǎo)優(yōu)化過程撬呢;graph是封裝了Operator Expressions的有向圖。其成員函數(shù)findBestExp()是優(yōu)化的入口妆兑,返回優(yōu)化過的Operator Expressions魂拦。執(zhí)行時會多次調(diào)用applyRule(...) 函數(shù),其中就會調(diào)用到RelOptRule的matches(RelOptRuleCall)和onMatch(RelOptRuleCall)搁嗓。


優(yōu)化流程
??優(yōu)化的主入口是HepPlanner.findBestExp()芯勘,其中會調(diào)用executeProgram(mainProgram),mainProgram 由Instructions組成腺逛,Instruction主要是RuleCollection荷愕,也有MatchOrder、MatchLimit等棍矛。對于RuleCollection安疗,executeInstruction就是對每一個rule進(jìn)行apply,這里以HiveReduceExpressionsRule為例往下分析够委,在HepPlanner.applyRule函數(shù)中可以看到荐类,首先調(diào)用matchOperands以及HiveReduceExpressionsRule.matches判斷此規(guī)則是否匹配,若匹配則調(diào)用fireRule(call)茁帽,會進(jìn)到HiveReduceExpressionsRule.onMatch函數(shù)進(jìn)行這條規(guī)則的具體優(yōu)化玉罐,時序圖如下:


??這里我們不展開討論HiveReduceExpressionsRule具體做了什么屈嗤,主要來看一下其怎么利用RelMetadataQuery進(jìn)行metadata訪問的。RelMetadataQuery可以看成metadata的訪問媒介吊输,實際訪問的metadata由RelNode的MetadataFactory提供饶号。在BuiltInMetadata中定義了所有metadata的接口,hive通過RelMetadataProvider實現(xiàn)了這些接口璧亚,并注冊到MetadataFactory中讨韭。
??RelMetadataProvider有好幾個實現(xiàn)類,其中最重要的是ReflectiveRelMetadataProvider癣蟋,這個類通過java的動態(tài)代理機(jī)制綁定hive的metadata實現(xiàn)透硝。具體可見ReflectiveRelMetadataProvider.reflectiveSource的實現(xiàn)。部分代碼如下:

private static RelMetadataProvider reflectiveSource(final Object target,
    final ImmutableList<Method> methods) {
  ...
  final Set<Class<RelNode>> classes = Sets.newHashSet();
  final Map<Pair<Class<RelNode>, Method>, Method> handlerMap =
      Maps.newHashMap();
  for (final Method handlerMethod : target.getClass().getMethods()) {
    for (Method method : methods) {
      if (couldImplement(handlerMethod, method)) {
        @SuppressWarnings("unchecked") final Class<RelNode> relNodeClass =
            (Class<RelNode>) handlerMethod.getParameterTypes()[0];
        classes.add(relNodeClass);
        handlerMap.put(Pair.of(relNodeClass, method), handlerMethod);
      }
    }
  }

  final ConcurrentMap<Class<RelNode>, UnboundMetadata> methodsMap = new ConcurrentHashMap<>();
  for (Class<RelNode> key : classes) {
    ImmutableNullableList.Builder<Method> builder =
        ImmutableNullableList.builder();
    for (final Method method : methods) {
      builder.add(find(handlerMap, key, method));
    }
    final List<Method> handlerMethods = builder.build();
    final UnboundMetadata function =
        new UnboundMetadata() {
          public Metadata bind(final RelNode rel,
              final RelMetadataQuery mq) {
            return (Metadata) Proxy.newProxyInstance(
                metadataClass0.getClassLoader(),
                new Class[]{metadataClass0},
                new InvocationHandler() {
                  public Object invoke(Object proxy, Method method,
                      Object[] args) throws Throwable {
     ...
                    try {
                      return handlerMethod.invoke(target, args1);
                    } catch (InvocationTargetException
                        | UndeclaredThrowableException e) {
                      Throwables.propagateIfPossible(e.getCause());
                      throw e;
                    } finally {
                      mq.set.remove(key);
                    }
                  }
                });
          }
        };
    methodsMap.put(key, function);
  }
  return new ReflectiveRelMetadataProvider(methodsMap, metadataClass0);
}

??函數(shù)的第一個參數(shù)target是hive實現(xiàn)的某個metadata的實現(xiàn)類疯搅,第二個參數(shù)methods是實現(xiàn)的目標(biāo)接口濒生。函數(shù)會找出target中對接口的實現(xiàn)函數(shù),并將該實現(xiàn)函數(shù)的第一個參數(shù)作為key放在map中幔欧。之后在訪問matadata的時候罪治,會以當(dāng)前RelNode的實際類型為key,在map中查找實現(xiàn)函數(shù)礁蔗。如果沒有以當(dāng)前RelNode的實際類型為第一個參數(shù)的具體實現(xiàn)觉义,就會有空指針異常。這里有我向hive提交的一個patch(HIVE-19202)浴井,就是這樣的問題晒骇。


總結(jié)
本文介紹了calcite的架構(gòu)及hive利用calcite進(jìn)行CBO的部分源碼分析。我們了解了一個數(shù)據(jù)處理系統(tǒng)可以如何通過擴(kuò)展calcite的rule和metadata接口實現(xiàn)自定義的優(yōu)化處理磺浙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洪囤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撕氧,更是在濱河造成了極大的恐慌瘤缩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伦泥,死亡現(xiàn)場離奇詭異剥啤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)不脯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門府怯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人跨新,你說我怎么就攤上這事富腊』捣辏” “怎么了域帐?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵赘被,是天一觀的道長。 經(jīng)常有香客問我肖揣,道長民假,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任龙优,我火速辦了婚禮羊异,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘彤断。我一直安慰自己野舶,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布宰衙。 她就那樣靜靜地躺著平道,像睡著了一般。 火紅的嫁衣襯著肌膚如雪供炼。 梳的紋絲不亂的頭發(fā)上固以,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天耽梅,我揣著相機(jī)與錄音,去河邊找鬼。 笑死惧所,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厕氨。 我是一名探鬼主播侠姑,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疫蔓!你這毒婦竟也來了含懊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤衅胀,失蹤者是張志新(化名)和其女友劉穎岔乔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滚躯,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡雏门,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掸掏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茁影。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖丧凤,靈堂內(nèi)的尸體忽然破棺而出募闲,到底是詐尸還是另有隱情,我是刑警寧澤愿待,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布浩螺,位于F島的核電站靴患,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏要出。R本人自食惡果不足惜鸳君,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望患蹂。 院中可真熱鬧或颊,春花似錦、人聲如沸传于。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沼溜。三九已至看铆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盛末,已是汗流浹背弹惦。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留悄但,地道東北人棠隐。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像檐嚣,于是被迫代替她去往敵國和親助泽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容