依赖:
milvus-sdk-java 2.4.x / 2.5.x(Milvus 2.x 服务端通用)
Maven
<dependency><groupId>io.milvus</groupId><artifactId>milvus-sdk-java</artifactId><version>2.5.0</version></dependency>场景说明:
- 向量字段:
embedding做语义相似度检索- 多个标量字段通过
expr过滤(category、source、create_time)- Java SDK Search API 核心:
searchParam.withExpr("多字段条件表达式")
集合Schema(对应代码示例)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT64(主键) | 文档ID |
| embedding | FLOAT_VECTOR | 向量,dim=1024 |
| category | VARCHAR | 文档分类 |
| source | VARCHAR | 来源 |
| create_time | INT64 | 创建时间戳 |
| content | VARCHAR | 文档正文 |
完整Java示例代码
importio.milvus.client.MilvusServiceClient;importio.milvus.common.clientenum.ConsistencyLevelEnum;importio.milvus.param.ConnectParam;importio.milvus.param.R;importio.milvus.param.dml.SearchParam;importio.milvus.response.SearchResultsWrapper;importio.milvus.grpc.DataType;importjava.util.ArrayList;importjava.util.List;publicclassMilvusMultiFieldSearchDemo{publicstaticvoidmain(String[]args){// 1. 创建Milvus客户端ConnectParamconnectParam=ConnectParam.newBuilder().withHost("127.0.0.1").withPort(19530)// 开启鉴权时添加// .withUsername("root")// .withPassword("xxxx").build();MilvusServiceClientclient=newMilvusServiceClient(connectParam);StringcollectionName="knowledge_base";// 2. 组装查询向量(业务中替换为文本向量化后的float数组)List<Float>queryVector=newArrayList<>();for(inti=0;i<1024;i++){queryVector.add(0.01f);}List<List<Float>>vectors=newArrayList<>();vectors.add(queryVector);// ======================// 【重点】多标量字段过滤表达式 expr// 语法规则:字符串使用双引号,and / or 组合多个条件// ======================Stringexpr="category == \"电力文档\" "+"and source in [\"内部手册\", \"规范文件\"] "+"and create_time > 1700000000";// 3. 构建Search参数SearchParamsearchParam=SearchParam.newBuilder().withCollectionName(collectionName).withVectors(vectors).withVectorFieldName("embedding")// 向量字段.withTopK(10)// 返回top10.withExpr(expr)// 多字段过滤条件.addOutField("id").addOutField("category").addOutField("source").addOutField("create_time").addOutField("content").withMetricType("COSINE").withParams("{\"nprobe\":16}").withConsistencyLevel(ConsistencyLevelEnum.EVENTUALLY).build();// 4. 执行检索R<SearchResultsWrapper>response=client.search(searchParam);if(!response.isSuccess()){System.err.println("检索失败: "+response.getException().getMessage());client.close();return;}SearchResultsWrapperresultsWrapper=response.getData();// 5. 解析结果List<SearchResultsWrapper.IDScore>hitList=resultsWrapper.getIDScore(0);for(SearchResultsWrapper.IDScorehit:hitList){longdocId=hit.getLongID();floatscore=hit.getScore();// 获取标量字段Stringcategory=resultsWrapper.getFieldData("category",0).getAsString(hit.getIndex());Stringsource=resultsWrapper.getFieldData("source",0).getAsString(hit.getIndex());Stringcontent=resultsWrapper.getFieldData("content",0).getAsString(hit.getIndex());LongcreateTime=resultsWrapper.getFieldData("create_time",0).getAsLong(hit.getIndex());System.out.printf("score=%.4f, id=%d%n",score,docId);System.out.printf("category=%s, source=%s, time=%d%n",category,source,createTime);System.out.println("content:"+content);System.out.println("------------------------");}client.close();}}常用expr条件示例(直接复制修改)
// 示例1:and 多条件Stringexpr1="category == \"防洪\" and create_time > 1700000000";// 示例2:or 或条件Stringexpr2="source == \"内部手册\" or source == \"行业标准\"";// 示例3:模糊匹配 Milvus >=2.4 支持 likeStringexpr3="category == \"业扩报装\" and content like \"%营商环境%\"";// 示例4:not 取反Stringexpr4="category == \"应急管理\" and not source == \"草稿\"";重要知识点(Java开发常见问题)
1. 多个向量字段如何检索?
Milvus不支持一次search同时检索多个向量列(无法同时指定多个vectorFieldName)
解决方案:
- 分别执行两次search(标题向量、正文向量)
- 在Java代码内实现RRF倒数融合 / 加权分数融合合并结果
伪代码参考:
// 检索标题向量SearchParamparamTitle=buildSearch("title_emb",queryTitleVec,expr);// 检索正文向量SearchParamparamContent=buildSearch("embedding",queryContentVec,expr);// 拿到两组结果,自定义融合排序2. 只想查询标量字段(不做向量检索)→ 使用QueryParam
importio.milvus.param.dml.QueryParam;QueryParamqueryParam=QueryParam.newBuilder().withCollectionName("knowledge_base").withExpr("category == \"电力文档\" and create_time > 1700000000").addOutField("id").addOutField("content").build();R<SearchResultsWrapper>queryResp=client.query(queryParam);3. 性能优化建议
- 经常过滤的标量字段建立标量索引
// Java创建标量索引示例(VARCHAR/INT字段)IndexParamindexParam=IndexParam.newBuilder().withCollectionName(collectionName).withFieldName("category").withIndexType("TREE").build();client.createIndex(indexParam);- 查询时使用
ConsistencyLevelEnum.EVENTUALLY提升查询速度 - 不要写过于复杂的like模糊查询,海量数据很慢
4. 避坑清单
- expr 字符串必须双引号
"文本",不要单引号 - expr不要直接拼接用户输入 →SQL注入风险!一定要参数化处理
生产建议:封装工具类,使用值替换,禁止字符串直接拼接用户原始文本
- 集合没有执行load()直接查询会报错
- 向量维度和建表dim不一致抛出异常