在现代 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)
复制
<dependencies>
<!-- Apache Calcite 核心依赖 -->
<dependency>
<groupId>org.apache.calcite</groupId>
<artifactId>calcite-core</artifactId>
<version>1.35.0</version>
</dependency>
<!-- Jackson 用于 JSON 解析 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Spring Boot Web 模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.
项目结构预览
复制
├── resources/
│ ├── model.json # 本地 JSON 数据
│ └── json-model.schema.json # Calcite 模型 schema
├── controller/
│ └── CalciteQueryController.java
├── service/
│ └── CalciteQueryService.java
├── config/
│ └── CalciteUtils.java # Calcite 配置和执行类1.2.3.4.5.6.7.8.9.
JSON 数据样例 model.json
复制
[
{"id":1,"name":"Alice","age":30},
{"id":2,"name":"Bob","age":25},
{"id":3,"name":"Charlie","age":28}
]1.2.3.4.5.
创建 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"
}
}
]
}
]
}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.
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<Map<String, Object>> executeQuery(String sql) throws Exception {
List<Map<String, Object>> results = new ArrayList<>();
try (Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
ResultSetMetaData meta = rs.getMetaData();
int columnCount = meta.getColumnCount();
while (rs.next()) {
Map<String, Object> row = new LinkedHashMap<>();
for (int i = 1; i <= columnCount; i++) {
row.put(meta.getColumnLabel(i), rs.getObject(i));
}
results.add(row);
}
}
return results;
}
}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.
查询接口实现
CalciteQueryService.java
复制
@Service
public class CalciteQueryService {
public List<Map<String, Object>> query(String sql) throws Exception {
return CalciteUtils.executeQuery(sql);
}
}1.2.3.4.5.6.
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());
}
}
}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.
测试
启动项目后,访问:
复制
http://localhost:8080/calcite/query?sql=SELECT * FROM json_schema.model WHERE age > 251.
返回结果:
复制
[
{"id":1,"name":"Alice","age":30},
{"id":3,"name":"Charlie","age":28}
]1.2.3.4.
结语
Apache Calcite 作为一个高度可扩展的查询引擎,在大数据和异构数据访问场景中具有广泛的应用价值。它不仅支持灵活的 SQL 查询语法,还能与各类数据源轻松集成,让开发者能够以统一方式访问结构化和非结构化数据。
通过本篇文章我们学习了如何结合 Spring Boot3.3 利用 Calcite 查询本地 JSON 文件,实现了无需转换即可用 SQL 查询 JSON 的能力,为复杂的数据分析与快速原型开发提供了极大的便利。
未来你还可以尝试对接 Elasticsearch、MongoDB、CSV 文件等更多数据源,构建统一查询平台,充分发挥 Calcite 的潜能。