美文网首页
calcite的hello world(CSV example)

calcite的hello world(CSV example)

作者: CarsonCao | 来源:发表于2020-01-03 19:53 被阅读0次

    1 下载代码并build

    需要 java8以上 环境

    $ git clone https://github.com/apache/calcite.git
    $ cd calcite
    $ ./gradlew build
    $ cd example/csv
    
    

    几种build方式,具体可以上官网查询(https://calcite.apache.org/docs/howto.html#running-tests):

    $ ./gradlew assemble # build the artifacts
    $ ./gradlew build -x test # build the artifacts, verify code style, skip tests
    $ ./gradlew check # verify code style, execute tests
    $ ./gradlew test # execute tests
    $ ./gradlew style # update code formatting (for auto-correctable cases) and verify style
    $ ./gradlew spotlessCheck checkstyleAll # report code style violations
    
    

    如果下载的源码里有pom文件,也可以用maven编译:

    mvn install -DskipTests -Dcheckstyle.skip=true
    
    

    2 查询

    官方文档通过sqlline查询的案例,通过执行sqlline命令实现对csv文件的查询,详情见官网:
    https://calcite.apache.org/docs/tutorial.html
    在官网的例子中,利用sqlline指定json文件设置数据库的元数据:

    $ ./sqlline
    sqlline> !connect jdbc:calcite:model=src/test/resources/model.json admin admin
    

    通过 !tables 可以显示当前的所有表信息:

    > !table
    +-----------+-------------+------------+------------+---------+----------+------------+-----------+---------------------------+----------------+
    | TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_CAT | TYPE_SCHEM | TYPE_NAME | SELF_REFERENCING_COL_NAME | REF_GENERATION |
    +-----------+-------------+------------+------------+---------+----------+------------+-----------+---------------------------+----------------+
    |           | SALES       | DEPTS      | TABLE      |         |          |            |           |                           |                |
    |           | SALES       | EMPS       | TABLE      |         |          |            |           |                           |                |
    |           | SALES       | SDEPTS     | TABLE      |         |          |            |           |                           |                |
    |           | metadata    | COLUMNS    | SYSTEM TABLE |         |          |            |           |                           |              |
    |           | metadata    | TABLES     | SYSTEM TABLE |         |          |            |           |                           |              |
    +-----------+-------------+------------+------------+---------+----------+------------+-----------+---------------------------+----------------+
    

    可以发现有5个表,COLUMNSTABLES两个表可以不用考虑,我们看到在schema SALES中,有三张表分别是:DEPTS,EMPS,SDEPTS
    我们执行一个复杂点的查询语句试试:

    > SELECT d.name, COUNT(*)
    >   FROM emps AS e JOIN depts AS d ON e.deptno = d.deptno
    >   GROUP BY d.name;
    +------+---------------------+
    | NAME      |      EXPR$1    |
    +------+---------------------+
    | Sales     | 1              |
    | Marketing | 2              |
    +------+---------------------+
    
    

    3 自定义schema

    那么calcite是如何发现这些table的呢?
    我们先看我们指定的model.json里有什么:

    {
      "version": "1.0",
      "defaultSchema": "SALES",
      "schemas": [
        {
          "name": "SALES",
          "type": "custom",
          "factory": "org.apache.calcite.adapter.csv.CsvSchemaFactory",
          "operand": {
            "directory": "sales"
          }
        }
      ]
    }
    

    里面声明了schema的名字SCALES,声明了创建schema的工厂类org.apache.calcite.adapter.csv.CsvSchemaFactoryoperand里面是一些自定义参数,在这里指定了csv文件的路径。
    有了配置文件,还需要对配置文件进行解析,有兴趣的可以看一下这部分的源码,可以从CsvSchemaFactory类里一层层往下看。
    配置文件中还可以通过tables的关键字指定自定义的table:

    {
      version: '1.0',
      defaultSchema: 'SALES',
      schemas: [
        {
          name: 'SALES',
          type: 'custom',
          factory: 'org.apache.calcite.adapter.csv.CsvSchemaFactory',
          operand: {
            directory: 'target/test-classes/sales'
          },
          tables: [
            {
              name: 'FEMALE_EMPS',
              type: 'view',
              sql: 'SELECT * FROM emps WHERE gender = \'F\''
            }
          ]
        }
      ]
    }
    

    以上定义了一个view,view没有物化的数据,可以通过执行sql得到view。
    看了这么多我们接下来再回顾一下这几个重要的概念:

    • Schema,是table和function的名称空间,它是一个可嵌套的结构,Schema还可以有subSchema,理论上可以无限嵌套,但一般不会这么做。Schema可以理解成Database,Database下面有table,这样就和传统数据库的概念联系起来了,在Calcite中,顶层的Schema是root,自定义的Schema是root的subSchema,同时还可以设置defaultSchema,类似我们使用数据库时,使用use database命令以后就不用再输入database名字前缀。
    • Table,就很好理解了,就是数据库中的表。在table描述了字段名以及相应的类型、表的统计信息,例如表有多少条记录等等,这里先不展开讲。另外重要的是数据文件的存储以及如何扫描读取数据文件。

    再来看上面的model文件,就比较清晰了。它描述了在数据库中有多少个Schema、每个Schema如何创建以及默认的Schema,这里的Schema可以理解成database。defaultSchema属性设置默认Schema,schemas是数组类型,每一项代表一个Schema描述信息,在描述信息中有一个关键的属性factory,它是创建Schema的工厂类,在这个例子中factory是org.apache.calcite.adapter.csv.CsvSchemaFactory,它实现了SchemaFactory接口。

    要自实现具有全表扫描功能的简单数据库需要做如下几步:

    1. 自定义 SchemaFactory
    2. 自定义 Schema
    3. 自定义 Table
    4. 自定义 Enumerator

    3 自定义table

    上面章节介绍的是利用自定义的schema工厂创建table的方式,另外还有一种自定义table工厂的方式。

    {
      version: '1.0',
      defaultSchema: 'CUSTOM_TABLE',
      schemas: [
        {
          name: 'CUSTOM_TABLE',
          tables: [
            {
              name: 'EMPS',
              type: 'custom',
              factory: 'org.apache.calcite.adapter.csv.CsvTableFactory',
              operand: {
                file: 'target/test-classes/sales/EMPS.csv.gz',
                flavor: "scannable"
              }
            }
          ]
        }
      ]
    }
    

    这种方式直接调用json中指定的CsvTableFactory创建一个table,不管是自定义schema还是自定义table,最终都会实现table接口。但是不同的是自定义table不需要去scan数据从而获取数据的字段信息。(CsvTableFactory creates a CsvScannableTable, just as CsvSchema does, but the table implementation does not scan the filesystem for .csv files.)

    自定义table需要使用者做更多的工作,因为需要针对每个数据表进行配置,但是功能相对自定义schema更加强大,可以针对每个表做个性化配置。

    4 定义rules

    calcite 通过添加 rule 的方式对查询优化进行扩展, rule 通过指定在查询树中寻找特定的 pattern (比如: 一个挂在 table 之上的 projection), 并将匹配的节点转换为一组全新的节点, 来尝试优化.

    calcite 中的 rule 也完全可扩展的, 通过定义规则就像前面定义 schema/table 一样. 直接看 demo 中的例子:
    https://calcite.apache.org/docs/tutorial.html
    https://zhuanlan.zhihu.com/p/53725382

    5 几种table接口

    5.1 ScannableTable

    a simple implementation of Table, using the ScannableTable interface, that enumerates all rows directly

    这种方式基本不会用,原因是查询数据库的时候没有任何条件限制,默认会先把全部数据拉到内存,然后再根据filter条件在内存中过滤。

    使用方式:实现Enumerable scan(DataContext root);,该函数返回Enumerable对象,通过该对象可以一行行的获取这个Table的全部数据。

    5.2 FilterableTable

    a more advanced implementation that implements FilterableTable, and can filter out rows according to simple predicates

    初级用法,我们能拿到filter条件,即能再查询底层DB时进行一部分的数据过滤,一般开始介入calcite可以用这种方式(translatable方式学习成本较高)。

    使用方式:实现Enumerable scan(DataContext root, List filters )

    如果当前类型的“表”能够支持我们自己写代码优化这个过滤器,那么执行完自定义优化器,可以把该过滤条件从集合中移除,否则,就让calcite来过滤,简言之就是,如果我们不处理List filters ,Calcite也会根据自己的规则在内存中过滤,无非就是对于查询引擎来说查的数据多了,但如果我们可以写查询引擎支持的过滤器(比如写一些hbase、es的filter),这样在查的时候引擎本身就能先过滤掉多余数据,更加优化。提示,即使走了我们的查询过滤条件,可以再让calcite帮我们过滤一次,比较灵活。

    5.3 TranslatableTable

    advanced implementation of Table, using TranslatableTable, that translates to relational operators using planner rules.

    高阶用法,有些查询用上面的方式都支持不了或支持的不好,比如join、聚合、或对于select的字段筛选等,需要用这种方式来支持,好处是可以支持更全的功能,代价是所有的解析都要自己写,“承上启下”,上面解析sql的各个部件,下面要根据不同的DB(es\mysql\drudi..)来写不同的语法查询。

    当使用ScannableTable的时候,我们只需要实现函数Enumerable scan(DataContext root);,该函数返回Enumerable对象,通过该对象可以一行行的获取这个Table的全部数据(也就意味着每次的查询都是扫描这个表的数据,我们干涉不了任何执行过程);当使用FilterableTable的时候,我们需要实现函数Enumerable scan(DataContext root, List filters );参数中多了filters数组,这个数据包含了针对这个表的过滤条件,这样我们根据过滤条件只返回过滤之后的行,减少上层进行其它运算的数据集;当使用TranslatableTable的时候,我们需要实现RelNode toRel( RelOptTable.ToRelContext context, RelOptTable relOptTable);,该函数可以让我们根据上下文自己定义表扫描的物理执行计划,至于为什么不在返回一个Enumerable对象了,因为上面两种其实使用的是默认的执行计划,转换成EnumerableTableAccessRel算子,通过TranslatableTable我们可以实现自定义的算子,以及执行一些其他的rule,Kylin就是使用这个类型的Table实现查询。

    参考资料:
    https://www.jianshu.com/p/c698673e2c84
    https://www.infoq.cn/article/new-big-data-hadoop-query-engine-apache-calcite/
    https://calcite.apache.org/docs/tutorial.html
    https://zhuanlan.zhihu.com/p/53725382
    http://www.programmersought.com/article/9029515743/
    https://www.cnblogs.com/wcgstudy/p/11795952.html

    相关文章

      网友评论

          本文标题:calcite的hello world(CSV example)

          本文链接:https://www.haomeiwen.com/subject/qbgsgctx.html