背景与 JSON 类型介绍
GreptimeDB v0.10 (最新版本 v0.11.0 已发布)引入了 JSON 类型支持,完善了半结构化和结构化数据的支持能力。GreptimeDB 的 Schemaless 模型本身类似 MongoDB,在通过 gRPC、Prometheus Remote Write 等协议写入的时候支持动态的建表和自动加列,可灵活应对数据结构的不确定性。不过在很多场景下,很多列都的是结构化的,比如典型的 OpenTelemetry 里的 Traces (链路追踪):
{
"name": "hello",
"context": {
"trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",
"span_id": "051581bf3cb55c13"
},
"parent_id": null,
"start_time": "2022-04-29T18:52:58.114201Z",
"end_time": "2022-04-29T18:52:58.114687Z",
"attributes": {
"http.route": "some_route1"
},
"events": [
{
"name": "Guten Tag!",
"timestamp": "2022-04-29T18:52:58.114561Z",
"attributes": {
"event_attributes": 1
}
}
]
}
其中 context
、attributes
和 events
都是 JSON 对象或数组。GreptimeDB 的目标是成为一个能统一处理指标、日志、事件以及链路的时序数据库,就必须支持 JSON 类型。
本文以 GreptimeDB 的 MySQL 协议支持来举例,并且假设读者已安装 GreptimeDB v0.10 版本。安装指南请阅读文档。
JSON 类型例子
使用指南:创建表与插入数据
首先,你可以创建表的时候将某个列指定为 JSON 类型:
CREATE TABLE traces(
`name` STRING,
context JSON,
parent_id STRING,
start_time TIMESTAMP,
end_time TIMESTAMP,
attributes JSON,
events JSON,
TIME INDEX (start_time),
PRIMARY KEY(`name`, parent_id, context)
);
我们这里将 context
、attributes
和 events
都设置为了 JSON 类型,时间索引设置为 start_time,将 name
、parent_id
和 context
加入 Primary Key,也就是作为标签列。
由于
name
是保留关键字,因此需要使用反引号进行转义。
尝试插入数据:
INSERT INTO traces
VALUES
(
'hello',
'{
"trace_id": "5b8aa5a2d2c872e8321cf37308d69df2",
"span_id": "051581bf3cb55c13"
}',
null,
'2022-04-29T18:52:58.114201Z'::TIMESTAMP,
'2022-04-29T18:52:58.114687Z'::TIMESTAMP,
'{
"http.route": "some_route1"
}',
'[
{
"name": "Guten Tag!",
"timestamp": "2022-04-29T18:52:58.114561Z",
"attributes": {
"event_attributes": 1
}
}
]');
用户可以直接将 JSON 字符串作为 JSON 类型写入, GreptimeDB 会自动转换为 JSON 类型。
查询与处理 JSON 数据
查询表:
mysql> SELECT * FROM traces\G;
*************************** 1. row ***************************
name: hello
context: {"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}
parent_id: NULL
start_time: 2022-04-29 18:52:58.114000
end_time: 2022-04-29 18:52:58.114000
attributes: {"http.route":"some_route1"}
events: [{"attributes":{"event_attributes":1},"name":"Guten Tag!","timestamp":"2022-04-29T18:52:58.114561Z"}]
1 row in set (0.01 sec)
ERROR:
No query specified
对于表的数据查询,因为可以从表的 schema 中拿到类型信息,所以查询的时候会自动将 JSON 类型转化为字符串来展示,如上所示。 GreptimeDB 提供了一些 JSON 函数来帮助处理 JSON 类型。
比如 parse_json
,可以将字符串解析为 JSON:
mysql> select parse_json('{"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}');
+--------------------------------------------------------------------------------------------------+
| parse_json(Utf8("{"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}")) |
+--------------------------------------------------------------------------------------------------+
| @ span_idtrace_id051581bf3cb55c135b8aa5a2d2c872e8321cf37308d69df2 |
+--------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
由于 GreptimeDB 底层是用 binary 类型来存储 JSON, parse_json
返回的是一个 binary 的结果。
json_to_string
函数将 JSON 类型转为字符串:
mysql> select json_to_string(parse_json('{"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}'));
+------------------------------------------------------------------------------------------------------------------+
| json_to_string(parse_json(Utf8("{"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}"))) |
+------------------------------------------------------------------------------------------------------------------+
| {"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"} |
+------------------------------------------------------------------------------------------------------------------+
通过 json_get_
系列函数提取 JSON 中的特定字段,例如:
mysql> SELECT json_get_string(context, 'trace_id') FROM traces;
+--------------------------------------------------+
| json_get_string(traces.context,Utf8("trace_id")) |
+--------------------------------------------------+
| 5b8aa5a2d2c872e8321cf37308d69df2 |
+--------------------------------------------------+
1 row in set (0.02 sec)
mysql> select json_get_string(parse_json('{"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}'), 'span_id');
+-----------------------------------------------------------------------------------------------------------------------------------+
| json_get_string(parse_json(Utf8("{"span_id":"051581bf3cb55c13","trace_id":"5b8aa5a2d2c872e8321cf37308d69df2"}")),Utf8("span_id")) |
+-----------------------------------------------------------------------------------------------------------------------------------+
| 051581bf3cb55c13 |
+-----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
看到这里,熟悉 MongoDB 的朋友可能要问,我们能不能直接用 SELECT context.trace_id FROM traces
的方式来查询?
很遗憾暂时不行,因为我们没法保证 context.trace_id
的类型在所有列中是一致的,而 GreptimeDB SQL 的查询引擎和返回结果却是强类型的,这就需要用户明确来指定下希望返回的类型,不符合该类型的字段将尝试类型转换,或者返回 null
。
我们插入一条 trace_id
为整数的数据,测试其对不同 JSON 类型字段的兼容性:
INSERT INTO traces(name, context,start_time)
values ('world', '{"trace_id": 999}',now());
接下来使用 json_get_string
和 json_get_int
分别来查询:
mysql> SELECT json_get_string(context, 'trace_id') FROM traces;
+--------------------------------------------------+
| json_get_string(traces.context,Utf8("trace_id")) |
+--------------------------------------------------+
| 999 |
| 5b8aa5a2d2c872e8321cf37308d69df2 |
+--------------------------------------------------+
2 rows in set (0.02 sec)
mysql> SELECT json_get_int(context, 'trace_id') FROM traces;
+-----------------------------------------------+
| json_get_int(traces.context,Utf8("trace_id")) |
+-----------------------------------------------+
| NULL |
| 999 |
+-----------------------------------------------+
2 rows in set (0.02 sec)
结果显示,json_get_string
能将两行结果都正确返回,且整数 999 转为字符串并正常返回,而 json_get_int
则正确提取了整型字段 999
,但由于另一行的 trace_id
为字符串,无法转换,因此返回了 NULL
。
总结
GreptimeDB v0.10 引入了 JSON 类型后,通过 JSON 函数,增强了半结构化和结构化数据的存取能力。未来, GreptimeDB 也将进一步加强对 JSON 类型的支持,例如允许对 JSON 内部分字段建立倒排索引来加速查询,引入类似 Databend JQ 函数来简化数据处理等。
v0.10 系列文章的合集:
后续文章发布中,敬请期待!
关于 Greptime
Greptime 格睿科技专注于为可观测、物联网及车联网等领域提供实时、高效的数据存储和分析服务,帮助客户挖掘数据的深层价值。目前基于云原生的时序数据库 GreptimeDB 已经衍生出多款适合不同用户的解决方案,更多信息或 demo 展示请联系下方小助手(微信号:greptime)。
欢迎对开源感兴趣的朋友们参与贡献和讨论,从带有 good first issue 标签的 issue 开始你的开源之旅吧~期待在开源社群里遇见你!添加小助手微信即可加入“技术交流群”与志同道合的朋友们面对面交流哦~
Star us on GitHub Now: https://github.com/GreptimeTeam/greptimedb
Twitter: https://twitter.com/Greptime
Slack: https://greptime.com/slack