一、背景
Apache Calcite 是一个动态数据管理框架,它包含构成典型数据库管理系统的许多部分,但省略了一些关键功能:数据存储、处理数据的算法和用于存储元数据的存储库。
Calcite 有意远离存储和处理数据的业务。这使其成为在应用程序与一个或多个数据存储位置和数据处理引擎之间进行调解的绝佳选择。它也是构建数据库的完美基础:只需添加数据即可。
为了说明这一点,让我们创建一个空的Calcite实例,然后将其指向一些数据。
public class Demo1 { public static void main(String[] args) throws Exception{ 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); SchemaPlus rootSchema = calciteConnection.getRootSchema(); Schema schema = new ReflectiveSchema(new HrSchema()); 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(*) > 0"); while (resultSet.next()){ String deptno = resultSet.getString(1); int empid = resultSet.getInt(2); System.out.println("deptno="+deptno+",empid="+empid); } resultSet.close(); statement.close(); connection.close(); } public static class HrSchema{ public Employee[] emps = new Employee[1]; public Department[] depts = new Department[1]; public HrSchema(){ emps[0]=new Employee("deptno_1",12); depts[0]=new Department("deptno_1"); } public static class Employee{ public String deptno; public Integer empid; public Employee(String deptno,Integer empid){ this.deptno=deptno; this.empid=empid; } } public static class Department{ public String deptno; public Department(String deptno){ this.deptno=deptno; } } } }
数据库在哪里?
显然没有数据库,收集emps 和depts 数据,使用 ReflectiveSchema 将 Java 对象注册为Schema
calcite不想拥有数据,它甚至没有最喜欢的数据格式。此示例使用内存中的数据集,并使用 linq4j 库中的 groupBy 和 join 等运算符处理它们。但calcite也可以处理其他数据格式的数据,
如果使用JDBC,那么将
Schema schema = new ReflectiveSchema(new HrSchema());
替换为
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");
calcite将在 JDBC 中执行相同的查询。对于应用程序,数据和 API 是相同的,但在幕后的实现却大不相同。calcite使用优化器规则将 JOIN 和 GROUP BY 操作推送到源数据库。
内存中和 JDBC 只是两个熟悉的例子。calcite可以处理任何数据源和数据格式。若要添加数据源,需要编写一个适配器,告诉方解石数据源中的哪些集合应视为“表”。
对于更高级的集成,您可以编写优化器规则。优化器规则允许calcite访问新格式的数据,允许注册新的运算符(例如更好的连接算法),并允许calcite优化查询转换为运算符的方式。calcite将规则和运算符与内置规则和运算符相结合,应用基于成本的优化,并生成有效的计划。
二、编写适配器
example/csv 下的子项目提供了一个 CSV 适配器,该适配器功能齐全,可用于应用程序,但也足够简单,如果您正在编写自己的适配器,可以用作一个很好的模板。