博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
calcite介绍
阅读量:5788 次
发布时间:2019-06-18

本文共 2343 字,大约阅读时间需要 7 分钟。

前言

calcite是一个可以将任意数据查询转换成基于sql查询的引擎,引擎特性也有很多,比如支持sql树的解析,udf的扩展,sql执行优化器的扩展等等。目前已经被很多顶级apache项目引用,比如hive,kylin等。在这个SQL作为主流的数据查询语言大数据世界里,calcite的作用会越来越大。

 

理解calcite的核心流程

如图1所示。calcite核心步骤有两个,数据关系化, SQL解析执行。

 

图1 calcite核心流程

 

数据协议关系化

要想使用sql进行查询,首先要把非结构化数据结构化,而calcite号称支持所有数据协议,则必然得将这部分内容抽象出来。

在calcite的接口中,Schema和Table是数据关系化中最重要的两个接口。Schema是对catalog或者是database的抽象,以兼容已经存在的各类数据库,Table是对表,视图,流的抽象,以兼容数据的各种场景,下面详细描述一下这两种抽象。

 

schema

calcite利用schema的层级关系,构造出来namespace的概念,如图2所示,schema自身是一个树形结构,这样设计的优点很明显,可以兼容所有已知和未知的数据库,基于namespace结构,schema无论是横向还是纵向都可以无限扩展。

图2 schema的namespace

在实际应用中,RootSchema是根所有schema的路径,所有注册在RootSchema上的table或者是udf都是全局的,意思就是说可以被SubSchema直接使用,而注册在SubSchema里的table或者是udf,则在使用中必须声明是哪个SubSchema拥有的。

 

table

table是schema的核心属性,一个schema拥有多个table,这就像一个数据库中有很多表一样。而table的概念更为广泛,为了兼容到各类数据库或者消息队列,calcite将table类型细分为TableType,基本的类似传统关系型数据库中的表或者视图,流式的Stream等。

另外对数据协议的兼容是非常重要的,像json,csv,xml等等,table抽象出了RelDataType接口,目的是将应用层的数据协议转关系化,从而可以为sql服务。

拿csv格式的数据来说,假设csv数据的每一行数据和table中的每一行一一对应,那么在关系化的过程中,必须将csv中每个字段的类型及一些元数据定义清晰,比如字段是int类型还是long类型,主键是哪个字段,外键是哪个字段等,calcite提供了几乎所有已存在的字段类型。

关于嵌套数据,calcite也考虑的很周全,提供MapSqlType或者ArraySqlType的形式来兼容这些结构。

拿json格式的数据来说,字段嵌套是很常见的,如果想把这类结构数据关系化,通常有两种选择(1)数据扁平化,将嵌套的字段提上来,形成a.b的形式(2)通过calcite引擎声明嵌套字段及规则,在使用sql查询的时候再通过calcite的表达式提取这些字段。

 

SQL解析执行

到了这一步,其实和传统数据库很像了,如图3所示,calcite采用了该方案来解决从sql的输入到输出。

calcite通过关系代数来实现对sql的执行,而关系代数之间通过树形结构作为载体,每一个输入的sql命令都会被转换成树形结构的关系代数也就是关系表达式树。calcite支持直接构建关系表达式树,通过RelBuilder接口。

注:关系代数,常见的有(交,并,差,投影,选择,笛卡尔积,连接)

 

图3

 

案例

完整案例

calcite提供了基于json和csv的案例,在calcite-example模块下,另外在该模块的单元测试中,有一些完整的例子。

 

sql解析案例

// 可以通过SqlParser直接对sql语句作解析,返回的就是sql树。SqlParser sqlParser = SqlParser.create("select * from \"table\" where \"column\" > 1 limit 1");SqlNode sqlNode =  sqlParser.parseQuery();if(sqlNode instanceof SqlCall){    if(sqlNode instanceof SqlBasicCall){        SqlBasicCall basicCall = (SqlBasicCall) sqlNode;        System.out.println(((SqlIdentifier)basicCall.operand(0)).getSimple());        System.out.println(((SqlNumericLiteral)basicCall.operand(1)).getValue());        System.out.println(basicCall.getKind());    }    System.out.println(sqlNode.getKind()+" -> "+sqlNode.getClass());    SqlCall call = (SqlCall) sqlNode;    for(SqlNode node: call.getOperandList()){        parse(node);    }}

 

引用

// calcite官网

 

// calcite github

 

转载于:https://www.cnblogs.com/ulysses-you/p/9358186.html

你可能感兴趣的文章
LNMP之Mysql主从复制(四)
查看>>
阅读Spring源代码(1)
查看>>
nagios一键安装脚本,nagios监控被监控主机上的应用服务mysql数据库
查看>>
grep 命令
查看>>
JS二维数组的声明和使用
查看>>
v$archive_gap dg dataguard 断档处理 scn恢复
查看>>
问责IT风险管理:CIO需关注两个重点
查看>>
Winform打包发布图解
查看>>
PDF文件怎么编辑,超简单的方法
查看>>
EasyUI基础入门之Easyloader(载入器)
查看>>
Uva 839 Not so Mobile
查看>>
30款超酷的HTTP 404页面未找到错误设计
查看>>
程序猿必备 MyEclipse2013-2014系列
查看>>
java中ArrayList 、LinkList区别
查看>>
Spring ’14 Wave Update: Installing Dynamics CRM on Tablets for Windows 8.1
查看>>
利用rand7()构造rand10()
查看>>
MySQL 备份与恢复
查看>>
吃午饭前,按书上的代码写会儿--Hunt the Wumpus第一个版本
查看>>
easyui中combobox的值改变onchang事件
查看>>
Eclipse魔法堂:任务管理器
查看>>