mirror of
https://gitee.com/dromara/MilvusPlus.git
synced 2025-12-07 01:18:23 +08:00
!56 态字段查询与映射转换 & 优化分区名称设置前的集合非空判断
Merge pull request !56 from CodeYuan-Y/main
This commit is contained in:
commit
d15e1f8c51
@ -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;
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
// 处理字段名,优先使用注解中的字段名,若无则用反射获取的字段名
|
// 处理字段名,优先使用注解中的字段名,若无则用反射获取的字段名
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,8 +1012,16 @@ 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) {
|
||||||
|
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));
|
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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user