Valkey: 搜索与 JSON
使用 Valkey 搜索模块存储和查询 JSON 文档
👋 欢迎查阅 Stackhero 文档!
Stackhero 提供即开即用的 Valkey 云端 解决方案,带来多项优势,包括:
- 集成
Valkey AdminWeb 管理界面。- 无限制的消息大小与传输。
- 一键完成升级,操作便捷。
- 基于专属私有基础设施,实现卓越性能与强大安全性。
节省时间,简化您的工作流程:只需 5 分钟即可体验 Stackhero 的 Valkey 云托管 方案!
您在 Stackhero 上的 Valkey 实例内置了由 Valkey 项目维护的核心模块。这些模块让 Valkey 不仅仅是一个缓存:您可以原生存储 JSON 文档,对数据建立索引,并执行标签、数值、文本和向量查询,无需额外管理独立数据库。
目前提供三大模块,全部包含在您的套餐中,并采用与 Valkey 相同的宽松 BSD 3-Clause 许可协议:
- JSON(
JSON.*命令):支持 JSONPath,存储和更新结构化 JSON 文档。您可以直接读取或修改单个字段,无需为小变更重写整个文档。 - Search(
FT.*命令):支持二级索引、标签、数值、全文检索及向量相似度查询。 - Bloom(
BF.*命令):利用 Bloom filter 高效判断“大数据集中某项是否已出现”,极大节省内存。
启用模块
模块默认处于关闭状态,因此您的现有服务会保持当前行为,直到您手动启用。
- 在 Stackhero 控制台 打开您的服务。
- 进入服务配置页面。
- 在 Modules(模块)部分,选择您要启用的模块。
- 保存更改。
Valkey 会重启以加载所选模块,通常只需几秒钟。
如果您已通过某个模块(如 JSON 文档或 Bloom filter)存储了数据,请务必保持该模块处于启用状态。Valkey 无法在缺少创建数据的模块时读取这些数据。禁用该模块将导致服务无法成功重启。
您可以随时检查当前已加载的模块:
valkey-cli -u "rediss://default:<yourPassword>@<XXXXXX>.stackhero-network.com:<PORT_TLS>" MODULE LIST
存储 JSON 文档
您可以直接以 JSON 格式原生存储结构化文档,无需序列化为字符串:
JSON.SET product:1 $ '{"name":"Espresso machine","brand":"Bianca","price":459,"stock":12}'
读取或更新单个字段操作快速、原子且由服务端处理:
JSON.GET product:1 $.price
# "[459]"
JSON.NUMINCRBY product:1 $.stock -1
# "[11]"
这种方式无需每次更新都在应用端获取并解析整个文档。例如,减少库存计数器现在只需一次原子操作,无需担心并发冲突或额外代码。
JSON.* 命令集与 RedisJSON 的 API 保持一致,因此大多数 Valkey 和 Redis 客户端无需修改即可兼容。
索引与搜索
只需创建一次索引,Valkey 会自动为所有匹配前缀的 key 保持索引最新,甚至包括索引创建前已存在的 key:
FT.CREATE productsIndex
ON HASH
PREFIX 1 product:
SCHEMA
name TEXT
brand TAG
price NUMERIC
您可以通过强大的搜索命令查询已索引数据:
# 标签精确匹配
FT.SEARCH productsIndex "@brand:{Bianca}"
# 数值范围
FT.SEARCH productsIndex "@price:[0 500]"
# 组合查询
FT.SEARCH productsIndex "@brand:{Bianca} @price:[0 500]"
# 按名称全文检索
FT.SEARCH productsIndex "espresso"
您还可以使用 FT.AGGREGATE 在同一索引上进行聚合分析。FT.INFO 命令可用于检查索引状态,包括后台索引任务的进度。
JSON 文档同样支持索引。当启用 JSON 模块后,您可以在 schema 中使用 ON JSON 及 JSONPath 表达式。
示例:在 Node.js 中使用 Valkey 搜索
由于 Valkey 与 Redis 协议兼容,任何 Redis 客户端都可直接使用。以下示例适用于官方 node-redis 客户端:
import { createClient, SCHEMA_FIELD_TYPE } from 'redis';
const client = createClient({ url: process.env.STACKHERO_VALKEY_URL_TLS });
await client.connect();
// 启动时仅需创建一次索引
try {
await client.ft.create(
'productsIndex',
{
name: SCHEMA_FIELD_TYPE.TEXT,
brand: SCHEMA_FIELD_TYPE.TAG,
price: SCHEMA_FIELD_TYPE.NUMERIC
},
{ ON: 'HASH', PREFIX: 'product:' }
);
} catch (error) {
if (!error.message.includes('Index already exists')) {
throw error;
}
}
await client.hSet('product:1', { name: 'Espresso machine', brand: 'Bianca', price: '459' });
const results = await client.ft.search('productsIndex', '@brand:{Bianca} @price:[0 500]');
console.log(results.total, results.documents);
await client.quit();
示例:在 Python 中使用 Valkey 搜索
您可以通过 redis-py 客户端 调用 Valkey 搜索功能:
import os
import redis
from redis.commands.search.field import TextField, TagField, NumericField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
r = redis.from_url(os.environ['STACKHERO_VALKEY_URL_TLS'], decode_responses=True)
# 启动时仅需创建一次索引
try:
r.ft('productsIndex').create_index(
(TextField('name'), TagField('brand'), NumericField('price')),
definition=IndexDefinition(prefix=['product:'], index_type=IndexType.HASH),
)
except redis.ResponseError as error:
if 'Index already exists' not in str(error):
raise
r.hset('product:1', mapping={'name': 'Espresso machine', 'brand': 'Bianca', 'price': 459})
results = r.ft('productsIndex').search(Query('@brand:{Bianca} @price:[0 500]'))
print(results.total, results.docs)
温馨提示
- 搜索模块提供了一组专注的命令:
FT.CREATE、FT.SEARCH、FT.AGGREGATE、FT.INFO、FT.DROPINDEX和FT._LIST。这些命令高效支持标签、数值、文本和向量查询。如果您的应用需要更高级的全文检索功能(如拼写检查、同义词或建议词典),可参考 Redis 查询引擎 获取更丰富的能力。 - 索引按数据库隔离,并在每个数据库内生效。 例如,在数据库 3 创建的索引,仅能在数据库 3 内被查询和访问。这是 Valkey 相较于 Redis 数据库选择 的扩展,后者仅支持在数据库 0 上建立索引。
- 索引占用您的套餐内存,与数据一样。您可以在 Prometheus 指标 中监控
used_memory,以便在构建索引后查看内存占用。 - 对现有 key 的索引在后台异步进行。 执行
FT.CREATE后,搜索结果可能在几秒内不完整,待索引构建完成后即可正常使用。 - 所有模块命令均已启用。 您的服务可使用所有模块的全部命令,无任何限制。
如需探索向量相似度、语义搜索或检索增强生成(RAG),请参阅 向量搜索指南。