!56 态字段查询与映射转换 & 优化分区名称设置前的集合非空判断

Merge pull request !56 from CodeYuan-Y/main
This commit is contained in:
xgc 2025-09-30 00:44:00 +00:00 committed by Gitee
commit d15e1f8c51
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 73 additions and 15 deletions

View File

@ -54,7 +54,7 @@ public class CollectionSchemaBuilder {
} }
public void addNumPartitions(Integer numPartitions){ public void addNumPartitions(Integer numPartitions){
if (numPartitions < 1) { if (numPartitions == null || numPartitions < 1) {
return; return;
} }
this.numPartitions=numPartitions; this.numPartitions=numPartitions;

View File

@ -1,7 +1,10 @@
package org.dromara.milvus.plus.cache; package org.dromara.milvus.plus.cache;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* @author xgc * @author xgc
**/ **/
@ -13,6 +16,9 @@ public class PropertyCache {
public Map<String, String> methodToPropertyMap = new HashMap<>(); //属性get方法名称->集合属性名称 public Map<String, String> methodToPropertyMap = new HashMap<>(); //属性get方法名称->集合属性名称
public Set<String> metaFunctionSet = new HashSet<>(); //动态字段属性名称
public Map<String, String> metaMethodMap = new HashMap<>(); //属性get方法名称
// 根据值查找第一个匹配的键 // 根据值查找第一个匹配的键
public String findKeyByValue(String value) { public String findKeyByValue(String value) {

View File

@ -94,6 +94,11 @@ public class MilvusConverter {
for (Field field : fields) { for (Field field : fields) {
MilvusField fieldAnnotation = field.getAnnotation(MilvusField.class); MilvusField fieldAnnotation = field.getAnnotation(MilvusField.class);
if (Objects.isNull(fieldAnnotation)) { if (Objects.isNull(fieldAnnotation)) {
if (collectionAnnotation.enableDynamicField()) {
propertyCache.functionToPropertyMap.put("$meta", "$meta");
propertyCache.metaFunctionSet.add(field.getName());
propertyCache.metaMethodMap.put(getGetMethodName(field), field.getName());
}
continue; continue;
} }
// 处理字段名优先使用注解中的字段名若无则用反射获取的字段名 // 处理字段名优先使用注解中的字段名若无则用反射获取的字段名

View File

@ -3,6 +3,7 @@ package org.dromara.milvus.plus.converter;
import io.milvus.v2.service.vector.response.GetResp; import io.milvus.v2.service.vector.response.GetResp;
import io.milvus.v2.service.vector.response.QueryResp; import io.milvus.v2.service.vector.response.QueryResp;
import io.milvus.v2.service.vector.response.SearchResp; import io.milvus.v2.service.vector.response.SearchResp;
import org.apache.commons.collections4.CollectionUtils;
import org.dromara.milvus.plus.cache.ConversionCache; import org.dromara.milvus.plus.cache.ConversionCache;
import org.dromara.milvus.plus.cache.MilvusCache; import org.dromara.milvus.plus.cache.MilvusCache;
import org.dromara.milvus.plus.cache.PropertyCache; import org.dromara.milvus.plus.cache.PropertyCache;
@ -27,7 +28,7 @@ public class SearchRespConverter {
* @param entityType 指定的Java实体类类型用于将搜索结果的每个实体转换为该类型 * @param entityType 指定的Java实体类类型用于将搜索结果的每个实体转换为该类型
* @return 转换后的MilvusResp对象其中包含了列表形式的搜索结果以及操作是否成功的标志 * @return 转换后的MilvusResp对象其中包含了列表形式的搜索结果以及操作是否成功的标志
*/ */
public static <T> MilvusResp<List<MilvusResult<T>>> convertSearchRespToMilvusResp(SearchResp searchResp, Class<T> entityType) { public static <T> MilvusResp<List<MilvusResult<T>>> convertSearchRespToMilvusResp(SearchResp searchResp, Class<T> entityType, List<String> outputMetaFields) {
// 从缓存中获取对应实体类型的转换缓存和属性缓存 // 从缓存中获取对应实体类型的转换缓存和属性缓存
ConversionCache conversionCache = MilvusCache.milvusCache.get(entityType.getName()); ConversionCache conversionCache = MilvusCache.milvusCache.get(entityType.getName());
PropertyCache propertyCache = conversionCache.getPropertyCache(); PropertyCache propertyCache = conversionCache.getPropertyCache();
@ -41,7 +42,18 @@ public class SearchRespConverter {
Map<String, Object> entityMap = new HashMap<>(); Map<String, Object> entityMap = new HashMap<>();
for (Map.Entry<String, Object> entry : searchResult.getEntity().entrySet()) { for (Map.Entry<String, Object> entry : searchResult.getEntity().entrySet()) {
String key = propertyCache.findKeyByValue(entry.getKey()); String key = propertyCache.findKeyByValue(entry.getKey());
if(key!=null){ if (conversionCache.getMilvusEntity().getEnableDynamicField()
&& "$meta".equals(entry.getKey())
&& CollectionUtils.isNotEmpty(outputMetaFields)) {
if (entry.getValue() == null) {
continue;
}
Map<String, Object> metaMap = GsonUtil.fromJsonToMap(entry.getValue().toString());
//metaFunctionSet 类型匹配并完成 map 放入 entityMap 的操作
metaMap.entrySet().stream()
.filter(mapEntry -> propertyCache.metaFunctionSet.contains(String.valueOf(mapEntry.getKey())) && outputMetaFields.contains(mapEntry.getKey()))
.forEach(mapEntry -> entityMap.put(String.valueOf(mapEntry.getKey()), mapEntry.getValue()));
} else if(key!=null){
Object value = entry.getValue(); Object value = entry.getValue();
entityMap.put(key,value); entityMap.put(key,value);
} }
@ -69,10 +81,10 @@ public class SearchRespConverter {
* @param entityType 实体类型用于泛型结果的类型转换 * @param entityType 实体类型用于泛型结果的类型转换
* @return 返回一个包含Milvus结果列表的MilvusResp对象 * @return 返回一个包含Milvus结果列表的MilvusResp对象
*/ */
public static <T> MilvusResp<List<MilvusResult<T>>> convertGetRespToMilvusResp(QueryResp getResp, Class<T> entityType) { public static <T> MilvusResp<List<MilvusResult<T>>> convertGetRespToMilvusResp(QueryResp getResp, Class<T> entityType, List<String> outputMetaFields) {
// 从QueryResp中提取查询结果 // 从QueryResp中提取查询结果
List<QueryResp.QueryResult> queryResults = getResp.getQueryResults(); List<QueryResp.QueryResult> queryResults = getResp.getQueryResults();
return convertQuery(queryResults, entityType); return convertQuery(queryResults, entityType, outputMetaFields);
} }
public static MilvusResp<Long> convertGetRespToCount(QueryResp getResp) { public static MilvusResp<Long> convertGetRespToCount(QueryResp getResp) {
// 从QueryResp中提取查询结果 // 从QueryResp中提取查询结果
@ -86,10 +98,10 @@ public class SearchRespConverter {
* @param entityType 实体类型用于泛型结果的类型转换 * @param entityType 实体类型用于泛型结果的类型转换
* @return 返回一个包含Milvus结果列表的MilvusResp对象 * @return 返回一个包含Milvus结果列表的MilvusResp对象
*/ */
public static <T> MilvusResp<List<MilvusResult<T>>> convertGetRespToMilvusResp(GetResp getResp, Class<T> entityType) { public static <T> MilvusResp<List<MilvusResult<T>>> convertGetRespToMilvusResp(GetResp getResp, Class<T> entityType, List<String> outputMetaFields) {
// 从GetResp中提取结果 // 从GetResp中提取结果
List<QueryResp.QueryResult> getResults = getResp.getResults; List<QueryResp.QueryResult> getResults = getResp.getResults;
return convertQuery(getResults, entityType); return convertQuery(getResults, entityType, outputMetaFields);
} }
@ -100,7 +112,7 @@ public class SearchRespConverter {
* @param entityType 需要转换成的实体类型指定了转换的目标 * @param entityType 需要转换成的实体类型指定了转换的目标
* @return MilvusResp对象包含转换后的实体列表每个实体都包装在一个MilvusResult对象中同时设置成功状态为true * @return MilvusResp对象包含转换后的实体列表每个实体都包装在一个MilvusResult对象中同时设置成功状态为true
*/ */
private static <T> MilvusResp<List<MilvusResult<T>>> convertQuery(List<QueryResp.QueryResult> getResults, Class<T> entityType){ private static <T> MilvusResp<List<MilvusResult<T>>> convertQuery(List<QueryResp.QueryResult> getResults, Class<T> entityType, List<String> outputMetaFields){
// 初始化转换缓存和属性缓存用于帮助将查询结果映射到Java实体 // 初始化转换缓存和属性缓存用于帮助将查询结果映射到Java实体
ConversionCache conversionCache = MilvusCache.milvusCache.get(entityType.getName()); ConversionCache conversionCache = MilvusCache.milvusCache.get(entityType.getName());
PropertyCache propertyCache = conversionCache.getPropertyCache(); PropertyCache propertyCache = conversionCache.getPropertyCache();
@ -113,7 +125,12 @@ public class SearchRespConverter {
// 通过属性缓存转换键名以适应Java实体的字段命名 // 通过属性缓存转换键名以适应Java实体的字段命名
for (Map.Entry<String, Object> entry : entityMap.entrySet()) { for (Map.Entry<String, Object> entry : entityMap.entrySet()) {
String key = propertyCache.findKeyByValue(entry.getKey()); String key = propertyCache.findKeyByValue(entry.getKey());
if(key!=null){ if (conversionCache.getMilvusEntity().getEnableDynamicField()
&& propertyCache.metaFunctionSet.contains(entry.getKey())
&& CollectionUtils.isNotEmpty(outputMetaFields)
&& outputMetaFields.contains(entry.getKey())) {
entityMap2.put(String.valueOf(entry.getKey()), entry.getValue());
} else if(key!=null){
Object value = entry.getValue(); Object value = entry.getValue();
entityMap2.put(key,value); entityMap2.put(key,value);
} }

View File

@ -36,6 +36,7 @@ import java.util.stream.Collectors;
public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wrapper<LambdaQueryWrapper<T>, T> { public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wrapper<LambdaQueryWrapper<T>, T> {
private ConversionCache conversionCache; private ConversionCache conversionCache;
private List<String> outputFields; private List<String> outputFields;
private List<String> outputMetaFields;
private Class<T> entityType; private Class<T> entityType;
private String collectionName; private String collectionName;
private String collectionAlias; private String collectionAlias;
@ -858,6 +859,9 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
Collection<String> values = conversionCache.getPropertyCache().functionToPropertyMap.values(); Collection<String> values = conversionCache.getPropertyCache().functionToPropertyMap.values();
builder.outputFields(new ArrayList<>(values)); builder.outputFields(new ArrayList<>(values));
} }
if (CollectionUtils.isEmpty(outputMetaFields) && !CollectionUtils.isEmpty(conversionCache.getPropertyCache().metaFunctionSet)) {
outputMetaFields = new ArrayList<>(conversionCache.getPropertyCache().metaFunctionSet);
}
if (!searchParams.isEmpty()) { if (!searchParams.isEmpty()) {
builder.searchParams(searchParams); builder.searchParams(searchParams);
} }
@ -914,6 +918,9 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
Collection<String> values = conversionCache.getPropertyCache().functionToPropertyMap.values(); Collection<String> values = conversionCache.getPropertyCache().functionToPropertyMap.values();
builder.outputFields(new ArrayList<>(values)); builder.outputFields(new ArrayList<>(values));
} }
if (CollectionUtils.isEmpty(outputMetaFields) && !CollectionUtils.isEmpty(conversionCache.getPropertyCache().metaFunctionSet)) {
outputMetaFields = new ArrayList<>(conversionCache.getPropertyCache().metaFunctionSet);
}
return builder.build(); return builder.build();
} }
private HybridSearchReq buildHybrid(){ private HybridSearchReq buildHybrid(){
@ -955,6 +962,9 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
Collection<String> values = conversionCache.getPropertyCache().functionToPropertyMap.values(); Collection<String> values = conversionCache.getPropertyCache().functionToPropertyMap.values();
reqBuilder.outFields(new ArrayList<>(values)); reqBuilder.outFields(new ArrayList<>(values));
} }
if (CollectionUtils.isEmpty(outputMetaFields) && !CollectionUtils.isEmpty(conversionCache.getPropertyCache().metaFunctionSet)) {
outputMetaFields = new ArrayList<>(conversionCache.getPropertyCache().metaFunctionSet);
}
if (!CollectionUtils.isEmpty(partitionNames)) { if (!CollectionUtils.isEmpty(partitionNames)) {
reqBuilder.partitionNames(partitionNames); reqBuilder.partitionNames(partitionNames);
} }
@ -977,18 +987,18 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
HybridSearchReq hybridSearchReq = buildHybrid(); HybridSearchReq hybridSearchReq = buildHybrid();
log.info("Build HybridSearch Param--> {}", GsonUtil.toJson(hybridSearchReq)); log.info("Build HybridSearch Param--> {}", GsonUtil.toJson(hybridSearchReq));
SearchResp searchResp = client.hybridSearch(hybridSearchReq); SearchResp searchResp = client.hybridSearch(hybridSearchReq);
return SearchRespConverter.convertSearchRespToMilvusResp(searchResp, entityType); return SearchRespConverter.convertSearchRespToMilvusResp(searchResp, entityType, outputMetaFields);
} }
if (!vectors.isEmpty()) { if (!vectors.isEmpty()) {
SearchReq searchReq = buildSearch(); SearchReq searchReq = buildSearch();
log.info("Build Search Param--> {}", GsonUtil.toJson(searchReq)); log.info("Build Search Param--> {}", GsonUtil.toJson(searchReq));
SearchResp searchResp = client.search(searchReq); SearchResp searchResp = client.search(searchReq);
return SearchRespConverter.convertSearchRespToMilvusResp(searchResp, entityType); return SearchRespConverter.convertSearchRespToMilvusResp(searchResp, entityType, outputMetaFields);
} else { } else {
QueryReq queryReq = buildQuery(); QueryReq queryReq = buildQuery();
log.info("Build Query param--> {}", GsonUtil.toJson(queryReq)); log.info("Build Query param--> {}", GsonUtil.toJson(queryReq));
QueryResp queryResp = client.query(queryReq); QueryResp queryResp = client.query(queryReq);
return SearchRespConverter.convertGetRespToMilvusResp(queryResp, entityType); return SearchRespConverter.convertGetRespToMilvusResp(queryResp, entityType, outputMetaFields);
} }
}, },
"collection not loaded", "collection not loaded",
@ -1002,7 +1012,15 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
public MilvusResp<List<MilvusResult<T>>> query(FieldFunction<T, ?>... outputFields) throws MilvusException { public MilvusResp<List<MilvusResult<T>>> query(FieldFunction<T, ?>... outputFields) throws MilvusException {
List<String> otf = new ArrayList<>(); List<String> otf = new ArrayList<>();
for (FieldFunction<T, ?> outputField : outputFields) { for (FieldFunction<T, ?> outputField : outputFields) {
otf.add(outputField.getFieldName(outputField)); String methodName = outputField.getSerializedLambda(outputField).getImplMethodName();
if (conversionCache.getMilvusEntity().getEnableDynamicField() &&
conversionCache.getPropertyCache().metaMethodMap.containsKey(methodName)){
outputMetaFields = Optional.ofNullable(outputMetaFields).orElse(new ArrayList<>());
outputMetaFields.add(conversionCache.getPropertyCache().metaMethodMap.get(methodName));
otf.add("$meta");
} else {
otf.add(outputField.getFieldName(outputField));
}
} }
this.outputFields = otf; this.outputFields = otf;
return query(); return query();
@ -1027,7 +1045,19 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
} }
public MilvusResp<List<MilvusResult<T>>> query(String... outputFields) throws MilvusException { public MilvusResp<List<MilvusResult<T>>> query(String... outputFields) throws MilvusException {
this.outputFields = Arrays.stream(outputFields).collect(Collectors.toList()); this.outputFields = Arrays.stream(outputFields)
.map(field -> {
String milvusField = conversionCache.getPropertyCache().functionToPropertyMap.get(field);
if (milvusField == null &&
conversionCache.getMilvusEntity().getEnableDynamicField() &&
conversionCache.getPropertyCache().metaFunctionSet.contains(field)) {
outputMetaFields = Optional.ofNullable(outputMetaFields).orElse(new ArrayList<>());
outputMetaFields.add(field);
return "$meta";
}
return milvusField;
})
.collect(Collectors.toList());
return query(); return query();
} }
@ -1041,7 +1071,7 @@ public class LambdaQueryWrapper<T> extends AbstractChainWrapper<T> implements Wr
GetReq getReq = builder.build(); GetReq getReq = builder.build();
GetResp getResp = client.get(getReq); GetResp getResp = client.get(getReq);
return SearchRespConverter.convertGetRespToMilvusResp(getResp, entityType); return SearchRespConverter.convertGetRespToMilvusResp(getResp, entityType, outputMetaFields);
} }
@Override @Override