JSON 类型

JSON(JavaScript Object Notation)是云器 Lakehouse 的原生半结构化数据类型。相比使用 STRING 存储 JSON 文本,使用原生 JSON 类型可以利用列式存储优化谓词下推,显著提升查询性能并减少存储开销。

为什么使用 JSON 类型?

特性STRING 类型JSON 类型
存储方式纯文本,无法压缩结构列式存储:高频字段自动提取为独立列存储
查询性能需全量扫描并解析文本列裁剪:仅读取需要的字段,无需解析整行
类型安全提取后需手动 CAST内置
json_extract_bigint
json_extract_bigint
等函数直接返回 SQL 类型

1. 构建 JSON 数据

1.1 从字符串解析(推荐)

使用

parse_json
parse_json
(或
json_parse
json_parse
)函数将字符串转换为 JSON 对象。这是处理外部导入数据最常用的方式。

SELECT parse_json('{"id": 1, "name": "Lakehouse"}') AS data; -- 结果: {"id":1,"name":"Lakehouse"}

1.2 JSON 常量

在 SQL 中直接定义 JSON 数据,使用

JSON '...'
JSON '...'
语法。

SELECT JSON '{"key": "value"}' AS const_json;

1.3 使用构造函数

从 SQL 值动态构建 JSON 对象或数组。

-- 构建对象 SELECT json_object('id', 1, 'name', 'Lakehouse'); -- 结果: {"id":1,"name":"Lakehouse"} -- 构建数组 SELECT json_array(1, 2, 3, 'test'); -- 结果: [1,2,3,"test"]


2. 查询与访问 JSON 数据

Lakehouse 提供两种访问 JSON 内部数据的方式:快捷语法(返回 JSON 类型)和 提取函数(返回 SQL 类型)。

2.1 快捷语法
['key']
['key']

适用于快速访问,返回结果仍为 JSON 类型。支持嵌套访问和数组索引。

WITH t AS ( SELECT parse_json('{"user": {"id": 101, "tags": ["vip", "active"]}}') AS data ) SELECT data['user']['id'] AS user_id_json, -- 返回 JSON 类型的 101 data['user']['tags'][0] AS first_tag; -- 返回 JSON 类型的 "vip"

2.2 类型提取函数(推荐用于计算)

使用

json_extract_*
json_extract_*
系列函数,直接返回 SQL 原生类型(如 BIGINT, STRING),便于后续计算和过滤。

函数返回类型示例
json_extract_string
json_extract_string
STRING
json_extract_string(data, '$.name')
json_extract_string(data, '$.name')
json_extract_bigint
json_extract_bigint
BIGINT
json_extract_bigint(data, '$.id')
json_extract_bigint(data, '$.id')
json_extract_int
json_extract_int
INT
json_extract_int(data, '$.age')
json_extract_int(data, '$.age')
json_extract_double
json_extract_double
DOUBLE
json_extract_double(data, '$.price')
json_extract_double(data, '$.price')
json_extract_float
json_extract_float
FLOAT
json_extract_float(data, '$.score')
json_extract_float(data, '$.score')
json_extract_boolean
json_extract_boolean
BOOLEAN
json_extract_boolean(data, '$.is_active')
json_extract_boolean(data, '$.is_active')
json_extract_date
json_extract_date
DATE
json_extract_date(data, '$.birth_date')
json_extract_date(data, '$.birth_date')
json_extract_timestamp
json_extract_timestamp
TIMESTAMP
json_extract_timestamp(data, '$.created')
json_extract_timestamp(data, '$.created')

示例

SELECT json_extract_bigint(data, '$.user.id') AS user_id, json_extract_string(data, '$.user.tags[0]') AS first_tag FROM (SELECT parse_json('{"user": {"id": 101, "tags": ["vip"]}}') AS data) t;


3. 类型转换(注意事项)

在处理 JSON 字符串时,

parse_json
parse_json
::json
::json
(CAST)
的行为完全不同,请务必注意:

方式语义示例结果
parse_json(str)
parse_json(str)
将字符串内容解析为 JSON 结构
parse_json('{"a":1}')
parse_json('{"a":1}')
→ JSON 对象
{"a":1}
{"a":1}
str::json
str::json
将字符串整体视为一个 JSON 字符串值
'{"a":1}'::json
'{"a":1}'::json
→ JSON 字符串
"{\"a\":1}"
"{\"a\":1}"

实测对比

-- 场景 1:正确解析 SELECT parse_json('{"a": 1}')['a']; -- 结果: 1 (成功获取值) -- 场景 2:错误转换 (Cast) SELECT ('{"a": 1}'::json)['a']; -- 结果: NULL (因为这是一个字符串,没有 key 'a')

结论:当你的数据源是 JSON 格式的字符串(如日志、API 响应)时,必须使用

parse_json
parse_json
::json
::json
通常用于将普通字符串(如
"hello"
"hello"
)转换为 JSON 字符串类型。


4. 性能优化实战

4.1 谓词下推(Predicate Pushdown)

当使用

json_extract_bigint
json_extract_bigint
等强类型函数进行过滤时,Lakehouse 可以直接扫描底层的优化列,避免全表解析。

-- 高效查询:利用列存索引 SELECT * FROM logs WHERE json_extract_bigint(data, '$.status') = 200; -- 低效查询:全表扫描解析 SELECT * FROM logs WHERE data['status']::bigint = 200; -- 注意:某些版本可能无法下推

4.2 处理非法 JSON

parse_json
parse_json
具有容错性。如果输入不是合法的 JSON,它会返回
NULL
NULL
而不是报错,这在处理脏数据时非常有用。

SELECT parse_json('invalid json'); -- 结果: NULL SELECT parse_json('{"a": 1}'); -- 结果: {"a":1}


5. 限制与注意事项

  • 不支持排序/分组:JSON 列本身不支持
    ORDER BY
    ORDER BY
    GROUP BY
    GROUP BY
    JOIN
    JOIN
    。必须提取出具体字段后才能进行这些操作。
  • 大小限制:默认 JSON 字符串最大长度为 16MB。如需调整,可修改表属性:

    ALTER TABLE table_name SET PROPERTIES("cz.storage.write.max.json.bytes"="33554432");

  • Key 顺序:JSON 对象内部的 Key 顺序在存储时可能会被重排,输出顺序与输入不一致属于正常现象。

相关文档

联系我们
预约咨询
微信咨询
电话咨询