springboot milvus search向量相似度查询 踩坑使用经验

发布于:2025-03-25 ⋅ 阅读:(22) ⋅ 点赞:(0)

1.前提提要:java的pom 版本为:2.4.9 milvus 版本是:2.4.13-hotfix
2.先来工具类方法

    /**
     * 向量搜索
     * @param client
     * @param query
     * @return
     */
    public SearchResp search(@NonNull MilvusClientV2 client, @NonNull VectorCondition query) {
        final List<BaseVector> data = query.getData();
        if (CollectionUtils.isEmpty(data)) {
            return null;
        }
        SearchReq.SearchReqBuilder searchReqBuilder = SearchReq.builder().collectionName(query.getCollectionName())
                .data(data);
        if (query.getTopK() > 0) {
            searchReqBuilder.topK(query.getTopK());
        }
        if (!StringUtils.isEmpty(query.getAnnsField())) {
            searchReqBuilder.annsField(query.getAnnsField());
        }
        if (!CollectionUtils.isEmpty(query.getSearchParams())) {
            searchReqBuilder.searchParams(query.getSearchParams());
        }
        if (!CollectionUtils.isEmpty(query.getPartitionNames())) {
            searchReqBuilder.partitionNames(query.getPartitionNames());
        }
        if (!CollectionUtils.isEmpty(query.getOutputFields())) {
            searchReqBuilder.outputFields(query.getOutputFields());
        } else {
            searchReqBuilder.outputFields(Collections.singletonList("*"));
        }
        if (StringUtils.isNotBlank(query.getFilter())) {
            searchReqBuilder.filter(query.getFilter());
        }
        final SearchResp search = client.search(searchReqBuilder.build());
        return search;
    }

3.包装的请求条件

@Data
@Builder
public class VectorCondition {
    //现有集合的名称。
    @NonNull
    String collectionName;
    String partitionName;
    //分区名称列表。
    List<String> partitionNames;
    //返回每个实体中包含的字段名称列表。
    //该值默认为None。如果未指定,则选择集合中的所有字段作为输出字段。
    List<String> outputFields;
    //要查询的实体的 ID。
    List<Object> ids;
    //用于筛选匹配实体的标量筛选条件。
    //您可以将此参数设置为空字符串以跳过标量过滤。要构建标量过滤条件,请参阅布尔表达式规则。
    String filter;
    //目标集合的一致性级别。
    //该值默认为创建当前集合时指定的值,选项包括Strong ( 0 )、Bounded ( 1 )、Session ( 2 ) 和Finally ( 3 )。
    ConsistencyLevel consistencyLevel;
    //查询结果中要跳过的记录数。
    //您可以结合使用此参数来limit启用分页。
    //该值的总和limit应小于 16,384。
    long offset;
    //查询结果中返回的记录数。
    //您可以结合使用此参数来offset启用分页。
    //该值的总和offset应小于 16,384。
    long limit;
    //矢量字段的名称,当有多个矢量字段时使用。如果只存在一个矢量字段,我们将直接使用它
    String annsField;
    //搜索结果中返回的记录数。此参数使用与参数相同的语法limit,因此您只应设置其中一个。
    //您可以结合使用此参数来offset启用分页。
    //该值的总和offset应小于 16,384。
    int topK;
    //向量嵌入的列表。
    //Milvus 搜索与指定的向量嵌入最相似的向量嵌入。
    List<BaseVector> data;
    //插入的向量。
    List<JsonObject> dataJson;
    //Milvus 将计算出的距离四舍五入到的小数位数。
    //该值默认为-1,表示 Milvus 跳过对计算距离进行四舍五入并返回原始值。
    int roundDecimal;
    //此操作特有的参数设置。
    //metric_type (字符串)
    //应用于此操作的度量类型。这应该与索引上面指定的矢量字段时使用的类型相同。
    //可能的值是L2、IP和COSINE。
    //半径(浮点数)
    //确定最小相似度的阈值,设置metric_type为时L2,确保该值大于range_filter的值,否则,该值应小于range_filter的值。
    //范围过滤器(浮点数)
    //将搜索范围缩小到特定相似度范围内的向量。设置metric_type为IP或 时COSINE,请确保此值大于 radius 。否则,此值应小于radius。
    Map<String, Object> searchParams;
    //是否在相似性搜索期间忽略增长的片段。
    boolean ignoreGrowing;
    //设置字段名称以对结果进行分组。
    String groupByFieldName;
}


4.向量数据的转换

   final List<Object> data;
     // 使用Stream API进行转换
        List<Float> floatList = data.stream()
                .map(obj -> obj instanceof Double ? ((Double) obj).floatValue() : (Float) obj) // 转换为Float
                .collect(Collectors.toList()); // 收集结果到新的列表

        List<BaseVector> requestData = new ArrayList<>();
        final FloatVec baseVector = new FloatVec(floatList);
        requestData.add(baseVector);
        Map<String, Object> params = new HashMap<>();
        params.put("nprobe", "1024");
        params.put("radius", 0.5f);
        final VectorCondition vector = VectorCondition.builder()
                .collectionName("xxxxx")
                .annsField("vector")
                .topK(1)
                .searchParams(params)
                .data(requestData)
                .build();
        SearchResp searchR = (SearchResp) milvusUtil.execute("search", vector);
        final List<List<SearchResp.SearchResult>> searchResults = searchR.getSearchResults();
        for (List<SearchResp.SearchResult> results : searchResults) {
            for (SearchResp.SearchResult result : results) {
                System.out.printf("ID: %s, Score: %f, %s\n", result.getId(), result.getScore(), result.getEntity().toString());
            }
        }

使用线程池获取MilvusClient连接对象,具体可看之前的博客

            case MilvusUtil.SEARCH:
                result = this.search(milvusClientPool.getClient(SEARCH), vectorCondition);
                break;

报错
Caused by: java.lang.ClassNotFoundException: com.google.gson.ToNumberPolicy
原因:java.lang.ClassNotFoundException:com.google.gson.ToNumberPolicy
和上次使用的经验一样,肯定没有最新的包,果然,换成最新的谷歌的包问题解决

        <!--milvus-->
        <dependency>
            <groupId>io.milvus</groupId>
            <artifactId>milvus-sdk-java</artifactId>
            <version>2.4.9</version>
            <exclusions>
                <exclusion>
                    <artifactId>guava</artifactId>
                    <groupId>com.google.guava</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>gson</artifactId>
                    <groupId>com.google.gson</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>26.0-jre</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.11.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.9</version> <!-- 或者更新版本 -->
        </dependency>

在这里插入图片描述