前言

最近公司的项目有一个milvus混合检索的功能设计,在添加过滤条件,检索目标向量时,返回的结果为空,即没有检索到任何数据,但是从Attu客户端检查,满足过滤条件是有entity的,这篇博客主要复盘这次典型的混合查询失败的问题原因,希望通过这次分享,帮助大家更深入地理解Milvus的检索机制,避免踩坑。

问题排查

  1. 下面这段程序是一个经典的milvus的混合检索java程序,只检索出满足过滤条件的向量实体

    			 String filterExpr = String.format("manufacturer in ['%s']", placeholders); 
            SearchReq searchReq = SearchReq.builder()
                    .databaseName(CommonConstant.MATERIAL_MILVUS_DATABASE)
                    .collectionName(CommonConstant.MATERIAL_NAME_MATCH_COLLECTION)
                    .data(Collections.singletonList(floatVec))
                    .topK(CommonConstant.MILVUS_RETURN_NUM)
                    .filter(filterExpr) //设置过滤条件
                    .outputFields(returnFields)
                    .searchParams(searchParamsMap)
                    .build();
    
  2. 但是这段程序在检索数据时,大多数数据是可以正确检索到,有些数据检索不到,且检索失败的数据,通过Attu客户端是可以看到满足过滤条件的,是有entity存在的。

  3. 因此我的初步排查方向包括:
    数据是否存在:确认数据已成功插入并建立了索引。
    过滤条件是否正确:检查过滤表达式语法无误,且集合中确实存在满足该标量条件的实体。
    连接与集合状态:确认连接正常,集合已正确加载(load())。

  4. 进一步,还有一个可能,milvus只会检索出相似度大于某个阈值的数据,但是程序中并没有指定相似度阈值,查看官网信息,也没有看到有默认阈值的设定,因此,相似度阈值的原因也被排除掉。

  5. 那既然都没有问题,我就在Attu上测试,看看是不是milvus java sdk本身存在漏洞,因此打开attu客户端,在向量检索界面,设置查询失败的过滤条件,随机生成一个embedding进行测试,如图所示,依然查询失败。
    在这里插入图片描述

  6. 但是在数据栏,直接进行标量检索时,是可以检索到数据的,说明是有entity满足过滤条件的,并不是没有数据导致的检索结果为空。
    在这里插入图片描述

  7. 在以上方面均未发现异常后,我开始思考milvus向量检索本身,特别是索引和搜索参数的配置上。当时,为集合的向量字段建立的索引类型为IVF_FLAT,参数为 nlist=512。而在执行搜索时,设置的搜索参数是 nprobe=128,会不会是因为满足过滤条件的所有entity的embedding都是与检索向量相似度过低,并不在最相近的这128个“桶”内,因此,重新设置nprobe参数值,发现是可以检索出数据的,破案。
    在这里插入图片描述

  8. 原因是我第一次使用milvus进行混合检索,疏忽了IVF_FLAT索引类型和过滤条件的 混合检索执行流程,导致刚发现问题时有点蒙。

IVF_FLAT索引检索过程

要理解为何这样设置会导致空结果,我们需要先了解IVF_FLAT索引的大致工作流程

  1. 索引构建(聚类):在构建索引时,Milvus会使用K-Means等算法将集合中的所有向量划分到nlist个聚类中心(桶)中。nlist=512意味着整个向量空间被划分成了512个簇。
  2. 搜索过程:当进行搜索时,对于一个给定的查询向量:
    第一步:粗选桶。系统会计算该查询向量与所有512个聚类中心的距离,并选出距离最近的nprobe个桶。nprobe=128意味着系统只关注与查询向量最相似的128个桶。
    第二步:桶内精搜。系统会在这128个桶内部进行精确的最近邻搜索(比如计算欧氏距离或余弦相似度),并按照相似度排序返回结果
  3. 关键点在于:混合查询中的标量过滤(条件过滤)发生在第二步之后,即先进行向量相似性搜索,再对得到的候选向量进行标量条件过滤,因此,如果符合条件过滤的embedding不在候选相似度排序的范围中,最后就会导致查询不到数据。

总结

本次对Milvus混合查询返回空结果的排查,揭示了深入理解索引和查询参数的重要性。IVF_FLAT索引中的nprobe参数直接控制了搜索的范围,在混合查询场景下,不合理的nprobe设置可能会使满足属性条件的数据因落在搜索范围外而被遗漏。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐