Redis向量搜索大K值无法返回指定数量文档的问题求助
问题
我部署了RedisSearch服务器测试向量相似度搜索,严格遵循《Using Redis as a Vector Database with OpenAI》指南,采用HNSW算法。
测试目标为中等规模数据集(约2000万文档)及大返回量(5000-10000条),因为ElasticSearch在增大k和num_candidates时性能过慢。
为测试Redis VSS性能,我通过list(np.random.rand(1024))生成假嵌入向量并索引2000万文档。当前请求1000条时能稳定返回,但请求5000条及以上时,返回结果为空或数量不足。
我未设置相似度分数阈值,仅需返回指定数量的任意分数文档,如何实现?
搜索代码片段:
def search_redis( redis_client: redis.Redis, user_query: str, index_name: str = INDEX_NAME, vector_field: str = "embedding", return_fields: list = ["id", "user_id", "title", "vector_score"], hybrid_fields = "*", k: int = 100, ): embedded_query = get_fake_embeddings() # 1024 random floats base_query = f'{hybrid_fields}=>[KNN {k} @{vector_field} $vector AS vector_score]' query = ( Query(base_query) .return_fields(*return_fields) .sort_by("vector_score") .paging(0, k) .dialect(2) ) params_dict = {"vector": np.array(embedded_query).astype(dtype=np.float32).tobytes()} results = redis_client.ft(index_name).search(query, params_dict) return results.docs
解决方案
针对大k值(5000+)返回结果不足的问题,可从以下几点调整:
1. 调整HNSW的EF_RUNTIME参数
HNSW算法查询时的EF_RUNTIME参数控制遍历的候选节点数,默认值不足以支撑大k值的召回需求。需在KNN查询中显式设置该参数,确保Redis能检索到足够多的候选结果来满足k的要求。
修改后的KNN查询语句:
base_query = f'{hybrid_fields}=>[KNN {k} @{vector_field} $vector AS vector_score EF_RUNTIME {k * 2}]'
建议将EF_RUNTIME设为k的1.5-3倍(示例用2倍),让Redis查询时遍历更多节点,保证召回足够数量的结果。
2. 取消不必要的排序(按需操作)
如果仅需返回指定数量的文档、不需要按相似度分数排序,可去掉.sort_by("vector_score")。排序操作处理大结果集会增加开销,还可能因排序截断导致结果不足。
3. 检查索引的向量字段配置
创建索引时需确保:
- 向量字段的
DIM设置为1024,与生成的嵌入维度匹配 DISTANCE_METRIC符合需求(默认L2距离即可)- HNSW的
EF_CONSTRUCTION参数建议设为200或更高(针对2000万级数据集),过低会影响查询召回能力
修改后的完整代码
def search_redis( redis_client: redis.Redis, user_query: str, index_name: str = INDEX_NAME, vector_field: str = "embedding", return_fields: list = ["id", "user_id", "title", "vector_score"], hybrid_fields = "*", k: int = 100, ): embedded_query = get_fake_embeddings() # 1024 random floats # 设置EF_RUNTIME为k的2倍,确保足够的候选节点 base_query = f'{hybrid_fields}=>[KNN {k} @{vector_field} $vector AS vector_score EF_RUNTIME {k * 2}]' query = ( Query(base_query) .return_fields(*return_fields) # 不需要按相似度排序则注释掉此行 # .sort_by("vector_score") .paging(0, k) .dialect(2) ) params_dict = {"vector": np.array(embedded_query).astype(dtype=np.float32).tobytes()} results = redis_client.ft(index_name).search(query, params_dict) return results.docs
额外优化建议
- 若k值超过10000,可考虑分批次查询(比如每次查2000条,分5次)再合并结果,避免单次查询内存压力过大
- 确保Redis服务器预留足够内存:2000万条1024维float32向量约占76GB内存,加上其他数据需额外预留空间
内容的提问来源于stack exchange,提问作者ruslaniv
相关产品推荐
相关产品推荐

