-
最近公司项目遇到一个milvus的技术场景,需要更新Collection的标量字段值,查了一遍官网,发现milvus并不支持直接修改字段值。
-
所以一个替代方案是,先获取collection的所有entities,然后逐条判断当前entity是否需要修改字段值,如果需要,根据ID将这条entity删除,然后重新插入修改后的完整entity。
-
需要注意的是,根据标量查询的entity有size限制,因此,设置的响应返回字段中不能有向量embedding字段,如果这条entity要更新,需要根据查询到的original_text重新生成嵌入向量。
-
值得庆幸的是,milvus提供了这样的API,不需要我们手动删除后再插入,milvus将这两个过程合并在一个API中实现了。
-
这个API就是
Upsert,下面这个图就是Upsert的工作过程,如果Collection中主键id是自动生成的(Auto),那么Milvus就会先自动生成一个主键id,然后整合接收的entity实体插入数据,然后,根据 Upsert 请求中包含的实体主键值执行删除旧数据操作
-
下面是完整java程序
java
@Test
public void clean(){
// 定义返回字段,这里返回A,B还有主键id字段
List<String> outputFields = Arrays.asList("id","A","B");
String queryExpr = "id > 0";
//设置标量查询条件
QueryReq queryReq = QueryReq.builder()
.databaseName(CommonConstant.MATERIAL_MILVUS_DATABASE)
.collectionName(CommonConstant.MATERIAL_NAME_MATCH_COLLECTION)
.filter(queryExpr)
.outputFields(outputFields)
.build();
QueryResp queryResp = milvusServiceClient.query(queryReq);
List<QueryResp.QueryResult> results = queryResp.getQueryResults();
for (QueryResp.QueryResult result : results) {
long id = (long)result.getEntity().get("id");
String original_text = (String) result.getEntity().get("A");
String standard_code = (String) result.getEntity().get("B");
String treat = treat(manufacturer);
// 只更新需要修改的entity
if (!treat.equals(manufacturer)){
JsonObject jsonObject = new JsonObject();
List<Float> embedding = embeddingService.postForEmbedding(original_text).getData().get(0).getEmbedding();
jsonObject.addProperty("id", id);
jsonObject.add("embedding", gson.toJsonTree(embedding));
jsonObject.addProperty("A", original_text);
jsonObject.addProperty("B", standard_code);
List<JsonObject> dataList = Collections.singletonList(jsonObject);
// 封装UpsertReq 跳进
UpsertReq upsertReq = UpsertReq.builder()
.databaseName(CommonConstant.MATERIAL_MILVUS_DATABASE)
.collectionName(CommonConstant.MATERIAL_NAME_MATCH_COLLECTION)
.data(dataList)
.build();
UpsertResp upsertResp = milvusServiceClient.upsert(upsertReq);
log.info(manufacturer + " 处理之后: " + treat );
System.out.println(upsertResp);
}
}
}
private String treat(String original){
String res = original.replaceAll("\\s+", "");
// 2. 将英文()替换为中文()
res = res.replace("(", "(").replace(")", ")");
return res;
}