You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:23:29