Catalyst Optimizer最佳化器,catalystoptimizer

來源:互聯網
上載者:User

Catalyst Optimizer最佳化器,catalystoptimizer

更多參見ChenZhongPu’s Gitbook :
https://www.gitbook.com/book/chenzhongpu/bigdatanotes/details

Spark SQL的最佳化器Catalyst是易於擴充的。它同時支援基於規則(rule-based)和基於代價(cost-based)的最佳化方法。

在它內部,Catalyst包含了一個表示樹和操作樹的規則的通用庫。在此架構下,目前實現了針對關係查詢處理(如,運算式,邏輯查詢計劃)的庫,和在處理查詢執行不同階段(分析,邏輯最佳化,物理最佳化,代碼產生)的一些規則。

Tree

在Catalyst主要的資料類型就是由節點對象組成的樹。每個節點都有一個節點類型和0至多個孩子。新節點類型都是Scala裡面TreeNode的子類。

Add(Attribute(x), Add(Literal(1), Literal(2)))

Rules

可以使用規則(rules)操縱樹,也就是將一棵樹轉化成另一顆樹的方法。雖然規則可以在輸入的樹上執行任意代碼(因為樹也僅是一個Scala對象),但通常的做法是使用一系列的pattern matching方法來尋找並使用特定的結果來替換子樹。

比如,我們下面實現了摺疊(folds)常量間的Add操作:

    tree.transform {      case Add(Literal(c1), Literal(c2)) => Literal(c1+c2)    }

這樣,對x+(1+2)的樹使用該規則,就會產生一顆新樹x+3

在一個轉化的調用中,規則可以進行多次match pattern。

最後,規則的條件及內容是可以包含任意代碼的。這使得Catalyst能夠對初級使用者更簡單。

另外,樹的轉化(transformation)都是在不可變(immutable)樹上進行的,這易於調試,也更有利於最佳化器的並行。

Using Catalyst in Spark SQL

Analysis

不管是由SQL parser得到的AST(abstract syntax tree)還是使用API構建的DataFrame對象,關係(relation)裡面肯定包含了未解析(unresolved)的屬性引用或關係:比如SELECT col FROM sales,直到我們查詢sales這張表,我們才知道col的類型,甚至col是否是一個合法的列名。

An attribute is called unresolved if we do not know its type or have not matched it to an input table (or an alias)

Spark SQL使用Catalyst規則和追蹤資料來源裡tables的Catalog對象來解析這些屬性。

這部分代碼位於 org.apache.spark.sql.catalyst.analysis.Analyzer.scala

Logical Optimizations

邏輯最佳化是完全基於規則(rule-based)的。

包括:常量摺疊(constant folding)、謂詞下推(predicate pushdown)、投影減枝(project pruning)、null propagation、BOOL運算式簡化,等等。

predicata pushdown :將外層查詢塊的 WHERE 子句中的謂詞移入所包含的較低層查詢塊(例如視圖),從而能夠提早進行資料過濾以及有可能更好地利用索引。

針對不同的情況,添加規則也是及其簡單的。

比如下面簡化LIKE運算式的:

object LikeSimplification extends Rule[LogicalPlan] {  val startsWith = "([^_%]+)%".r  val endsWith = "%([^_%]+)".r  val contains = "%([^_%]+)%".r  val equalTo = "([^_%]*)".r  def apply(plan: LogicalPlan): LogicalPlan = plan transformAllExpressions {    case Like(l, Literal(startsWith(pattern), StringType)) if !pattern.endsWith("\\") =>      StartsWith(l, Literal(pattern))    case Like(l, Literal(endsWith(pattern), StringType)) =>      EndsWith(l, Literal(pattern))    case Like(l, Literal(contains(pattern), StringType)) if !pattern.endsWith("\\") =>      Contains(l, Literal(pattern))    case Like(l, Literal(equalTo(pattern), StringType)) =>      EqualTo(l, Literal(pattern))  }}

這段代碼的注釋是:
>
Simplifies LIKE expressions that do not need full regular expressions to evaluate the condition.
For example, when the expression is just checking to see if a string starts with a given pattern.

這部分代碼位於org.apache.spark.sql.catalyst.optimizer.Optimizer.scala

Physical Planning

在物理計劃階段,Spark SQL通過邏輯計劃產生一個或多個物理計劃,然後使用代價模型(cost model)選擇一個計劃。

目前,代碼模型只在選擇Join演算法時被用到:如果一個關係很小,SparkSQL將使用broadcast join,利用其peer-to-peer的broadcast特性。代價模型今後可以被推廣在其他演算法選擇上。

物理計劃也會執行基於規則的的最佳化。

這部分代碼位於org.apache.spark.sql.execution.SparkStrategies.scala

Code Generation

在運行時產生Java子節碼是最後階段的查詢最佳化。

因為Spark SQL基本都是在記憶體資料集上操作,這是CPU-bound的,所以產生代碼可以加速運行。

代碼產生引擎是很難實現的,基本相當於一個編譯器。但是,依賴Scala語言的新特性Quasiquotes,使得它簡單得多。Quasiquotes允許程式構建抽象文法樹(abstract syntax trees),在運行時提交給編譯器產生子節碼。

比如 (x+y)+1,如果沒有代碼產生,這樣的運算式會針對每行資料解釋,來遍曆樹的節點,這樣會引入大量分支和虛方法的調用。

def compile(node: Node): AST = node match {  case Literal(value) => q"$value"  case Attribute(name) => q"row.get($name)"  case Add(left, right) => q"${compile(left)} + ${compile(right)}"}

這部分代碼位於org.spark.sql.catalyst.expressions.codegen.CodeGenerator.scala

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.