Redisearch通配符前缀索引失效求助:index_test_wildcard无法匹配数据
问题:Redis通配符前缀索引无法匹配键值
我正在排查为何index_test索引可正常工作,但index_test_wildcard索引无法匹配对应数据。后者虽尝试用通配符语法创建索引,却无法匹配函数内生成的doc:1:data:1记录。
相关代码
from redis.commands.json.path import Path from redis.commands.search.field import TagField, TextField, NumericField from redis.commands.search.indexDefinition import IndexDefinition, IndexType from redis import Redis def initialise_redis(): # 假设此处为Redis客户端初始化逻辑 return Redis(host='localhost', port=6379, db=0) def index_test(r: Redis): r.json().set('doc:data:1', Path.root_path(), { "title": "Example Title", "views": 150, "tags": ["tutorial", "redis"] }) schema = [ TextField('$.title', as_name='title', weight=5.0), NumericField('$.views', as_name='views'), TagField('$.tags', as_name='tags', separator=',') ] definition = IndexDefinition(prefix=['doc:data:'], index_type=IndexType.JSON) r.ft("index_test").create_index(schema, definition=definition) def index_test_wildcard(r: Redis): r.json().set('doc:1:data:1', Path.root_path(), { "title": "Example Title", "views": 150, "tags": ["tutorial", "redis"] }) schema = [ TextField('$.title', as_name='title', weight=5.0), NumericField('$.views', as_name='views'), TagField('$.tags', as_name='tags', separator=',') ] definition = IndexDefinition(prefix=['doc:*:data:'], index_type=IndexType.JSON) r.ft("index_test_wildcard").create_index(schema, definition=definition) redis_client = initialise_redis() index_test(redis_client) index_test_wildcard(redis_client)
查询结果
127.0.0.1:6379> FT.SEARCH index_test * 1) (integer) 1 2) "doc:data:1" 3) 1) "$" 2) "{\"title\":\"Example Title\",\"views\":150,\"tags\":[\"tutorial\",\"redis\"]}" 127.0.0.1:6379> FT.SEARCH index_test_wildcard * 1) (integer) 0
问题原因
Redis Search的索引前缀通配符仅支持后缀通配——*只能放在前缀字符串的末尾,不能出现在中间。你使用的doc:*:data:属于中间插入通配符的格式,不符合Redis Search的前缀匹配规则,因此无法匹配doc:1:data:1这个键。
解决方法
方案1:调整键命名规则(推荐)
将键格式改为固定前缀+可变后缀,比如把doc:1:data:1改为doc:data:1:1,再将索引前缀设为doc:data:*,即可匹配所有以doc:data:开头的键:
def index_test_wildcard(r: Redis): # 修改键名格式 r.json().set('doc:data:1:1', Path.root_path(), { "title": "Example Title", "views": 150, "tags": ["tutorial", "redis"] }) schema = [ TextField('$.title', as_name='title', weight=5.0), NumericField('$.views', as_name='views'), TagField('$.tags', as_name='tags', separator=',') ] # 前缀改为固定开头+末尾通配符 definition = IndexDefinition(prefix=['doc:data:*'], index_type=IndexType.JSON) r.ft("index_test_wildcard").create_index(schema, definition=definition)
方案2:添加Tag字段存储分段信息
如果无法修改键名,可在JSON数据中添加字段存储键的可变分段(比如doc:和:data:之间的部分),创建Tag索引后通过过滤该字段匹配目标数据:
def index_test_wildcard(r: Redis): r.json().set('doc:1:data:1', Path.root_path(), { "title": "Example Title", "views": 150, "tags": ["tutorial", "redis"], "key_segment": "1" # 新增存储可变分段的字段 }) schema = [ TextField('$.title', as_name='title', weight=5.0), NumericField('$.views', as_name='views'), TagField('$.tags', as_name='tags', separator=','), TagField('$.key_segment', as_name='key_segment') # 为该字段创建Tag索引 ] # 前缀设为键的固定开头部分 definition = IndexDefinition(prefix=['doc:'], index_type=IndexType.JSON) r.ft("index_test_wildcard").create_index(schema, definition=definition)
查询时用FILTER子句过滤:
FT.SEARCH index_test_wildcard * FILTER key_segment == "1"
方案3:查询时直接匹配键名(性能较低)
若不想修改数据或索引,可通过__key内置字段匹配键名通配符,但该方式性能不如前缀索引,仅适合小数据量场景:
FT.SEARCH index_test_wildcard * RETURN 1 $ WHERE __key LIKE "doc:*:data:*"
内容的提问来源于stack exchange,提问作者Harry Stuart
相关产品推荐
相关产品推荐

