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

根据这些数据,这些键可分类如下:

  • 类型键af (始终为整数)

  • 动态键b (混合字符串/整数)

  • 共享键e (不经常出现的键)

第二阶段:存储优化

第 1 阶段的分类决定了存储布局。Milvus 使用专为查询优化的列格式。

Json Shredding Flow 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 切碎的行为进行微调。

参数名称

说明

默认值

调整建议

common.enabledJSONShredding

控制是否启用 JSON 切碎构建和加载流程。

必须设为true才能激活该功能。

common.usingjsonShreddingForQuery

控制 Milvus 是否使用粉碎数据进行加速。

为真

设为false,作为查询失败时的恢复措施,恢复到原始查询路径。

queryNode.mmap.jsonShredding

决定 Milvus 在加载粉碎数据时是否使用 mmap。

有关详情,请参阅使用 mmap

此设置通常为性能优化。只有在系统有特定内存管理需求或限制的情况下才会调整它。

dataCoord.jsonShreddingMaxColumns

将存储在粉碎列中的 JSON 键的最大数量。

如果频繁出现的键的数量超过此限制,Milvus 将优先对最频繁出现的键进行粉碎,其余键将存储在共享列中。

1024

这足以满足大多数情况的需要。对于有数千个频繁出现密钥的 JSON,可能需要增加这一限制,但要监控存储空间的使用情况。

dataCoord.jsonShreddingRatioThreshold

要将一个 JSON 密钥粉碎到粉碎列中,该密钥必须具备的最小出现率。

如果一个密钥的出现比率高于此阈值,则该密钥被视为频繁出现。

0.3

如果符合粉碎标准的密钥数量超过dataCoord.jsonShreddingMaxColumns 限制,则增加(例如增加到 0.5)。这将使阈值更加严格,减少符合粉碎条件的钥匙数量。

如果你想粉碎更多出现频率低于默认 30% 阈值的密钥,则将阈值降低(例如降低到 0.1)。

性能基准

我们的测试表明,在不同的 JSON 密钥类型和查询模式下,性能都有显著提高。

测试环境和方法

  • 硬件:1 核/8GB 集群

  • 数据集来自JSONBench的 100 万个文档

  • 平均文档大小:478.89 字节

  • 测试持续时间100 秒,测量 QPS 和延迟

结果:键入键

该测试测量的是查询大多数文档中存在的键时的性能。

查询表达式

键值类型

QPS (不粉碎)

QPS (已粉碎)

性能提升

json['time_us'] > 0

整数

8.69

287.50

33x

json['kind'] == 'commit'

字符串

8.42

126.1

14.9x

结果:共享键

本测试重点查询属于 "共享 "类别的稀疏嵌套键。

查询表达式

键值类型

QPS (不粉碎)

QPS (已粉碎)

性能提升

json['identity']['seq'] > 0

嵌套整数

4.33

385

88.9x

json['identity']['did'] == 'xxxxx'

嵌套字符串

7.6

352

46.3x

关键信息

  • 共享关键字查询显示出最显著的改进(快达 89 倍)

  • 键入式查询可持续提高 15-30 倍性能

  • 所有查询类型都从 JSON 破碎处理中获益,性能没有下降

常见问题

  • 如何验证 JSON 破碎处理是否正常工作?

    1. 首先,使用Birdwatcher工具中的show segment --format table 命令检查数据是否已构建。如果成功,输出将在Json Key Stats 字段下包含shredding_data/shared_key_index/

      Birdwatcher Output Birdwatcher 输出

    2. 接下来,在查询节点上运行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 字段概述

想要更快、更简单、更好用的 Milvus SaaS服务 ?

Zilliz Cloud是基于Milvus的全托管向量数据库,拥有更高性能,更易扩展,以及卓越性价比

免费试用 Zilliz Cloud
反馈

此页对您是否有帮助?