Apache Calcite - 自定义数据源适配之访问内存列表

前言

上一篇文章中学习了Calcite基本概念,其中框架的核心能力是通过统一的Sql访问不同来源的数据。这篇文章中将通过一个简单的例子学习如何实现改功能。 最终通过sql来访问Java List中的数据。

准备工作

maven依赖

    <dependency><groupId>org.apache.calcite</groupId><artifactId>calcite-core</artifactId><version>1.36.0</version></dependency>

数据源定义

PersonList维护了一个Person对象列表,我们将通过sql访问PersonList中的数据

public class PersonList {private List<Person> personList;private PersonList(List<Person> personList) {this.personList = personList;}public static PersonList create() {return new PersonList(Lists.newArrayList());}public void addPerson(Person person) {personList.add(person);}public Iterator<Person> getIterator() {return personList.iterator();}
}public class Person {private Long id;private String name;private Integer age;public static Person createRandomly() {Person person = new Person();person.setId((long) ((int) ((Math.random() * 1000000000) + 1)));person.setName("Person" + person.getId());person.setAge((int) ((Math.random() * 100) + 1));return person;}// 省略getter setter
}

核心对象介绍

为了适配多源数据,根据上一篇文章,我们需要扩展实现Calcite中的Schema与Table。

schema

在Calcite 中,Schema 是一个非常核心的概念,它代表了一种数据组织方式,用于定义数据源的结构。Schema 可以被理解为数据库中的一个模式(schema),它包含了表(tables)、视图(views)、类型(types)和其他数据库对象的集合。在 Calcite 中,Schema 是数据访问的逻辑组织和层次结构的基础。

  • 数据源抽象:Schema 为不同类型的数据源提供了一个统一的抽象层。不论数据存储在何处(如 JDBC 数据库、文件、内存中的集合等),都可以通过定义相应的 Schema 来实现对这些数据的查询和操作。

  • 查询解析和执行:在执行 SQL 查询时,Calcite 需要知道每个表的结构,包括列名、数据类型等信息。Schema 提供了这些信息,使 Calcite 能够解析 SQL 语句并生成相应的执行计划。

  • 数据访问的统一入口:通过定义 Schema,开发者可以在不改变查询逻辑的情况下,更换后端数据源。这提供了很高的灵活性,使得系统能够适应不同的数据存储需求。

  • 支持多数据源和数据联合:Calcite 能够同时访问多个数据源,并且可以在一个查询中联合多个数据源的数据。每个数据源都由一个 Schema 描述,Calcite 负责处理数据源之间的通信和数据转换。

  • 扩展性和自定义:开发者可以实现自定义的 Schema,对数据访问逻辑进行定制。这对于特殊的数据格式或特定的性能优化非常有用。

table

Table 是一个核心概念,它代表了可查询的数据集合。在数据库术语中,一个表通常是数据的行和列的集合,而在 Calcite 中,Table 接口更加通用,可以表示不仅仅是传统的表格数据,还可以表示流数据或任何其他形式的结构化数据。

在 Calcite 的架构中,Table 是一个接口,定义在 org.apache.calcite.schema 包中。它提供了对数据的抽象视图,不关心数据的存储方式或物理格式。通过实现不同类型的 Table 接口,Calcite 能够支持多种数据源,如 JDBC 数据库、CSV 文件、内存中的数据结构等。

Calcite 中的 Table 可以具体化为以下几种类型,每种类型都有其特定的用途和功能:

  • ScannableTable:这种类型的表支持全表扫描。当查询需要访问表中的所有数据时,可以使用此类型的表。
  • FilterableTable:这种表支持在表的实现层面上应用过滤条件。这意味着不需要将整个数据集加载到内存中,而是可以推送过滤逻辑到数据源(如果数据源支持这样的操作),从而提高查询效率。
  • ProjectableFilterableTable:结合了 FilterableTable 和投影(选择特定列)的能力。这允许在读取数据时仅返回查询所需的列,减少数据传输和处理的开销。
  • TranslatableTable:这种类型的表可以被翻译成特定的执行计划。这是 Calcite 中非常强大的功能,因为它允许开发者自定义如何将 SQL 查询转换为对底层数据源的操作。

代码实现

结构描述

  1. 扩展实现Schema,对我们要访问的数据源进行抽象
  2. 扩展实现ScannableTable访问数据集
  3. 创建Table实例,关联实际数据集
  4. 创建Schema实列,维护Table实例
  5. 将创建的Schema加入Calcite
  6. 创建连接对象
  7. 执行Sql
  8. 遍历结果

实现代码

schema与table

public class ListSchema extends AbstractSchema {Map<String, Table> tableMap = new HashMap<>();public void addTable(String name, Table table) {tableMap.put(name, table);}public ListSchema() {}@Overrideprotected Map<String, Table> getTableMap() {return tableMap;}
}public class TableForList extends AbstractTable implements ScannableTable{private PersonList personList;public TableForList(PersonList personList) {this.personList = personList;}@Overridepublic Enumerable<Object[]> scan(DataContext root) {return new DefaultEnumerable<Object[]>() {@Overridepublic Enumerator<Object[]> enumerator() {return null;}@NotNull@Overridepublic Iterator<Object[]> iterator() {Iterator<Person> iterator = personList.getIterator();return new Iterator<Object[]>() {@Overridepublic boolean hasNext() {return iterator.hasNext();}// 迭代返回每行数据@Overridepublic Object[] next() {Person next = iterator.next();return new Object[]{next.getId(),next.getName(),next.getAge()};}};}};}@Overridepublic RelDataType getRowType(RelDataTypeFactory typeFactory) {return typeFactory.builder().add("id", typeFactory.createSqlType(SqlTypeName.BIGINT)).add("name",typeFactory.createSqlType(SqlTypeName.VARCHAR)).add("age",typeFactory.createSqlType(SqlTypeName.INTEGER)).build();}}

主流程

@Test
public void test() throws Exception{PersonList personList = PersonList.create();personList.addPerson(Person.createRandomly());personList.addPerson(Person.createRandomly());personList.addPerson(Person.createRandomly());Table tableForList = new TableForList(personList);ListSchema listSchema = new ListSchema();listSchema.addTable("MyTable", tableForList);Properties info = new Properties();Connection connection = DriverManager.getConnection("jdbc:calcite:", info);CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);SchemaPlus rootSchema = calciteConnection.getRootSchema();rootSchema.add("listSchema", listSchema);Statement statement = calciteConnection.createStatement();ResultSet resultSet = statement.executeQuery("select * from \"listSchema\".\"MyTable\"");while (resultSet.next()) {int columnCount = resultSet.getMetaData().getColumnCount();for (int i = 1; i <= columnCount; i++) {String value = resultSet.getString(i);System.out.printf("%s ",value);}System.out.println();}
}

异常处理清单

1.SqlValidatorException: Object ‘HTTPSCHEMA’ not found; did you mean ‘httpSchema’?

原sql写为 “select * from listSchema.MyTable”, 异常指出在执行 SQL 查询时遇到了问题。错误明确指出了问题所在:Object ‘HTTPSCHEMA’ not found; did you mean ‘httpSchema’?。这意味着 Calcite 在尝试查找名为 HTTPSCHEMA 的对象时失败了,这通常是因为对象名称的大小写不匹配。3种解决方法如下:

  • 使用引号:如果你想明确指定标识符的大小写,可以在 SQL 查询中使用双引号将标识符括起来。例如,如果 schema 名称是小写的 listSchema,这样写查询:

select * from “listSchema”.“MyTable”;

  • 配置 Calcite 的大小写敏感性:在创建 Calcite 连接时设置 unquotedCasing 来定义对于未加引号的标识符的大小写处理方式。默认情况下,Calcite 将未加引号的标识符视为大写。如果希望 Calcite 忽略标识符的大小写,可以设置 caseSensitive 为 false。

Properties info = new Properties();
info.setProperty(“caseSensitive”, “false”);
Connection connection = DriverManager.getConnection(“jdbc:calcite:”, info);

  • 连接参数中设置词法规则,这里我们设置info参数lex,根据官方手册可以有这些参数,BIG_QUERY, JAVA, MYSQL, MYSQL_ANSI, ORACLE (default), SQL_SERVER., 我们设置为JAVA即可
  Properties info = new Properties();Connection connection = DriverManager.getConnection("jdbc:calcite:", info);

2. 打印结果 java.sql.SQLException: invalid column ordinal: 0

打印结果代码为,最初实现时,i = 0 开始打印。由于框架是从下标1开始访问,因此i=0 导致输出错误

      for (int i = 1; i <= columnCount; i++) {String value = resultSet.getString(i);System.out.printf("%s ",value);}

总结

实现多源访问,了解框架结构及核心类最终实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/20258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu系统下安装mysql的步骤详解

一、下载安装包 下载地址&#xff1a; https://dev.mysql.com/downloads/repo/apt 跳转到这个页面&#xff1a; 直接点击Download。 直接点击最下面的开始下载安装包即可。 二、将安装包下载到ubuntu系统中 先将用户切换成root用户&#xff0c;把下载好的安装包复制到桌面上&…

域名更换服务器的原因

在互联网的运营过程中&#xff0c;域名更换服务器是一个常见的操作&#xff0c;可能是由于业务扩展、性能需求、成本考虑或服务质量等多种因素。然而&#xff0c;这个过程如果处理不当&#xff0c;可能会导致网站访问中断、搜索引擎排名下降或用户体验受损。本文将探讨在域名更…

系统架构设计师【第11章】: 未来信息综合技术 (核心总结)

文章目录 11.1 信息物理系统技术概述11.1.1 信息物理系统的概念11.1.2 CPS的实现11.1.3 信息物理系统的建设和应用 11.2 人工智能技术概述11.2.1 人工智能的概念11.2.2 人工智能的发展历程11.2.3 人工智能关键技术 11.3 机器人技术概述11.3.1 机器人的概念11.3.2 机…

丛林生存法则其实就两个字:输出

不管你是在上班&#xff0c;还是在灵活就业&#xff0c;现在的大环境下&#xff0c;你要想活下来&#xff0c;生存下去&#xff0c;一定要记住这两个字&#xff1a;输出。如果你能记住更多的字&#xff0c;那便是持续高水平的输出。 你如果是大厂程序员&#xff0c;你肯定发现…

Linux DHCP server 配置

参考&#xff1a;linux dhcp配置多vlan ip_linux 接口vlan-CSDN博客 配置静态IP地址&#xff1a; 给固定的MAC地址分配指定的IP地址&#xff0c;固定的IP地址不必包含在指定的IP池中&#xff0c;如果包含在IP地址池中&#xff0c;固定的IP地址会从IP地址池中移除 配置方法&…

清洁力强的洗地机前十名排行榜:2024十大洗地机热销款式好用不踩雷

如今&#xff0c;洗地机行业竞争激烈&#xff0c;各品牌紧紧抓住用户对智能化和深度清洁的需求&#xff0c;深入研究创新。经过几轮行业内部的激烈竞争后&#xff0c;许多厂商在宣传中各说各的&#xff0c;对洗地机的重要参数描述不一&#xff0c;给消费者的选择带来了不少困惑…

【CVPR_2024】:逐元素乘积为什么会产生如此令人满意的结果?

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言论文重写星形运算一层网络推广多层网络特殊情况 W 1 W_1 W1​和/或 W 2 W_2 W2​…

JDK版本特性(JDK8\11\17\21版本)

JDK版本特性 Oracle官网https://www.oracle.com/java/technologies/java-se-support-roadmap.html Oracle官网中JDK版本的说明&#xff0c;Java SE 8、11、17和21是LTS版本。也就是长期支持版本。 我们针对这几个版本了解学习下对应版本的新特性。 JDK8版本 正式发布于2014…

Facebook的创新实验室:人工智能与新技术探索

Facebook作为全球领先的社交媒体平台之一&#xff0c;一直在不断探索和应用最新的技术来改善用户体验、推动创新和拓展业务边界。其创新实验室更是探索人工智能&#xff08;AI&#xff09;和新技术的前沿&#xff0c;为未来的社交媒体发展开辟了新的可能性。本文将深入探讨Face…

C语言| 求1到100之间所有能被3整除的数之和

思路分析&#xff1a; 有两种解题方法&#xff1a; 第一种 直接在100个数字里面&#xff0c;找能被3整除的数字。 for循环里面&#xff0c;判断条件是i%3 0。 第二种 设置变量i 3&#xff0c;for循环&#xff0c;每次i 加3&#xff0c;并相加求和&#xff0c;直到遍历完…

【题解 | 分享】2023年十四届蓝桥杯国赛(Java B组)

互质 答案&#xff1a;640720414 参考&#xff1a; public class Main {static int mod 1000000007;public static void main(String[] args) {long sum power(2023, 2023);long p1 ((sum % mod) * power( 7, mod - 2)) % mod;long p2 ((sum % mod) * power( 17, mod -…

Java数据结构与算法(最长回文子串中心扩散法)

前言 回文子串是练习数据结构和算法比较好的使用场景&#xff0c;可以同时练习到双指针、动态规划等一些列算法。 实现原理 中心扩散算法实现。这里定义最长回文子串长度的大小为maxLen&#xff0c;起点位置为0. 奇数个数为中心点和偶数个数为中心点分别计算回文长度大小。…

【ZYNQ】SCU 与 GIC

在多 CPU 架构中&#xff0c;处理器之间可以对共享数据进行操作。Snoop control uint (SCU) 模块用于确保每个处理器都在最新的数据拷贝上运行&#xff0c;从而保持缓存一致性。通用中断控制器 Generic interrupt controller (GIC) 使用优先级的思想&#xff0c;管理 CPU 中断信…

Spring系统学习 - Spring入门

什么是Spring&#xff1f; Spring翻译过来就是春天的意思&#xff0c;字面意思&#xff0c;冠以Spring的意思就是想表示使用这个框架&#xff0c;代表程序员的春天来了&#xff0c;实际上就是让开发更加简单方便&#xff0c;实际上Spring确实做到了。 官网地址&#xff1a;ht…

springboot 的yaml配置文件加密

springboot 的yaml配置文件加密 一、采用yaml 插件加密添加依赖创建启动类配置加密密钥加密需要加密的内容用过测试类编写加密的YAML配置解密配置可选&#xff1a;自定义配置扩展&#xff1a;修改ENC() 一、采用yaml 插件加密 使用Jasypt对Spring Boot的YAML配置文件进行加密是…

【Mac】XMind for mac(XMind思维导图)v24.04.10311软件介绍和安装教程

软件介绍 XMind for Mac是一款功能强大的思维导图软件。它具有以下主要特点&#xff1a; 1.多样化的思维导图功能&#xff1a;XMind for Mac提供了丰富的思维导图编辑功能&#xff0c;用户可以创建各种类型的思维导图&#xff0c;包括组织结构图、逻辑图、时间轴图等&#xf…

fluent UI v9版本Dialog右上角x按钮聚焦问题解决

右上角x按钮聚焦效果展示 第一次点击不会聚焦&#xff0c;第二次或多次点击会出现这种情况。如果多个地方公用一个页面里&#xff0c;这个页面包含这个组件&#xff0c;那其它页面刚打开弹框就是聚焦状态&#xff0c;是个样式的问题。 解决&#xff1a; import * as React fr…

【Vue3】自定义组件directiveapp.use()

历史小剧场 崇祯很勤政&#xff0c;崇祯并非王国之君&#xff0c;弘光很昏庸&#xff0c;弘光活该倒霉&#xff0c;几百年来&#xff0c;我们都这样认为。 但我们之所以一直这样认为&#xff0c;只是因为有人这样告诉我们。 之所以有人这样告诉我们&#xff0c;是因为他们希望我…

比较与深浅克隆

1.比较 &#xff08;1&#xff09;Comparable接口&#xff1a;&#xff08;重写compareTo方法&#xff09; 由于它是一个接口&#xff0c;而且在这个接口中只有一个compareTo方法&#xff0c;所以所有实现该接口的类都需要重写。这个compareTo方法相当于制定一个比较标准&…

pyinstaller将py文件打包成exe

pyinstaller将py文件打包成exe 一、为什么需要将python文件打包成exe文件?二、具体操作步骤一、为什么需要将python文件打包成exe文件? python文件需要在python环境中运行,也就是需要安装python解释器。有时我们自己写的python程序需要分享给自己的朋友、同事或者合作伙伴,…