JSON 切碎Compatible with Milvus 2.6.2+
通过将传统的基于行的存储转换为优化的列式存储,JSON 切碎可加速 JSON 查询。在保持 JSON 数据建模灵活性的同时,Milvus 在幕后执行列优化,从而显著提高了访问和查询效率。
JSON 切碎对大多数 JSON 查询场景都很有效。在以下情况下,性能优势会更加明显
更大、更复杂的 JSON 文档- 随着文档大小的增加,性能收益也会增加
读取繁重的工作负载--经常对 JSON 键进行过滤、排序或搜索
混合查询模式- 不同 JSON 键的查询从混合存储方法中获益
工作原理
JSON 粉碎过程分为三个不同阶段,以优化数据,实现快速检索。
第 1 阶段:输入和密钥分类
随着新 JSON 文档的写入,Milvus 不断对其进行采样和分析,以建立每个 JSON 关键字的统计数据。这种分析包括关键字的出现率和类型稳定性(其数据类型在不同文档中是否一致)。
根据这些统计数据,JSON 关键字被分为以下几类,以便进行最佳存储。
JSON 关键字分类
键类型 |
描述 |
|---|---|
类型键 |
存在于大多数文档中且始终具有相同数据类型(如所有整数或所有字符串)的键。 |
动态键 |
经常出现但具有混合数据类型的键(例如,有时是字符串,有时是整数)。 |
共享键 |
不常出现或嵌套的键,低于可配置的频率阈值。 |
分类示例
考虑包含以下 JSON 键的 JSON 数据样本:
{"a": 10, "b": "str1", "f": 1}
{"a": 20, "b": "str2", "f": 2}
{"a": 30, "b": "str3", "f": 3}
{"a": 40, "b": 1, "f": 4} // b becomes mixed type
{"a": 50, "b": 2, "e": "rare"} // e appears infrequently
根据这些数据,这些键可分类如下:
类型键:
a和f(始终为整数)动态键:
b(混合字符串/整数)共享键:
e(不经常出现的键)
第二阶段:存储优化
第 1 阶段的分类决定了存储布局。Milvus 使用专为查询优化的列格式。
Json 粉碎流程
切碎列:对于类型 键和动态 键,数据被写入专用列。这种列式存储允许在查询时进行快速、直接的扫描,因为 Milvus 可以只读取给定键所需的数据,而无需处理整个文档。
共享列:所有共享键都一起存储在一个紧凑的二进制 JSON 列中。在这一列上建立共享键反转索引。该索引对于加速低频键的查询至关重要,它允许 Milvus 快速剪裁数据,有效地将搜索空间缩小到仅包含指定键的行。
第 3 阶段查询执行
最后阶段利用优化的存储布局,为每个查询谓词智能选择最快的路径。
快速路径:对键入/动态键(如
json['a'] < 100)的查询直接访问专用列优化路径:对共享键(如
json['e'] = 'rare')的查询使用倒排索引来快速查找相关文档
启用 JSON 切碎功能
要激活该功能,请在milvus.yaml 配置文件中将common.enabledJSONShredding 设置为true 。新数据将自动触发粉碎过程。
# milvus.yaml
...
common:
enabledJSONShredding: true # Indicates whether to enable JSON key stats build and load processes
...
一旦启用,Milvus 将在摄取时开始分析和重组 JSON 数据,而无需任何进一步的人工干预。
参数调整
对于大多数用户来说,一旦启用 JSON 切碎,其他参数的默认设置就足够了。不过,您可以使用milvus.yaml 中的这些参数对 JSON 切碎的行为进行微调。
参数名称 |
说明 |
默认值 |
调整建议 |
|---|---|---|---|
|
控制是否启用 JSON 切碎构建和加载流程。 |
假 |
必须设为true才能激活该功能。 |
|
控制 Milvus 是否使用粉碎数据进行加速。 |
为真 |
设为false,作为查询失败时的恢复措施,恢复到原始查询路径。 |
|
决定 Milvus 在加载粉碎数据时是否使用 mmap。 有关详情,请参阅使用 mmap。 |
真 |
此设置通常为性能优化。只有在系统有特定内存管理需求或限制的情况下才会调整它。 |
|
将存储在粉碎列中的 JSON 键的最大数量。 如果频繁出现的键的数量超过此限制,Milvus 将优先对最频繁出现的键进行粉碎,其余键将存储在共享列中。 |
1024 |
这足以满足大多数情况的需要。对于有数千个频繁出现密钥的 JSON,可能需要增加这一限制,但要监控存储空间的使用情况。 |
|
要将一个 JSON 密钥粉碎到粉碎列中,该密钥必须具备的最小出现率。 如果一个密钥的出现比率高于此阈值,则该密钥被视为频繁出现。 |
0.3 |
如果符合粉碎标准的密钥数量超过 如果你想粉碎更多出现频率低于默认 30% 阈值的密钥,则将阈值降低(例如降低到 0.1)。 |
性能基准
我们的测试表明,在不同的 JSON 密钥类型和查询模式下,性能都有显著提高。
测试环境和方法
硬件:1 核/8GB 集群
数据集来自JSONBench的 100 万个文档
平均文档大小:478.89 字节
测试持续时间100 秒,测量 QPS 和延迟
结果:键入键
该测试测量的是查询大多数文档中存在的键时的性能。
查询表达式 |
键值类型 |
QPS (不粉碎) |
QPS (已粉碎) |
性能提升 |
|---|---|---|---|---|
|
整数 |
8.69 |
287.50 |
33x |
|
字符串 |
8.42 |
126.1 |
14.9x |
结果:共享键
本测试重点查询属于 "共享 "类别的稀疏嵌套键。
查询表达式 |
键值类型 |
QPS (不粉碎) |
QPS (已粉碎) |
性能提升 |
|---|---|---|---|---|
|
嵌套整数 |
4.33 |
385 |
88.9x |
|
嵌套字符串 |
7.6 |
352 |
46.3x |
关键信息
共享关键字查询显示出最显著的改进(快达 89 倍)
键入式查询可持续提高 15-30 倍性能
所有查询类型都从 JSON 破碎处理中获益,性能没有下降
常见问题
如何验证 JSON 破碎处理是否正常工作?
首先,使用Birdwatcher工具中的
show segment --format table命令检查数据是否已构建。如果成功,输出将在Json Key Stats 字段下包含shredding_data/和shared_key_index/。
Birdwatcher 输出 接下来,在查询节点上运行
show loaded-json-stats验证数据是否已加载。输出将显示每个查询节点已加载碎纸数据的详细信息。
如果遇到错误怎么办?
如果构建或加载过程失败,可以通过设置
common.enabledJSONShredding=false快速禁用该功能。要清除任何剩余任务,请使用Birdwatcher 中的remove stats-task <task_id>命令。如果查询失败,可设置common.usingjsonShreddingForQuery=false恢复到原始查询路径,绕过粉碎数据。如何在 JSON 切碎和 JSON 索引之间进行选择?
JSON 切碎非常适合文档中频繁出现的键,尤其是复杂的 JSON 结构。它结合了列式存储和反转索引的优点,非常适合查询许多不同键的重读取场景。不过,对于非常小的 JSON 文档,不建议使用这种方法,因为性能提升微乎其微。键值占 JSON 文档总大小的比例越小,粉碎带来的性能优化效果就越好。
JSON 索引更适合对基于特定键值的查询进行有针对性的优化,而且存储开销更低。它适用于较简单的 JSON 结构。请注意,JSON 切碎不包括对数组内部键的查询,因此需要 JSON 索引来加速这些查询。
有关详情,请参阅JSON 字段概述。