您好,登錄后才能下訂單哦!
??一個schema adapter允許Calcite去讀取特定類型的數據,將這些數據以一種table格式schema展示出來。
? Cassandra adapter (calcite-cassandra)
? CSV adapter (example/csv)
? Druid adapter (calcite-druid)
? Elasticsearch adapter(calcite-elasticsearch3 and calcite-elasticsearch6)
? File adapter (calcite-file)
? JDBC adapter (part of calcite-core)
? MongoDB adapter (calcite-mongodb)
? OS adapter (calcite-os)
? Pig adapter (calcite-pig)
? Solr cloud adapter (solr-sql)
? Spark adapter (calcite-spark)
? Splunk adapter (calcite-splunk)
? Eclipse Memory Analyzer (MAT) adapter (mat-calcite-plugin)
? Piglet (calcite-piglet) runs queries in a subset of Pig Latin
??許多項目和產品使用Apache Calcite進行SQL解析,查詢優化,數據虛擬化/聯邦以及物化視圖重寫。其中一些在“powered by Calcite”頁面。
??驅動程序允許您從應用程序連接到Calcite。
? JDBC Driver(Java Doc)
??JDBC驅動程序由Avatica提供 支持。連接可以是本地或遠程的(HTTP上的JSON或HTTP上的Protobuf)。
JDBC連接字符串參數
屬性 | 描述 |
---|---|
approximateDecimal | 是否可以接受DECIMAL類型上的聚合函數的近似結果 |
approximateDistinctCount | 是否可以接受聚合函數COUNT(DISTINCT …)的近似結果 |
approximateTopN | 是否可以接受”TopN”查詢(ORDER BY aggFun() DESC LIMIT n)的近似結果 |
caseSensitive | 標識符是否區分大小寫。如果未指定,則使用來自于lex的值。 |
conformance | SQL一致性級別。值:DEFAULT(默認,類似于PRAGMATIC_2003),LENIENT,MYSQL_5,ORACLE_10,ORACLE_12,PRAGMATIC_99,PRAGMATIC_2003,STRICT_92,STRICT_99,STRICT_2003,SQL_SERVER_2008。 |
createMaterializations | Calcite是否創建物化的東西。默認false |
defaultNullCollation | 如果在查詢中既不指定NULLS FIRST也不指定NULLS LAST,應如何對NULL值進行排序。缺省值為HIGH,與Oracle相同,對NULL值進行排序。 |
druidFetch | 執行一次SELECT查詢時,Druid適配器應該讀取多少行。 |
forceDecorrelate | 計劃器是否應該盡可能地相互關聯。默認為true。 |
fun | 內置函數和運算符的集合。有效值是“標準”(默認),“oracle”,“空間”,并可以使用逗號連接組合,例如“oracle,spatial”。 |
lex | 詞匯(關鍵字)策略。值是ORACLE(默認),MYSQL,MYSQL_ANSI,SQL_SERVER,JAVA。 |
materializationsEnabled | Calcite是否使用物化的東西。默認false |
model | JSON模型文件的URI |
parserFactory | 解析器工廠。實現SqlParserImplFactory 接口的類的名稱,并且有一個公有的默認構造方法或者INSTANCE常量 |
quoting | 如何引用標識符。值是DOUBLE_QUOTE,BACK_QUOTE,BRACKET。如果未指定,則使用來自于lex的值。 |
quotedCasing | 如何存儲使用了引號的標識符。值是UNCHANGED, TO_UPPER, TO_LOWER。如果未指定,則使用來自于lex的值。 |
schema | 初始化schema名稱 |
schemaFactory | Schema工廠。實現SchemaFactory接口的類的名稱,并且有一個公有的默認構造方法或者INSTANCE常量。如果指定了model,此屬性會被忽略。 |
schemaType | Schema類型。值必須是“MAP”(默認值),“JDBC”或“CUSTOM”。(如果schemaFactory指定則隱式指定為CUSTOM類型)如果指定了model,此屬性會被忽略。 |
spark | 指定是否應將Spark用作無法推送到源系統的處理引擎。如果為false(默認值),則Calcite將生成實現了Enumerable接口的代碼。 |
timeZone | 時區,例如“gmt-3”。默認是JVM的時區。 |
typeSystem | 類型系統。實現了接口RelDataTypeSystem的類的名稱,并具有公有的默認構造函數或INSTANCE常量。 |
unquotedCasing | 如果標識符未被引用,如何存儲。有效值是UNCHANGED,TO_UPPER,TO_LOWER。如果未指定,則使用來自于lex的值。 |
??如果僅僅連接到一個基于內置shema類型的模型,不需要指定model。例如:
jdbc:calcite:schemaType=JDBC; schema.jdbcUser=SCOTT; schema.jdbcPassword=TIGER; schema.jdbcUrl=jdbc:hsqldb:res:foodmart
??通過JDBC Schema適配器創建一個映射到foodmart數據庫的連接。
??相似的,可以連接到基于用戶定義的schema適配器的單一schema。例如:
jdbc:calcite:schemaFactory=org.apache.calcite.adapter.cassandra.CassandraSchemaFactory; schema.host=localhost; schema.keyspace=twissandra
??創建一個連接到Cassandra適配器連接,與如下的模型文件等效:
{
"version": "1.0",
"defaultSchema": "foodmart",
"schemas": [
{
type: 'custom',
name: 'twissandra',
factory: 'org.apache.calcite.adapter.cassandra.CassandraSchemaFactory',
operand: {
host: 'localhost',
keyspace: 'twissandra'
}
}
]
}
注意:
??operand部分的每個key,在連接字符串都以shema.為前綴。
??Calcite的核心模塊(calcite-core)支持SQL查詢(SELECT)和DML操作(INSERT,UPDATE,DELETE,MERGE),但不支持DDL操作,如CREATE SCHEMA或CREATE TABLE。正如我們將要看到的,DDL使存儲庫的狀態模型變得復雜,并且使得解析器更難以擴展,因此我們將DDL留在了核心之外。
??服務器模塊(calcite-server)向Calcite添加DDL支持。它擴展了SQL解析器,使用與子項目相同的機制,添加了一些DDL命令:
$ ./sqlline
sqlline version 1.3.0
> !connect jdbc:calcite:parserFactory=org.apache.calcite.sql.parser.ddl.SqlDdlParserImpl#FACTORY sa ""
> CREATE TABLE t (i INTEGER, j VARCHAR(10));
No rows affected (0.293 seconds)
> INSERT INTO t VALUES (1, 'a'), (2, 'bc');
2 rows affected (0.873 seconds)
> CREATE VIEW v AS SELECT * FROM t WHERE i > 1;
No rows affected (0.072 seconds)
> SELECT count(*) FROM v;
+---------------------+
| EXPR$0 |
+---------------------+
| 1 |
+---------------------+
1 row selected (0.148 seconds)
> !quit
Linux系統測試通過,Windows尚不支持。
??calcite-server模塊是可選的。其目標之一是使用簡潔的示例來展示Calcite的功能(例如物化視圖,外部表和生成列),可以從SQL命令行嘗試這些示例。所有calcite-server使用的功能都可以通過calcite-core中的API。
??如果您是子項目的作者,那么您的語法擴展名不太可能與calcite-server匹配,所以我們建議您通過擴展核心解析器來添加SQL語法擴展; 如果您需要DDL命令,則可以將calcite-server 復制粘貼到您的項目中。
??目前,存儲庫不會被持久化。在執行DDL命令時,通過從根Schema添加和刪除可訪問的對象來修改內存中的存儲庫 。同一SQL會話中的所有命令都將看到這些對象。您可以通過執行相同的SQL命令腳本,在將來的會話中創建相同的對象。
??Calcite也可以作為數據虛擬化或聯邦服務器:Calcite管理多個外部Schema中的數據,但是對于客戶端來說數據似乎都在同一個地方。Calcite選擇應該在哪里處理,以及是否為了提高效率創建數據副本。calcite-server模塊是實現這一目標的一個步驟; 一個行業垂直的解決方案將需要進一步的封裝擴展(使Calcite作為服務可運行),存儲庫持久性,授權和安全性。
??還有許多其他的API可以擴展Calcite的功能。
??在本節中,我們將簡要介紹這些API,為您提供一個對可以實現功能的思路。要充分使用這些API,您需要閱讀其他文檔,例如接口的javadoc,并且可能需要找我們出為它們編寫的測試。
??有幾種方法可以將運算符或函數添加到Calcite中。我們將首先描述最簡單(也是最不強大的)。
??用戶自定義的函數是最簡單的(但功能最少)。它們很容易編寫(你只需編寫一個Java類并將其注冊到Schema中),但是在參數的數量和類型,解析重載函數或派生返回類型方面不提供很大的靈活性。
??如果需要這種靈活性,可能需要寫一個用戶自定義的操作符 (參見SqlOperator接口)。
如果操作符不遵守標準的SQL函數語法“ f(arg1, arg2, ...)”,那么需要擴展解析器。
在測試中有很多很好的例子:UdfTest類測試用戶自定義的函數和用戶自定義的聚合函數。
??聚合函數
??用戶自定義的聚合函數與用戶自定義的函數相似,但每個函數都有幾個對應的Java方法,一個方法用于聚合生命周期中的每一個階段:
struct Accumulator {
final int sum;
}
Accumulator init() {
return new Accumulator(0);
}
Accumulator add(Accumulator a, int x) {
return new Accumulator(a.sum + x);
}
Accumulator merge(Accumulator a, Accumulator a2) {
return new Accumulator(a.sum + a2.sum);
}
int result(Accumulator a) {
return new Accumulator(a.sum + x);
}
下面是計算列值為4和7的兩行總和的順序調用序列:
a = init() # a = {0}
a = add(a, 4) # a = {4}
a = add(a, 7) # a = {11}
return result(a) # returns 11
窗口函數
??窗口函數與聚合函數類似,但是它應用于由OVER子句而不是由GROUP BY子句收集的一組行。每個聚合函數都可以用作窗口函數,但是有一些關鍵的區別。窗口函數看到的行可能是有序的,依賴于順序的窗口函數(RANK例如)不能用作聚合函數。
??另一個區別是,窗口是不相交的( non-disjoint):一個特定的行可以出現在多個窗口中。例如,10:37出現在9:00-10:00以及9:15-9:45兩個窗口。
??窗口函數是遞增計算的:當時鐘從10:14轉動到10:15時,可能有兩行進入窗口,三行離開。為此,窗口函數有一個額外的生命周期操作:
Accumulator remove(Accumulator a, int x) {
return new Accumulator(a.sum - x);
}
??下面是計算移動總和的順序調用序列,在前兩行中,4行中的值分別為4,7,2和3:
a = init() # a = {0}
a = add(a, 4) # a = {4}
emit result(a) # emits 4
a = add(a, 7) # a = {11}
emit result(a) # emits 11
a = remove(a, 4) # a = {7}
a = add(a, 2) # a = {9}
emit result(a) # emits 9
a = remove(a, 7) # a = {2}
a = add(a, 3) # a = {5}
emit result(a) # emits 5
分組窗口函數
??分組窗口函數是操作GROUP BY子句將記錄集合在一起的函數。內置的分組窗口函數有HOP,TUMBLE和SESSION。可以通過實現接口SqlGroupedWindowFunction來定義其他函數 。
表函數和table macros
??用戶自定義的表函數 的定義方式與常規的用戶自定義“標量”函數類似,但它是在查詢的FROM子句中使用。以下查詢使用一個名為Ramp的表函數:
SELECT * FROM TABLE(Ramp(3, 4))
??用戶定義的table macros使用與表函數相同的SQL語法,但定義不同。它們不會生成數據,而是生成一個關系表達式。在查詢準備過程中調用table macros,然后可以優化它們生成的關系表達式。(Calcite使用table macros實現視圖)。
??TableFunctionTest類測試表函數并包含幾個有用的例子。
??假設你需要擴展Calcite的SQL語法,這樣才能兼容未來語法的變化。在項目中復制Parser.jj語法文件的副本是愚蠢的,因為語法是經常編輯的。
??幸運的是,Parser.jj實際上是一個 Apache FreeMarker 模板,其中包含可以被替換的變量。calcite-core中的解析器使用變量的默認值實例化模板,通常為空,但可以覆蓋。如果項目使用不同的解析器,可以提供自己的config.fmpp和parserImpls.ftl文件,并因此產生擴展的解析器。
??calcite-server模塊是在[ CALCITE-707 ]中創建的,并添加了DDL語句如CREATE TABLE,這是可以參考遵循的一個示例。另外可參照類ExtensionSqlParserTest。
??要定制解析器應該接受的SQL擴展,請實現 SqlConformance接口或使用枚舉SqlConformanceEnum中的某個內置值 。
??要控制如何為外部數據庫(通常通過JDBC適配器)生成SQL,請使用SqlDialect類。方言也描述了引擎的能力,比如是否支持OFFSET和使用FETCH。
??要自定義Schema,需要實現SchemaFactory接口。
??在查詢準備期間,Calcite會調用這個接口來找出你自定義的Schema包含的表和子Schema。在查詢中引用你自定義schema中的表時,Calcite將要求你的schema創建Table接口的實例 。
??該表將被包裝在 TableScan中 ,并將進行查詢優化過程。
??反射(Reflective)schema(ReflectiveSchema類)是一種封裝Java對象的方式,以便它作為Schema出現。其擁有集合值的字段將顯示為表格。
??它不是一個Schema工廠,而是一個真正的模式; 必須通過調用API來創建對象并將其包裝在Schema中。
??請參閱ReflectiveSchemaTest類。
??要自定義一個表格,你需要實現TableFactory接口。盡管Schema工廠生產一組命名表格,但是當綁定到具有特定名稱的Schema(以及可選的一組額外操作數operands)時,表格工廠會生成單個表格。
修改數據
??如果你的自定義表格支持DML操作(INSERT,UPDATE,DELETE,MERGE),實現Table接口的同時也必須實現ModifiableTable接口。
流
??如果你的自定義表格支持流式查詢,實現Table接口的同時必須實現 StreamableTable接口。
??參見 StreamTest 類的例子。
操作下推到自定義表格
??如果您希望將處理推到自定義表格的源系統上,請考慮實現 FilterableTable 接口或 ProjectableFilterableTable接口。
??如果想要更多的控制,應該寫一個計劃器的規則。這將允許您下推表達式,根據成本決定是否下推處理,是否下推更復雜的操作,如關聯,聚合和排序。
??可以通過實現RelDataTypeSystem接口來自定義類型系統的某些方面。
關系運算符
??所有關系運算符都實現了RelNode接口, 并且大部分繼承自AbstractRelNode類。TableScan, TableModify, Values, ProjectFilter, Aggregate, Join, Sort, Union, Intersect, Minus, Window和 Match等核心運算符(由 SqlToRelConverter使用 ,覆蓋了常規傳統的關系代數) 。
??上述每一個都有一個“純”的邏輯子類,LogicalProject 等等。任何給定的適配器都會有引擎可以有效執行操作的對應部分; 例如,Cassandra適配器有 CassandraProject ,但是沒有CassandraJoin。
??可以定義你自己的RelNode子類來添加一個新的操作符,或者在一個特定的引擎中實現一個現有的運算符。
??為了使運算符有用且功能強大,您需要計劃器規則將其與現有運算符結合使用。(并提供元數據,見下文)。這是代數,效果是組合的:你寫了一些規則,但它們結合起來可以處理指數數量的查詢模式。
??如果可能的話,讓您的運算符成為現有運算符的子類; 那么可以重用或適應其規則。更好的是,如果你的運算符是一個邏輯操作,你可以用現有的運算符來重寫(通過計劃器規則),盡量應該這樣做。您將能夠重復使用這些運算符的規則,元數據和實現,而無需額外的工作。
計劃器規則
??計劃器規則(RelOptRule類)可以將關系表達式轉換為等效的關系表達式。
??計劃器引擎有許多計劃器規則注冊并觸發它們將輸入查詢轉換為更高效的計劃。因此,計劃器規則是優化過程的核心,但令人驚訝的是每個計劃器規則并不關心成本。計劃器引擎負責按順序發射規則,產生最優計劃,但是每個規則只關心它的正確性。
??Calcite有兩個內置的計劃器引擎: VolcanoPlanner 類使用動態編程,對窮舉搜索很有效,而 HepPlanner類則以更加固定的順序觸發一系列規則。
調用約定
??調用約定是特定數據引擎使用的協議。例如,Cassandra 引擎具有關系運算符的集合, CassandraProject,CassandraFilter等等,并且這些操作符可以被相互連接,而無需從一個格式轉換成另一種格式的數據。
??如果需要將數據從一個調用約定轉換為另一個調用約定,則Calcite使用一個稱為轉換器的特殊關系表達式子類(參見Converter類)。但是,當然,轉換數據需要運行成本。
在計劃使用多個引擎的查詢時,Calcite根據其調用約定對關系表達式樹的區域進行“著色”。計劃器通過觸發規則將操作推入數據源。如果引擎不支持特定操作,則規則不會觸發。有時一個操作可能發生在多個地方,最終根據成本選擇最佳方案。
??調用約定是實現了Convention接口,輔助接口(例如CassandraRel接口)和RelNode類的一組子類, 用于實現核心關系運算符(Project,Filter, Aggregate等等)的一個類。
內置SQL實現
??如果一個適配器沒有實現所有核心關系運算符,Calcite如何實現SQL?
??答案是一個特定的內置調用約定EnumerableConvention。可枚舉約定的關系表達式被實現為“內置”:Calcite生成Java代碼,編譯并在其自己的JVM中執行它。可枚舉約定比運行在列式數據文件上的分布式引擎效率低,但可以實現所有核心關系運算符以及所有內置的SQL函數和運算符。如果一個數據源不能實現一個關系運算符,則枚舉約定是一個回退。
??Calcite有一個元數據系統,允許你定義成本函數和有關關系運算符的統計信息,統稱為元數據。每種元數據都有(通常)一種方法的接口。例如,selectivity 由RelMdSelectivity類和方法 getSelectivity(RelNode rel,RexNode predicate)定義。
??有許多內置的元數據類型,包括collation, column origins, column uniqueness, distinct row count, distribution, explain visibility, expression lineage, max row count, node types, parallelism, percentage original rows, population size, predicates, row count, selectivity, size, table references, unique keys; 也可以自定義。
??然后,您可以提供一個元數據提供者(Provider)來計算RelNode的特定子類的元數據。元數據提供者可以處理內置和擴展的元數據類型,以及內置和擴展RelNode類型。在準備查詢時,Calcite將所有適用的元數據提供者組合起來,并維護一個緩存,以便只計算一次給定的元數據(例如在特定Filter運算符中x > 10條件的selectivity )。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。