Spring Boot3.3 + Apache Calcite 实战:用 SQL 动态查询 JSON 数据源
在现代 Web 应用开发中,数据来源日益多样化,除了传统的关系型数据库,JSON 文件、NoSQL 以及各种 API 接口提供的数据格式也被广泛使用。为了以统一的方式对异构数据源进行查询,Apache Calcite 提供了强大且灵活的 SQL 查询引擎,可以通过虚拟视图将 JSON 数据建模为表结构,再用标准 SQL 语句进行高效查询。
本篇文章将结合 Spring Boot3.3 与 Apache Calcite,详细讲解如何将本地 JSON 文件作为数据源,通过 Calcite 提供的 schema 映射机制进行 SQL 查询操作,帮助你轻松实现对 JSON 数据的结构化访问与动态查询。
Apache Calcite 简介
Apache Calcite 是一个开源的动态数据管理框架,它本身并不是数据库,而是一个提供 SQL 查询解析、验证、优化和执行的中间层框架,支持对多种数据源进行统一访问。其核心特性包括:
- 多数据源支持支持关系型数据库、CSV、JSON、MongoDB、Elasticsearch 等多种数据源。
- SQL 引擎具备完整的 SQL 解析、校验、优化和执行能力。
- 虚拟化查询可将非结构化或半结构化数据通过 schema 建模为结构化视图。
- 可插拔架构支持自定义函数、自定义规则、插件式架构。
在本文中,我们将使用 Apache Calcite 对本地 JSON 文件进行虚拟化建模,并通过标准 SQL 查询访问数据。
项目依赖配置(pom.xml)
org.apache.calcite
calcite-core
1.35.0
com.fasterxml.jackson.core
jackson-databind
org.springframework.boot
spring-boot-starter-web
项目结构预览
├── resources/
│ ├── model.json # 本地 JSON 数据
│ └── json-model.schema.json # Calcite 模型 schema
├── controller/
│ └── CalciteQueryController.java
├── service/
│ └── CalciteQueryService.java
├── config/
│ └── CalciteUtils.java # Calcite 配置和执行类
JSON 数据样例 model.json
[
{"id":1,"name":"Alice","age":30},
{"id":2,"name":"Bob","age":25},
{"id":3,"name":"Charlie","age":28}
]
创建 Calcite 模型文件 json-model.schema.json
{
"version":"1.0",
"defaultSchema":"json_schema",
"schemas":[
{
"name":"json_schema",
"type":"custom",
"factory":"org.apache.calcite.adapter.json.JsonSchemaFactory",
"operand":{
"directory":"src/main/resources",
"flavor":"file"
},
"tables":[
{
"name":"model",
"type":"custom",
"factory":"org.apache.calcite.adapter.json.JsonTableFactory",
"operand":{
"path":"model.json"
}
}
]
}
]
}
Calcite 工具类 CalciteUtils.java
@Slf4j
public class CalciteUtils {
public static Connection getConnection() throws Exception {
Properties info = new Properties();
try {
String modelPath = Paths.get("src/main/resources/json-model.schema.json").toAbsolutePath().toString();
info.put("model", modelPath);
return DriverManager.getConnection("jdbc:calcite:", info);
} catch (Exception e) {
log.error("初始化 Calcite 连接失败", e);
throw e;
}
}
public static List
查询接口实现
CalciteQueryService.java
@Service
public class CalciteQueryService {
public List> query(String sql) throws Exception {
return CalciteUtils.executeQuery(sql);
}
}
CalciteQueryController.java
@RestController
@RequestMapping("/calcite")
public class CalciteQueryController {
@Autowired
private CalciteQueryService service;
@GetMapping("/query")
public ResponseEntity> query(@RequestParam String sql) {
try {
return ResponseEntity.ok(service.query(sql));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage());
}
}
}
测试
启动项目后,访问:
http://localhost:8080/calcite/query?sql=SELECT * FROM json_schema.model WHERE age > 25
返回结果:
[
{"id":1,"name":"Alice","age":30},
{"id":3,"name":"Charlie","age":28}
]
结语
Apache Calcite 作为一个高度可扩展的查询引擎,在大数据和异构数据访问场景中具有广泛的应用价值。它不仅支持灵活的 SQL 查询语法,还能与各类数据源轻松集成,让开发者能够以统一方式访问结构化和非结构化数据。
通过本篇文章我们学习了如何结合 Spring Boot3.3 利用 Calcite 查询本地 JSON 文件,实现了无需转换即可用 SQL 查询 JSON 的能力,为复杂的数据分析与快速原型开发提供了极大的便利。
未来你还可以尝试对接 Elasticsearch、MongoDB、CSV 文件等更多数据源,构建统一查询平台,充分发挥 Calcite 的潜能。