索引
如何索引和搜索 JSON 文档
除了对 Redis 哈希进行索引外,Redis Stack 还支持对 JSON 文档进行索引。
前置要求
在对 JSON 文档进行索引和搜索之前,你需要确保数据库符合以下条件之一:
- Redis Stack,它默认包含 JSON 和搜索查询功能。
- Redis 6.x 或更高版本,并安装并启用了以下模块:
- RediSearch 2.2 或更高版本
- RedisJSON 2.0 或更高版本
使用 JSON 模式创建索引
在使用 FT.CREATE
命令创建索引时,添加 ON JSON
关键字即可索引数据库中已有和未来存储的所有 JSON 文档。
在定义 SCHEMA
时,你可以使用 JSONPath 表达式。每个 JSONPath 表达式的结果都会被索引,并与一个逻辑名称(称为 attribute
,之前叫做 field
)关联。你可以在查询中使用这些属性。
注意:在
FT.CREATE
中,attribute
是可选的。
创建 JSON 索引的语法:
FT.CREATE {index_name} ON JSON SCHEMA {json_path} AS {attribute} {type}
例如,以下命令为表示库存商品的 JSON 文档创建索引,索引了名称、描述、价格和图片的向量嵌入:
127.0.0.1:6379> FT.CREATE itemIdx ON JSON PREFIX 1 item: SCHEMA $.name AS name TEXT $.description AS description TEXT $.price AS price NUMERIC $.embedding AS embedding VECTOR FLAT 6 DIM 4 DISTANCE_METRIC L2 TYPE FLOAT32
关于 JSON 索引 SCHEMA
限制的更多细节,请参阅 索引限制。
添加 JSON 文档
创建索引后,Redis Stack 会自动对数据库中已有、修改或新建的 JSON 文档进行索引。对于已有文档,索引会在后台异步运行,因此文档可能需要一段时间才能在搜索中可用。修改和新建文档会同步索引,因此在执行完添加或修改命令后,文档就能被立即检索。
你可以使用任何 JSON 写入命令,例如 JSON.SET
和 JSON.ARRAPPEND
,来创建或修改 JSON 文档。
以下是表示库存商品的两个 JSON 文档示例:
商品 1:
{
"name": "Noise-cancelling Bluetooth headphones",
"description": "Wireless Bluetooth headphones with noise-cancelling technology",
"connection": {
"wireless": true,
"type": "Bluetooth"
},
"price": 99.98,
"stock": 25,
"colors": ["black", "silver"],
"embedding": [0.87, -0.15, 0.55, 0.03]
}
商品 2:
{
"name": "Wireless earbuds",
"description": "Wireless Bluetooth in-ear headphones",
"connection": {
"wireless": true,
"type": "Bluetooth"
},
"price": 64.99,
"stock": 17,
"colors": ["black", "white"],
"embedding": [-0.7, -0.51, 0.88, 0.14]
}
使用 JSON.SET
将它们存储到数据库:
127.0.0.1:6379> JSON.SET item:1 $ '{"name":"Noise-cancelling Bluetooth headphones","description":"Wireless Bluetooth headphones with noise-cancelling technology","connection":{"wireless":true,"type":"Bluetooth"},"price":99.98,"stock":25,"colors":["black","silver"],"embedding":[0.87,-0.15,0.55,0.03]}'
"OK"
127.0.0.1:6379> JSON.SET item:2 $ '{"name":"Wireless earbuds","description":"Wireless Bluetooth in-ear headphones","connection":{"wireless":true,"type":"Bluetooth"},"price":64.99,"stock":17,"colors":["black","white"],"embedding":[-0.7,-0.51,0.88,0.14]}'
"OK"
由于在这种情况下索引是同步的,所以文档会在 [JSON.SET
] 命令返回后立即可用。之后的查询将能返回这些文档。
搜索索引
使用 FT.SEARCH
命令在索引中搜索 JSON 文档。你可以按 SCHEMA
中定义的任何属性进行搜索。
例如,查询名称中包含 “earbuds” 的商品:
127.0.0.1:6379> FT.SEARCH itemIdx '@name:(earbuds)'
查询描述中包含 “bluetooth” 和 “headphones” 的所有商品:
127.0.0.1:6379> FT.SEARCH itemIdx '@description:(bluetooth headphones)'
查询价格小于 70 的蓝牙耳机:
127.0.0.1:6379> FT.SEARCH itemIdx '@description:(bluetooth headphones) @price:[0 70]'
查询与向量 [1.0, 1.0, 1.0, 1.0]
最相似的蓝牙耳机:
127.0.0.1:6379> FT.SEARCH itemIdx '@description:(bluetooth headphones)=>[KNN 2 @embedding $blob]' PARAMS 2 blob \x01\x01\x01\x01 DIALECT 2
更多查询语法,请参阅 查询语法。
将 JSON 数组索引为 TAG
在索引多值字段时,可以将 JSON 数组索引为 TAG。数组中的每个值都会被索引,且这些值必须是标量(字符串或布尔值)。
在创建索引时,使用 JSONPath 通配符运算符指定多值字段:
127.0.0.1:6379> FT.CREATE itemIdx2 ON JSON PREFIX 1 item: SCHEMA $.colors.* AS colors TAG $.name AS name TEXT $.description AS description TEXT
查询颜色为银色的耳机:
127.0.0.1:6379> FT.SEARCH itemIdx2 "@colors:{silver} (@name:(headphones)|@description:(headphones))"
将 JSON 数组索引为 NUMERIC
从 RediSearch 2.6.1 开始,可以将 JSON 数组中的数值索引为 NUMERIC 并进行搜索。
添加商品的最大音量级别:
127.0.0.1:6379> JSON.SET item:1 $ '{"max_level":[60,70,80,90,100]}'
127.0.0.1:6379> FT.CREATE itemIdx4 ON JSON PREFIX 1 item: SCHEMA $.max_level AS dB NUMERIC
查询最大音量在 70 到 80 之间的耳机:
127.0.0.1:6379> FT.SEARCH itemIdx4 '@dB:[70 80]'
限制
JSONPath 返回多个数值时的处理
- 数值会被索引
null
值会被跳过- 任何其他类型的值都会导致索引失败
将 JSON 数组索引为 GEO 和 GEOSHAPE
你可以使用 GEO
和 GEOSHAPE
字段来存储地理空间数据,例如地理位置和几何形状。请参阅 地理空间索引 了解如何使用这些模式类型,并查看 地理空间 参考页面,了解其格式和用法。
将 JSON 数组索引为 VECTOR
从 RediSearch 2.6.0 开始,你可以将指向数值数组的 JSONPath 索引为 VECTOR
类型。
例如,假设你的 JSON 数据中包含产品图片的向量嵌入数组。在创建索引时,通过 SCHEMA
定义 JSONPath 为 $.embedding
:
127.0.0.1:6379> FT.CREATE itemIdx5 ON JSON PREFIX 1 item: SCHEMA $.embedding AS embedding VECTOR FLAT 6 DIM 4 DISTANCE_METRIC L2 TYPE FLOAT32
OK
127.0.0.1:6379> JSON.SET item:1 $ '{"name":"Noise-cancelling Bluetooth headphones","description":"Wireless Bluetooth headphones with noise-cancelling technology","price":99.98,"stock":25,"colors":["black","silver"],"embedding":[0.87,-0.15,0.55,0.03]}'
OK
127.0.0.1:6379> JSON.SET item:2 $ '{"name":"Wireless earbuds","description":"Wireless Bluetooth in-ear headphones","price":64.99,"stock":17,"colors":["black","white"],"embedding":[-0.7,-0.51,0.88,0.14]}'
OK
现在,你可以通过 KNN 查询搜索与图片嵌入向量最相似的耳机。(注意:向量查询在方言 2 中受支持)
127.0.0.1:6379> FT.SEARCH itemIdx5 '*=>[KNN 2 @embedding $blob AS dist]' SORTBY dist PARAMS 2 blob \x01\x01\x01\x01 DIALECT 2
1) (integer) 2
2) "item:1"
3) 1) "dist"
2) "1.08280003071"
3) "$"
4) "{\"name\":\"Noise-cancelling Bluetooth headphones\",\"description\":\"Wireless Bluetooth headphones with noise-cancelling technology\",\"price\":99.98,\"stock\":25,\"colors\":[\"black\",\"silver\"],\"embedding\":[0.87,-0.15,0.55,0.03]}"
4) "item:2"
5) 1) "dist"
2) "1.54409992695"
3) "$"
4) "{\"name\":\"Wireless earbuds\",\"description\":\"Wireless Bluetooth in-ear headphones\",\"price\":64.99,\"stock\":17,\"colors\":[\"black\",\"white\"],\"embedding\":[-0.7,-0.51,0.88,0.14]}"
索引多个数值数组为 VECTOR
如果你想将多个数值数组索引为 VECTOR
,可以使用 JSONPath 通配符、过滤器、联合、数组切片或递归下降运算符。
假设你的 JSON 数据中包含多个图片的嵌入向量数组。在创建索引时,使用 $.embeddings[*]
:
127.0.0.1:6379> FT.CREATE itemIdx5 ON JSON PREFIX 1 item: SCHEMA $.embeddings[*] AS embeddings VECTOR FLAT 6 DIM 4 DISTANCE_METRIC L2 TYPE FLOAT32
OK
127.0.0.1:6379> JSON.SET item:1 $ '{"name":"Noise-cancelling Bluetooth headphones","description":"Wireless Bluetooth headphones with noise-cancelling technology","price":99.98,"stock":25,"colors":["black","silver"],"embeddings":[[0.87,-0.15,0.55,0.03]]}'
OK
127.0.0.1:6379> JSON.SET item:2 $ '{"name":"Wireless earbuds","description":"Wireless Bluetooth in-ear headphones","price":64.99,"stock":17,"colors":["black","white"],"embeddings":[[-0.7,-0.51,0.88,0.14],[-0.8,-0.15,0.33,-0.01]]}'
OK
你可以使用 KNN 查询搜索最相似的耳机:
127.0.0.1:6379> FT.SEARCH itemIdx5 '*=>[KNN 2 @embeddings $blob AS dist]' SORTBY dist PARAMS 2 blob \x01\x01\x01\x01 DIALECT 2
1) (integer) 2
2) "item:2"
3) 1) "dist"
2) "0.771500051022"
3) "$"
4) "{\"name\":\"Wireless earbuds\",\"description\":\"Wireless Bluetooth in-ear headphones\",\"price\":64.99,\"stock\":17,\"colors\":[\"black\",\"white\"],\"embeddings\":[[-0.7,-0.51,0.88,0.14],[-0.8,-0.15,0.33,-0.01]]}"
4) "item:1"
5) 1) "dist"
2) "1.08280003071"
3) "$"
4) "{\"name\":\"Noise-cancelling Bluetooth headphones\",\"description\":\"Wireless Bluetooth headphones with noise-cancelling technology\",\"price\":99.98,\"stock\":25,\"colors\":[\"black\",\"silver\"],\"embeddings\":[[0.87,-0.15,0.55,0.03]]}"
⚠️ 注意:
0.771500051022
是查询向量与[-0.8,-0.15,0.33,-0.01]
之间的 L2 距离,小于与[-0.7,-0.51,0.88,0.14]
的距离,因此返回了第二个向量。
更多向量相似性查询语法,请参阅 向量字段。
索引 JSON 对象
你无法直接索引 JSON 对象。如果 JSONPath 表达式返回对象,该对象将被忽略。
为了索引 JSON 对象中的内容,你需要将对象内的每个元素单独映射为独立属性。
例如,索引 connection
对象中的字段:
127.0.0.1:6379> FT.CREATE itemIdx3 ON JSON SCHEMA $.connection.wireless AS wireless TAG $.connection.type AS connectionType TEXT
"OK"
搜索 wireless
为 true
的商品:
127.0.0.1:6379> FT.SEARCH itemIdx3 '@wireless:{true}'
搜索连接类型为 Bluetooth
的商品:
127.0.0.1:6379> FT.SEARCH itemIdx3 '@connectionType:(bluetooth)'