说道Calcite你可能有些陌生, 但提及Hive、Kylin、Apache Drill、Flink等一定不会陌生,这些都是在我们日常工作中经常用到的,如上这些都是基于Calcite实现查询引擎,还有Druid和Storm也是使用它来实现SQL功能。按照官方的说法,Calcite是动态数据管理框架,这个解释理解起来有点抽象,通俗一点讲,要使用Calcite实现数据库,只需要关注存储引擎以及元数据管理,其他都交给Ca

lcite。可能这个说法有些不严谨,文档中还提到了Calcite不提供处理数据的算法,但Calcite-core和Calite-linq都提供了一些算子的实现对于一个简单的数据库足够了。

对于Calcite的详细介绍推荐大家看一遍文章,本文主要介绍Calcite如何使用,例如已经有一种数据格式的文件存储,如何利用Calcite快速实现SQL查询。我看过kylin、druid的Calcite应用,也是各不相同,这大概也是Calcite的魅力吧。

Calcite文档有一个指南,介绍使用CSV File作为数据存储格式实现SQL查询,掌握了以后我们可以照猫画虎造出一个其他数据格式的数据库,或者对学习kylin、druid的源码有帮忙,概括地讲,在这个例子使用以下技巧:

自定义Schema

自定义Table

决定Table的字段类型

使用ScannableTable实现简单的全表扫描

更高级一点的技巧,使用Filterable Table实现谓词下推

更酷一点的技巧,基于TranslateTable使用Rule实现逻辑表达式的转换

前四点是构建一个简单的,采用全表扫描的方式实现查询。5和6属于进阶内容,在案例中,使用Rule转换的方式实现了Project下推,和5实现的谓词下推是常用的SQL优化方式。下面由浅到深介绍这几项技巧。先来看前四项,完成一个简单的只能全表扫描的数据库。

首先在GitHub上下载Calcite的源码,看calcite-example-csv工程,在src/test/CSVTest中有各种场景的测试用例,例如

testFilterableWhere是测试谓词下推

testPushDownProject是Project下推

testSelect是最简单的全表扫描

可以先跑一下测试用例感受一下Calcite的魅力,Calcite实现一个数据库,只需要关注存储引擎以及元数据管理。存储格式采用csv,一个CSV文件会映射成一个Table,需要注意的是CSV文件的第一行是Table的元数据信息,采用“FieldName1:FieldType,FieldNameN:FieldType”这样的格式存储,类似excel中的表头信息。以下是sales/SALES.csv的示例。

DEPTNO:int,NAME:string

10,"Sales"

20,"Marketing"

30,"Accounts"

至此介绍了存储格式以及元数据,接下来介绍如何使用。

第一步,创建一个json格式的mode文件,描述了如何创建Schema,可以参照test/resource目录下的model.json,

{

"version": "1.0",

"defaultSchema": "SALES",

"schemas": [

{

"name": "SALES",

"type": "custom",

"factory": "org.apache.calcite.adapter.csv.CsvSchemaFactory",

"operand": {

"directory": "sales"

}

}

]

}

在分析model文件之前,我们先了解几个重要的概念:

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接口。

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

自定义SchemaFactory

自定义Schema

自定义Table

自定义Enumerator

先看看SchemaFactory接口,它只有一个方法:

Schema create(

SchemaPlus parentSchema,

String name,

Map operand);

create用于创建Schema,其参数说明如下:

parentSchema,他的父节点,一般为root

name schema的名字,它在model中定义的

operand,也是在mode中定义的,是Map类型,用于传入自定义参数。

在这个Model中,CSVSchemaFactory创建一个叫“SALES”的CSVSchema,它会把src/test/resources/sales下所有CSV文件构建成table。所以operand只许设定了一个参数directory,即读取CSV文件的根目录。CSVSchemaFactory的实现比较简单所以就不在展开分析,需要注意是的源码中flavor参数的处理,这个参数涉及优化进阶相关,这里先不用管,默认为SCANNABLE。

自定义Schema需要实现Schema接口,前面提过Schema是table和function的名称空间,其主要方法如下:

Table getTable(String name),根据表名获取Table

Set getTableNames(),获取Schema下的所有表名集合

Collection getFunctions(String name),根据函数名获取函数列表,和table不同,这里返回的是集合类型。

Set getFunctionNames(),或者所有的函数名集合。

CsvSchema->AbstractSchema->Schema,AbstractSchema重新设计了一个getTableMap方法,使用tableName->Table的Map结构存储所有table。这样设计的好处是getTable()能够快速查找。CSVSchema的实现也比较简单,遍历读取根目录下的每个

文件创建成表,因为上面的model.json中flavor没有设置,采用默认值SCANNABLE,创建成CsvScannableTable。

自定义Table是本文中最复杂的,先看下图:

image.jpg

如图可知,CSVScannableTable主要实现了两个接口ScannableTable和Table。右边部分,CSVTable实现了Table接口,它的作用是定义Table的字段以及字段类型,左侧的ScannableTable是实现如何遍历读取CSV文件的数据。Table接口有如下三个方法:

RelDataType getRowType(RelDataTypeFactory typeFactory); 这个方法就是定义Table行记录的字段以及字段类型。

Statistic getStatistic(); 获取统计信息

Schema.TableType getJdbcTableType(); table的类型,table的类型有很多种,例如table和view。

AbstractTable默认实现了getStatistic和getJdbcTableType,所以我们只需要实现getRowType方法。首先需要定义type,规范我们这个数据库支持的数据类型。例如字符串是采用String还是VarChar,具体实现在CsvFieldType枚举类,它内部维护了一个Map结构用来存储type的

STRING(String.class, "string"),

BOOLEAN(Primitive.BOOLEAN),

BYTE(Primitive.BYTE),

CHAR(Primitive.CHAR),

//只列举部分类型

由如上代码可知,type并不都是标准的SQL Type,例如String。Calcite中设计了RelDataTypeFactory,不仅支持标准的SQL TYPE,也支持java类型以及Array、Map等集合类型。该实例中,RowType是一个StructType,是集合类型,类似c语言中的struct,非常适合存储行记录中字段名以及类型,这和Hive的方式是一样的。例如SALES文件中的

DEPTNO:int,NAME:string

则Type为

struct

在这个例子中通过读取csv文件的第一行来获取fieldName以及fieldType的,具体实现在CsvEnumerator的deduceRowType()方法。

在calcite中一般有两种执行模型,解释和编译,这一点类似Java。编译模式更好理解一些,会把逻辑执行计划通过字节码技术生成java code然后编译执行。解释模式则省掉生成代码编译的过程。关于解释执行。我看过一些基于Calcite的应用,大部分还是采用编译模式的,所以你看完这篇文章以后再去看其他使用calicite的项目,可能找不到熟悉的身影,如果table实现了如下三个接口之一,Calcite则会使用解释模式执行

ScannableTable

FilterableTable

ProjectableFilterableTable

ScannableTable用于简单的全表扫描,FilterableTable用于谓词下推,ProjectableFilterableTable更酷一些既能支持谓词下推又能支持project下推。他们都有一个scan,但是参数不同

ScannableTable

Enumerable scan(DataContext root);

FilterableTable

Enumerable scan(DataContext root, List filters);

因为要做谓词下推,比ScannableTable多了filters。filters是where语句中的filter。

ProjectableFilterableTable

Enumerable scan(DataContext root, List filters,

int[] projects);

又增加了projects,投影字段顺序的数组。

Enumerable支持linq和java的迭代器

//返回java的迭代器

Iterator it = enumerable.iterator();

//LINQ风格的迭代器

Enumerator enumerator =enumerable.enumerator();

要使用这两种迭代器之前,必须要实现它!AbstractEnumerable借助Linq4j实现了enumerator和iterator的转换

public Iterator iterator() {

return Linq4j.enumeratorIterator(enumerator());

}

所以我们仅需实现enumerator方法。

Enumerator是Linq风格的迭代器,它有4个方法:

current()

moveNext()

reset()

close()

current返回游标所指的当前记录,需要注意的是current并不会改变游标的位置,这一点和iterator是不同的,在iterator相对应的是next方法,每一次调用都会将游标移动到下一条记录,current则不会,Enumerator是在调用moveNext方法时才会移动游标。moveNext方法将游标指向下一条记录,并获取当前记录供current方法调用,如果没有下一条记录则返回false。

CsvEnumerator是读取csv文件的迭代器,它还得需要一个RowConverter,因为csv中都是String类型,使用RowConverter转化成相应的类型。在moreNext方法中,有Stream和谓词下推filter部分的实现,在本文只关注如下几行代码:

final String[] strings = reader.readNext();

if (strings == null) {

current = null;

return false;

}

current = rowConverter.convertRow(strings);

return true;

至此,我们完成了使用csv文件存储的数据库全部工作,你可以在CsvTest中使用所有的名为“model”的模型进行测试,

checkSql("model", "select * from EMPS");

//smart模型的会在后续的文中介绍

checkSql("smart", "select name from EMPS");

总结一下:

创建模型,model.json

自定义SchemaFactory,CsvSchemaFactory

自定义Schema,CsvSchema

自定义Table,CsvTable、CsvScannableTable

自定义Enumerator,CsvEnumerator

分享的过程也是学习的过程,在写本文过程,也了解了不少以前自以为懂了的细节,但也有可能还存在不正确的认识,欢迎指正交流。微信号:zhl5919

参照资料:

calcite连接mysql_如何使用Calcite实现一个简单的数据库相关推荐

  1. java写一个窗体并连接MySQL_大神帮忙写一个简单地java页面,连接MySQL数据库之后能够显示数据库上的数据...

    展开全部 用jdbc 连接mysql数据库就行了,网上搜下一大把. --记得在classpath下加入mysql 的jdbc驱动包. /** * @author :来e68a84e8a2ad32313 ...

  2. jdk12连接mysql_使用基于JDK12版本的JDBC读取数据库中的数据在网页(jsp)表示出来...

    JDBC,数据库访问技术,就是通过Java访问数据库. 对于JDK1.8以后的版本,安装包不再有jre文件包了,这里总结一下我走过的坑. 一.JDBC所需的jar包:其中包含了SQL Server f ...

  3. 一个简单的数据库工具类

    为什么80%的码农都做不了架构师?>>>    接上面一片博文,自己弄了一个简单的数据库操作工具类: /** 创建日期 2014-6-5** TODO 要更改此生成的文件的模板,请转 ...

  4. 自己实现一个简单的数据库

    How do you build a database? (self.Database) How do you build a database? (self.Database) Its a grea ...

  5. java做一个简单的数据库,哪个嵌入式数据库用Java写成一个简单的键/值存储?

    我最近问了一个关于Neo4j的问题,我有工作,似乎很好.它是可嵌入的,它是用Java编写的,没有(太)许多依赖. 然而,它是一个图形数据库,我不知道这是一个好主意或不使用它作为一个简单的键/值存储. ...

  6. calcite连接mysql_使用Calcite做Sql语法解析

    Flink SQL中使用Calcite作为sql语法解析.校验.优化工具,本篇是实操篇,介绍一下calcite做sql语法解析使用方式. sql经过calcite解析之后,得到一棵抽象语法树,也就是我 ...

  7. RADStudio连接MySQL_使用FireDac(Delphi)在Firebird中创建数据库

    我最近从AnyDac改为FireDac(8.0.5.3365).我们正在运行Delphi 2006. 当我使用此组件的AnyDac版本时,我可以通过执行以下操作来创建新数据库. 设置我的连接 fCon ...

  8. ashx连接mysql_对C#中的web访问mysql数据库的一些知识点进行了整理归纳总结

    基本对比 使用方式 使用场合 优缺点 是否需要安装 需要的dll网址 引用方式 程序内引用 程序初期确定使用MySql,前期添加引用 大多数情况下使用在类文件内,多数使用于aspx,ashx等带有后置 ...

  9. python建立数据库并搜索_如何建立一个简单的数据库,可供人在网络上进行搜索?...

    看题主的需求,应该是一个非常典型的web应用. 以我的经验,大概可以分三块来做.分别是接入,逻辑和存储. 接入就是你说的,"别人在网络上输入一个网址".这里的"网址&qu ...

最新文章

  1. 在ASP.NET中获取文件属性
  2. ACE .i .inl文件(转)
  3. 001——数组(一)数组知识及foreach函数应用
  4. Java forEach中 Lambda Expr中的 final变量要求
  5. 【图像处理】——比特平面原理和实现方法(全网较全面,含所有比特位图的分层方法)
  6. ipvsadm命令及lvs-nat类型web服务器集群
  7. UE4之蓝图函数分组
  8. AS3 JPEG Encoder应用:从Flash中保存图片
  9. vdbench(一)
  10. 错误报告函数:strerror和perror
  11. Mac如何创建快捷方式?
  12. 任正非谈管理--读书笔记
  13. AIDL简单实用新手教程(AIDL 包含回调,耗时处理,in out inout oneway使用、打包jar等内容) 附demo下载
  14. 精品基于Uniapp+SSM实现的公园植物介绍APP
  15. 把代码和环境做成docker镜像_Jenkins把GitHub项目做成Docker镜像
  16. java生成图片,可设置背景,文本+公式图片+图片
  17. Go error--cannot find package
  18. 评点SAP HR功能及人力资源管理软件
  19. CSS 属性 columns
  20. Linux上搭建Magento电子商务网站

热门文章

  1. 无人机停机坪是什么?有哪些作用?无人机自动巡检如何实现?
  2. [转]NLP关键词提取方法总结及实现
  3. UML图 符号的含义
  4. java技术路线思维导图_开题报告中的研究方法及技术路线指的啥?
  5. macbook配置java环境变量_MAC安装JDK及环境变量配置
  6. Cpp环境【CQYZOJ3145】【CQOI2916】学生宿舍依法集会权遭受侵害案例
  7. 感谢一路相伴的朋友们!我的个人工作室招人啦!
  8. 用PS制作燃烧的火焰人物
  9. go time.Ticker与time.Timer使用
  10. 简单的集装箱号码识别