文章導讀:
- 什么是Calcite?
- Calcite的主要功能?
- 如何快速使用Calcite?
什么是Calcite
Apache Calcite是一個動態數據管理框架,它具備很多典型數據庫管理系統的功能,比如SQL解析、SQL校驗、SQL查詢優化、SQL生成以及數據連接查詢等,但是又省略了一些關鍵的功能,比如Calcite並不存儲相關的元數據和基本數據,不完全包含相關處理數據的算法等。
也正是因為Calcite本身與數據存儲和處理的邏輯無關,所以這讓它成為與多個數據存儲位置(數據源)和多種數據處理引擎之間進行調解的絕佳選擇。
Calcite所做的工作就是將各種SQL語句解析成抽象語法樹(AST Abstract Syntax Tree),並根據一定的規則或成本對AST的算法與關系進行優化,最后推給各個數據處理引擎進行執行。
目前,使用Calcite作為SQL解析與優化引擎的又Hive、Drill、Flink、Phoenix和Storm,Calcite憑借其優秀的解析優化能力,會有越來越多的數據處理引擎采用Calcite作為SQL解析工具。
Calcite 主要功能
Calcite的主要功能我們上面其實已經提到了,主要有以下功能:
SQL解析:通過JavaCC將SQL解析成未經校驗的AST語法樹
SQL校驗:校驗分兩部分,一種為無狀態的校驗,即驗證SQL語句是否符合規范;一種為有狀態的即通過與元數據結合驗證SQL中的Schema、Field、Function是否存在。
SQL查詢優化:對上個步驟的輸出(RelNode)進行優化,得到優化后的物理執行計划
SQL生成:將物理執行計划生成為在特定平台/引擎的可執行程序,如生成符合Mysql or Oracle等不同平台規則的SQL查詢語句等
數據連接與執行:通過各個執行平台執行查詢,得到輸出結果。
所以在Calcite中,一條SQL的處理步驟就很清晰了,那么我們通過Calcite的代碼來實際了解一下:
// 初始化配置
SqlParser.ConfigBuilder configBuilder = SqlParser.configBuilder();
configBuilder.setUnquotedCasing(Casing.UNCHANGED);
//Sql解析:解析Sql語句,通過JavaCC解析成AST語法樹,表現為SqlNode
SqlParser sqlParser = SqlParser.create(sql, configBuilder.build());
SqlNode sqlNode = sqlParser.parseQuery();
//Sql校驗:結合元數據信息驗證Sql是否符合規范
Planner planner = Frameworks.getPlanner(config);
SqlNode node = planner.validate(sqlNode);
//Sql查詢優化:將SqlNode轉換為LogicalPlan,表現為RelNode
RelRoot relRoot = planner.rel(node);
RelNode project = relRoot.project();
//指定優化規則
final HepProgram program = new HepProgramBuilder()
.addRuleInstance(SubQueryRemoveRule.PROJECT)
.addRuleInstance(SubQueryRemoveRule.FILTER)
.addRuleInstance(SubQueryRemoveRule.JOIN)
.build();
//生成優化后的RelNode
HepPlanner prePlanner = new HepPlanner(program);
prePlanner.setRoot(project);
RelNode relNode = prePlanner.findBestExp();
//ToDo 執行查詢
使用Calcite
那么前面對Calcite進行了簡單的介紹,我們如何使用Calcite呢?Calcite的使用非常簡單,你要做的只是添加數據源即可。我們以Mysql數據源為例,我們通過添加Mysql數據庫作為Calcite的數據源,實現通過Calcite對Mysql數據進行查詢的Demo。
//初始化calcite connection
Class.forName("org.apache.calcite.jdbc.Driver");
Properties info = new Properties();
info.setProperty("lex", "JAVA");
Connection connection =
DriverManager.getConnection("jdbc:calcite:", info);
CalciteConnection calciteConnection =
connection.unwrap(CalciteConnection.class);
//添加mysql數據庫作為數據源
SchemaPlus rootSchema = calciteConnection.getRootSchema();
Class.forName("com.mysql.jdbc.Driver");
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost");
dataSource.setUsername("username");
dataSource.setPassword("password");
Schema schema = JdbcSchema.create(rootSchema, "hr", dataSource,
null, "name");
rootSchema.add("hr", schema);
//執行查詢
Statement statement = calciteConnection.createStatement();
ResultSet resultSet = statement.executeQuery(
"select d.deptno, min(e.empid)\n"
+ "from hr.emps as e\n"
+ "join hr.depts as d\n"
+ " on e.deptno = d.deptno\n"
+ "group by d.deptno\n"
+ "having count(*) > 1");
print(resultSet);
resultSet.close();
statement.close();
connection.close();
Calcite提供了多種方式添加數據源,如通過“inline:”的字符串方式以及通過json或yaml文件的方式。同時,Calcite抽象出了功能齊全的接口,可以方便的將CSV文件抽象成數據表進行查詢。這部分內容可以通過官方的示例了解一下!
當然SQL解析、校驗與執行計划優化是Calcite的基本功能,Calcite的NB之處在於,Calcite的目標是“one size fits all”,希望能為不同的計算平台和數據源提供統一的查詢引擎,並且以類似傳統數據庫的訪問方式(SQL)來訪問Hadoop上的數據。所以Calcite提供了非常豐富的可擴展接口,幫助我們實現擴展數據源、擴展針對不同數據源的優化規則、擴展SQL查詢語法、擴展數據處理引擎等等。這部分后面會詳細介紹(挖坑ing)
參考資料:
https://calcite.apache.org/docs/tutorial.html
https://www.infoq.cn/article/new-big-data-hadoop-query-engine-apache-calcite
好久不更新了