索引

如何索引和搜索 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 索引的语法:

  1. FT.CREATE {index_name} ON JSON SCHEMA {json_path} AS {attribute} {type}

例如,以下命令为表示库存商品的 JSON 文档创建索引,索引了名称、描述、价格和图片的向量嵌入:

  1. 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.SETJSON.ARRAPPEND,来创建或修改 JSON 文档。

以下是表示库存商品的两个 JSON 文档示例:

商品 1:

  1. {
  2. "name": "Noise-cancelling Bluetooth headphones",
  3. "description": "Wireless Bluetooth headphones with noise-cancelling technology",
  4. "connection": {
  5. "wireless": true,
  6. "type": "Bluetooth"
  7. },
  8. "price": 99.98,
  9. "stock": 25,
  10. "colors": ["black", "silver"],
  11. "embedding": [0.87, -0.15, 0.55, 0.03]
  12. }

商品 2:

  1. {
  2. "name": "Wireless earbuds",
  3. "description": "Wireless Bluetooth in-ear headphones",
  4. "connection": {
  5. "wireless": true,
  6. "type": "Bluetooth"
  7. },
  8. "price": 64.99,
  9. "stock": 17,
  10. "colors": ["black", "white"],
  11. "embedding": [-0.7, -0.51, 0.88, 0.14]
  12. }

使用 JSON.SET 将它们存储到数据库:

  1. 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]}'
  2. "OK"
  3. 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]}'
  4. "OK"

由于在这种情况下索引是同步的,所以文档会在 [JSON.SET] 命令返回后立即可用。之后的查询将能返回这些文档。

搜索索引

使用 FT.SEARCH 命令在索引中搜索 JSON 文档。你可以按 SCHEMA 中定义的任何属性进行搜索。

例如,查询名称中包含 “earbuds” 的商品:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx '@name:(earbuds)'

查询描述中包含 “bluetooth” 和 “headphones” 的所有商品:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx '@description:(bluetooth headphones)'

查询价格小于 70 的蓝牙耳机:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx '@description:(bluetooth headphones) @price:[0 70]'

查询与向量 [1.0, 1.0, 1.0, 1.0] 最相似的蓝牙耳机:

  1. 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 通配符运算符指定多值字段:

  1. 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

查询颜色为银色的耳机:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx2 "@colors:{silver} (@name:(headphones)|@description:(headphones))"

将 JSON 数组索引为 NUMERIC

从 RediSearch 2.6.1 开始,可以将 JSON 数组中的数值索引为 NUMERIC 并进行搜索。

添加商品的最大音量级别:

  1. 127.0.0.1:6379> JSON.SET item:1 $ '{"max_level":[60,70,80,90,100]}'
  2. 127.0.0.1:6379> FT.CREATE itemIdx4 ON JSON PREFIX 1 item: SCHEMA $.max_level AS dB NUMERIC

查询最大音量在 70 到 80 之间的耳机:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx4 '@dB:[70 80]'

限制

JSONPath 返回多个数值时的处理

  • 数值会被索引
  • null 值会被跳过
  • 任何其他类型的值都会导致索引失败

将 JSON 数组索引为 GEO 和 GEOSHAPE

你可以使用 GEOGEOSHAPE 字段来存储地理空间数据,例如地理位置和几何形状。请参阅 地理空间索引 了解如何使用这些模式类型,并查看 地理空间 参考页面,了解其格式和用法。

将 JSON 数组索引为 VECTOR

从 RediSearch 2.6.0 开始,你可以将指向数值数组的 JSONPath 索引为 VECTOR 类型。

例如,假设你的 JSON 数据中包含产品图片的向量嵌入数组。在创建索引时,通过 SCHEMA 定义 JSONPath 为 $.embedding

  1. 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
  2. OK
  3. 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]}'
  4. OK
  5. 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]}'
  6. OK

现在,你可以通过 KNN 查询搜索与图片嵌入向量最相似的耳机。(注意:向量查询在方言 2 中受支持)

  1. 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
  2. 1) (integer) 2
  3. 2) "item:1"
  4. 3) 1) "dist"
  5. 2) "1.08280003071"
  6. 3) "$"
  7. 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]}"
  8. 4) "item:2"
  9. 5) 1) "dist"
  10. 2) "1.54409992695"
  11. 3) "$"
  12. 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[*]

  1. 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
  2. OK
  3. 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]]}'
  4. OK
  5. 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]]}'
  6. OK

你可以使用 KNN 查询搜索最相似的耳机:

  1. 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
  2. 1) (integer) 2
  3. 2) "item:2"
  4. 3) 1) "dist"
  5. 2) "0.771500051022"
  6. 3) "$"
  7. 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]]}"
  8. 4) "item:1"
  9. 5) 1) "dist"
  10. 2) "1.08280003071"
  11. 3) "$"
  12. 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 对象中的字段:

  1. 127.0.0.1:6379> FT.CREATE itemIdx3 ON JSON SCHEMA $.connection.wireless AS wireless TAG $.connection.type AS connectionType TEXT
  2. "OK"

搜索 wirelesstrue 的商品:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx3 '@wireless:{true}'

搜索连接类型为 Bluetooth 的商品:

  1. 127.0.0.1:6379> FT.SEARCH itemIdx3 '@connectionType:(bluetooth)'