Skip to content

Commit

Permalink
Support expression template values
Browse files Browse the repository at this point in the history
Signed-off-by: yhmo <[email protected]>
  • Loading branch information
yhmo committed Oct 25, 2024
1 parent 3d6de38 commit d0f4082
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 8 deletions.
14 changes: 10 additions & 4 deletions src/main/java/io/milvus/v2/service/vector/VectorService.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class VectorService extends BaseService {
Expand Down Expand Up @@ -224,12 +225,17 @@ public DeleteResp delete(MilvusServiceGrpc.MilvusServiceBlockingStub blockingStu
if (request.getFilter() == null) {
request.setFilter(vectorUtils.getExprById(respR.getPrimaryFieldName(), request.getIds()));
}
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
DeleteRequest.Builder builder = DeleteRequest.newBuilder()
.setCollectionName(request.getCollectionName())
.setPartitionName(request.getPartitionName())
.setExpr(request.getFilter())
.build();
MutationResult response = blockingStub.delete(deleteRequest);
.setExpr(request.getFilter());
if (request.getFilter() != null && !request.getFilter().isEmpty()) {
Map<String, Object> filterTemplateValues = request.getFilterTemplateValues();
filterTemplateValues.forEach((key, value)->{
builder.putExprTemplateValues(key, vectorUtils.deduceTemplateValue(value));
});
}
MutationResult response = blockingStub.delete(builder.build());
rpcUtils.handleResponse(title, response.getStatus());
GTsDict.getInstance().updateCollectionTs(request.getCollectionName(), response.getTimestamp());
return DeleteResp.builder()
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/io/milvus/v2/service/vector/request/DeleteReq.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import lombok.Data;
import lombok.experimental.SuperBuilder;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
@SuperBuilder
Expand All @@ -33,4 +35,15 @@ public class DeleteReq {
private String partitionName = "";
private String filter;
private List<Object> ids;

// Expression template, to improve expression parsing performance in complicated list
// Assume user has a filter = "pk > 3 and city in ["beijing", "shanghai", ......]
// The long list of city will increase the time cost to parse this expression.
// So, we provide exprTemplateValues for this purpose, user can set filter like this:
// filter = "pk > {age} and city in {city}"
// filterTemplateValues = Map{"age": 3, "city": List<String>{"beijing", "shanghai", ......}}
// Valid value of this map can be:
// Boolean, Long, Double, String, List<Boolean>, List<Long>, List<Double>, List<String>
@Builder.Default
private Map<String, Object> filterTemplateValues = new HashMap<>();
}
15 changes: 12 additions & 3 deletions src/main/java/io/milvus/v2/service/vector/request/QueryReq.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
import lombok.Data;
import lombok.experimental.SuperBuilder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;

@Data
@SuperBuilder
Expand All @@ -42,4 +40,15 @@ public class QueryReq {
private ConsistencyLevel consistencyLevel = null;
private long offset;
private long limit;

// Expression template, to improve expression parsing performance in complicated list
// Assume user has a filter = "pk > 3 and city in ["beijing", "shanghai", ......]
// The long list of city will increase the time cost to parse this expression.
// So, we provide exprTemplateValues for this purpose, user can set filter like this:
// filter = "pk > {age} and city in {city}"
// filterTemplateValues = Map{"age": 3, "city": List<String>{"beijing", "shanghai", ......}}
// Valid value of this map can be:
// Boolean, Long, Double, String, List<Boolean>, List<Long>, List<Double>, List<String>
@Builder.Default
private Map<String, Object> filterTemplateValues = new HashMap<>();
}
11 changes: 11 additions & 0 deletions src/main/java/io/milvus/v2/service/vector/request/SearchReq.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,15 @@ public class SearchReq {
private ConsistencyLevel consistencyLevel = null;
private boolean ignoreGrowing;
private String groupByFieldName;

// Expression template, to improve expression parsing performance in complicated list
// Assume user has a filter = "pk > 3 and city in ["beijing", "shanghai", ......]
// The long list of city will increase the time cost to parse this expression.
// So, we provide exprTemplateValues for this purpose, user can set filter like this:
// filter = "pk > {age} and city in {city}"
// filterTemplateValues = Map{"age": 3, "city": List<String>{"beijing", "shanghai", ......}}
// Valid value of this map can be:
// Boolean, Long, Double, String, List<Boolean>, List<Long>, List<Double>, List<String>
@Builder.Default
private Map<String, Object> filterTemplateValues = new HashMap<>();
}
56 changes: 56 additions & 0 deletions src/main/java/io/milvus/v2/utils/VectorUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package io.milvus.v2.utils;

import com.google.protobuf.ByteString;
import com.sun.org.apache.xpath.internal.operations.Bool;
import io.milvus.common.utils.GTsDict;
import io.milvus.common.utils.JsonUtils;
import io.milvus.v2.common.ConsistencyLevel;
Expand All @@ -44,6 +45,12 @@ public QueryRequest ConvertToGrpcQueryRequest(QueryReq request){
.addAllPartitionNames(request.getPartitionNames())
.addAllOutputFields(request.getOutputFields())
.setExpr(request.getFilter());
if (request.getFilter() != null && !request.getFilter().isEmpty()) {
Map<String, Object> filterTemplateValues = request.getFilterTemplateValues();
filterTemplateValues.forEach((key, value)->{
builder.putExprTemplateValues(key, deduceTemplateValue(value));
});
}

// a new parameter from v2.2.9, if user didn't specify consistency level, set this parameter to true
if (request.getConsistencyLevel() == null) {
Expand Down Expand Up @@ -180,6 +187,10 @@ public SearchRequest ConvertToGrpcSearchRequest(SearchReq request) {
builder.setDslType(DslType.BoolExprV1);
if (request.getFilter() != null && !request.getFilter().isEmpty()) {
builder.setDsl(request.getFilter());
Map<String, Object> filterTemplateValues = request.getFilterTemplateValues();
filterTemplateValues.forEach((key, value)->{
builder.putExprTemplateValues(key, deduceTemplateValue(value));
});
}

long guaranteeTimestamp = getGuaranteeTimestamp(request.getConsistencyLevel(), request.getCollectionName());
Expand All @@ -195,6 +206,51 @@ public SearchRequest ConvertToGrpcSearchRequest(SearchReq request) {
return builder.build();
}

public static TemplateValue deduceTemplateValue(Object value) {
if (value instanceof Boolean) {
return TemplateValue.newBuilder()
.setBoolVal((Boolean)value)
.setType(DataType.Bool)
.build();
} else if (value instanceof Long) {
return TemplateValue.newBuilder()
.setInt64Val((Long)value)
.setType(DataType.Int64)
.build();
} else if (value instanceof Double) {
return TemplateValue.newBuilder()
.setFloatVal((Double)value)
.setType(DataType.Double)
.build();
} else if (value instanceof String) {
return TemplateValue.newBuilder()
.setStringVal((String)value)
.setType(DataType.VarChar)
.build();
} else if (value instanceof List) {
List<Object> array = (List<Object>)value;
TemplateArrayValue.Builder builder = TemplateArrayValue.newBuilder();
DataType lastType = DataType.UNRECOGNIZED;
boolean sameType = true;
for (Object obj : array) {
TemplateValue tv = deduceTemplateValue(obj);
builder.addArray(tv);
if (lastType == DataType.UNRECOGNIZED) {
lastType = tv.getType();
} else if (lastType != tv.getType()) {
sameType = false;
}
}
DataType arrayType = sameType ? lastType : DataType.JSON;
return TemplateValue.newBuilder()
.setArrayVal(builder.build())
.setType(arrayType)
.build();
} else {
throw new ParamException("Unsupported value type for expression template.");
}
}

public static SearchRequest convertAnnSearchParam(@NonNull AnnSearchReq annSearchReq,
ConsistencyLevel consistencyLevel) {
SearchRequest.Builder builder = SearchRequest.newBuilder();
Expand Down
2 changes: 1 addition & 1 deletion src/main/milvus-proto

0 comments on commit d0f4082

Please sign in to comment.