zoukankan      html  css  js  c++  java
  • calcite介绍

    前言

    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官网

    http://calcite.apache.org/docs/tutorial.html

    // calcite github

    https://github.com/apache/calcite

  • 相关阅读:
    背水一战 Windows 10 (26)
    背水一战 Windows 10 (25)
    背水一战 Windows 10 (24)
    背水一战 Windows 10 (23)
    背水一战 Windows 10 (22)
    背水一战 Windows 10 (21)
    背水一战 Windows 10 (20)
    背水一战 Windows 10 (19)
    背水一战 Windows 10 (18)
    背水一战 Windows 10 (17)
  • 原文地址:https://www.cnblogs.com/ulysses-you/p/9358186.html
Copyright © 2011-2022 走看看