mirror of
https://gitee.com/dromara/easy-es.git
synced 2025-12-06 17:18:57 +08:00
!84 新增@MultiIndexField多字段注解,并完成相关索引创建功能,实现预期效果
Merge pull request !84 from yinlei1006/ospp-2023
This commit is contained in:
commit
6d8e6daa8d
@ -18,10 +18,4 @@
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -1,7 +1,6 @@
|
||||
package org.dromara.easyes.annotation;
|
||||
|
||||
|
||||
|
||||
import org.dromara.easyes.annotation.rely.*;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@ -80,6 +79,13 @@ public @interface IndexField {
|
||||
*/
|
||||
boolean ignoreCase() default false;
|
||||
|
||||
/**
|
||||
* 长度超过ignore_above设置的字符串将不会被索引或存储 keyword_text默认值为256
|
||||
*
|
||||
* @return 索引字段最大长度
|
||||
*/
|
||||
int ignoreAbove() default -1;
|
||||
|
||||
/**
|
||||
* 默认嵌套类
|
||||
*
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package org.dromara.easyes.annotation;
|
||||
|
||||
import org.dromara.easyes.annotation.rely.DefaultChildClass;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
@ -82,6 +81,4 @@ public @interface IndexName {
|
||||
* @return CRUD作用的路由
|
||||
*/
|
||||
String routing() default "";
|
||||
|
||||
RefreshPolicy refreshPolicy() default RefreshPolicy.GLOBAL;
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package org.dromara.easyes.annotation;
|
||||
|
||||
|
||||
import org.dromara.easyes.annotation.rely.Analyzer;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
|
||||
/**
|
||||
* 内部字段索引注解
|
||||
* <p>
|
||||
*
|
||||
* @author yinlei
|
||||
**/
|
||||
public @interface InnerIndexField {
|
||||
/**
|
||||
* 内部字段的前缀,必须指定,否则无存在意义,且不可重名,重名则以首次出现的为准
|
||||
*
|
||||
* @return 内部字段的前缀
|
||||
*/
|
||||
String suffix();
|
||||
|
||||
/**
|
||||
* 内部字段在es索引中的类型,必须指定,否则无存在意义
|
||||
*
|
||||
* @return 类型
|
||||
*/
|
||||
FieldType fieldType();
|
||||
|
||||
/**
|
||||
* 内部字段索引文档时用的分词器
|
||||
*
|
||||
* @return 分词器
|
||||
*/
|
||||
String analyzer() default Analyzer.NONE;
|
||||
|
||||
/**
|
||||
* 内部字段查询分词器
|
||||
*
|
||||
* @return 分词器
|
||||
*/
|
||||
String searchAnalyzer() default Analyzer.NONE;
|
||||
|
||||
/**
|
||||
* 内部字段长度超过ignore_above设置的字符串将不会被索引或存储 keyword_text默认值为256
|
||||
*
|
||||
* @return 索引内部字段最大长度
|
||||
*/
|
||||
int ignoreAbove() default -1;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package org.dromara.easyes.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 多字段索引注解
|
||||
* <p>
|
||||
*
|
||||
* @author yinlei
|
||||
**/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface MultiIndexField {
|
||||
/**
|
||||
* 主字段信息
|
||||
*
|
||||
* @return 主字段信息
|
||||
*/
|
||||
IndexField mainIndexField();
|
||||
|
||||
/**
|
||||
* 内部字段信息
|
||||
*
|
||||
* @return 内部字段信息
|
||||
*/
|
||||
InnerIndexField[] otherIndexFields() default {};
|
||||
}
|
||||
@ -29,6 +29,9 @@ public enum FieldType {
|
||||
BINARY("binary"),
|
||||
KEYWORD("keyword"),
|
||||
TEXT("text"),
|
||||
/**
|
||||
* This type can not be used for @InnerIndexField
|
||||
*/
|
||||
KEYWORD_TEXT("keyword&text"),
|
||||
WILDCARD("wildcard"),
|
||||
/**
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package org.dromara.easyes.annotation.rely;
|
||||
package org.dromara.easyes.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
@ -7,17 +7,11 @@ import lombok.Getter;
|
||||
* 数据刷新策略枚举
|
||||
* <p>
|
||||
* Copyright © 2021 xpc1024 All Rights Reserved
|
||||
*
|
||||
* @see org.elasticsearch.action.support.WriteRequest.RefreshPolicy
|
||||
**/
|
||||
@AllArgsConstructor
|
||||
public enum RefreshPolicy {
|
||||
/**
|
||||
* 使用全局设置: easy-es.global-config.db-config.refresh-policy
|
||||
*/
|
||||
GLOBAL(""),
|
||||
/**
|
||||
* 不立即刷新 (es默认的数据刷新策略)
|
||||
* 默认不刷新
|
||||
*/
|
||||
NONE("false"),
|
||||
/**
|
||||
@ -61,7 +61,26 @@ public class Assert {
|
||||
}
|
||||
}
|
||||
|
||||
public static void notBlank(String str, String message) {
|
||||
if (str == null || str.isEmpty() || !containsText(str)) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean containsText(CharSequence str) {
|
||||
int strLen = str.length();
|
||||
|
||||
for (int i = 0; i < strLen; ++i) {
|
||||
if (!Character.isWhitespace(str.charAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isEmpty(Object[] array) {
|
||||
return array == null || array.length == 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
package org.dromara.easyes.core.biz;
|
||||
|
||||
import org.dromara.easyes.annotation.IndexField;
|
||||
import org.dromara.easyes.annotation.rely.FieldStrategy;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
import org.dromara.easyes.core.config.GlobalConfig;
|
||||
import com.alibaba.fastjson.serializer.NameFilter;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.dromara.easyes.annotation.IndexField;
|
||||
import org.dromara.easyes.annotation.rely.FieldStrategy;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
import org.dromara.easyes.core.config.GlobalConfig;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* es实体字段信息
|
||||
@ -47,6 +48,10 @@ public class EntityFieldInfo {
|
||||
* 字段是否忽略大小写,默认不忽略 为true时则忽略大小写
|
||||
*/
|
||||
private boolean ignoreCase;
|
||||
/**
|
||||
* 字段最大索引长度
|
||||
*/
|
||||
private Integer ignoreAbove;
|
||||
/**
|
||||
* 分词器
|
||||
*/
|
||||
@ -86,6 +91,11 @@ public class EntityFieldInfo {
|
||||
private String sqlSelect;
|
||||
private NameFilter nameFilter;
|
||||
|
||||
/**
|
||||
* 内部字段列表
|
||||
*/
|
||||
private List<InnerFieldInfo> innerFieldInfoList;
|
||||
|
||||
/**
|
||||
* 存在 TableField 注解时, 使用的构造函数
|
||||
*
|
||||
@ -95,7 +105,6 @@ public class EntityFieldInfo {
|
||||
*/
|
||||
public EntityFieldInfo(GlobalConfig.DbConfig dbConfig, Field field, IndexField tableField) {
|
||||
this.column = field.getName();
|
||||
|
||||
// 优先使用单个字段注解,否则使用全局配置
|
||||
if (tableField.strategy() == FieldStrategy.DEFAULT) {
|
||||
this.fieldStrategy = dbConfig.getFieldStrategy();
|
||||
@ -115,4 +124,31 @@ public class EntityFieldInfo {
|
||||
this.column = field.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部字段
|
||||
*/
|
||||
@Data
|
||||
public static class InnerFieldInfo {
|
||||
/**
|
||||
* 内部字段名
|
||||
*/
|
||||
private String column;
|
||||
/**
|
||||
* 内部字段类型
|
||||
*/
|
||||
private FieldType fieldType;
|
||||
/**
|
||||
* 内部字段分词器
|
||||
*/
|
||||
private String analyzer;
|
||||
/**
|
||||
* 内部字段查询分词器
|
||||
*/
|
||||
private String searchAnalyzer;
|
||||
/**
|
||||
* 字段最大索引长度
|
||||
*/
|
||||
private Integer ignoreAbove;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
|
||||
import com.alibaba.fastjson.serializer.SerializeFilter;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
@ -178,8 +177,6 @@ public class EntityInfo {
|
||||
*/
|
||||
private final Map<Class<?>, List<SerializeFilter>> classSimplePropertyPreFilterMap = new HashMap<>();
|
||||
|
||||
private RefreshPolicy refreshPolicy;
|
||||
|
||||
/**
|
||||
* 获取需要进行查询的字段列表
|
||||
*
|
||||
|
||||
@ -2,6 +2,8 @@ package org.dromara.easyes.core.biz;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 索引相关参数
|
||||
* <p>
|
||||
@ -45,6 +47,10 @@ public class EsIndexParam {
|
||||
* 字段是否忽略大小写,默认不忽略 为true时则忽略大小写
|
||||
*/
|
||||
private boolean ignoreCase;
|
||||
/**
|
||||
* 字段最大索引长度 默认256
|
||||
*/
|
||||
private Integer ignoreAbove;
|
||||
/**
|
||||
* 父名称
|
||||
*/
|
||||
@ -53,4 +59,35 @@ public class EsIndexParam {
|
||||
* 子名称
|
||||
*/
|
||||
private String childName;
|
||||
/**
|
||||
* 内部字段列表
|
||||
*/
|
||||
private List<InnerFieldParam> innerFieldParamList;
|
||||
|
||||
/**
|
||||
* 内部段参数
|
||||
*/
|
||||
@Data
|
||||
public static class InnerFieldParam {
|
||||
/**
|
||||
* 内部字段名称
|
||||
*/
|
||||
private String column;
|
||||
/**
|
||||
* 内部字段类型
|
||||
*/
|
||||
private String fieldType;
|
||||
/**
|
||||
* 内部分词器
|
||||
*/
|
||||
private String analyzer;
|
||||
/**
|
||||
* 内部查询分词器
|
||||
*/
|
||||
private String searchAnalyzer;
|
||||
/**
|
||||
* 内部字段最大索引长度
|
||||
*/
|
||||
private Integer ignoreAbove;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import lombok.Data;
|
||||
import org.dromara.easyes.annotation.rely.FieldStrategy;
|
||||
import org.dromara.easyes.annotation.rely.IdType;
|
||||
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
import org.dromara.easyes.common.enums.RefreshPolicy;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
import static org.dromara.easyes.common.constants.BaseEsConstants.EMPTY_STR;
|
||||
@ -79,7 +79,7 @@ public class GlobalConfig {
|
||||
*/
|
||||
private boolean enableTrackTotalHits = true;
|
||||
/**
|
||||
* data refresh policy 数据刷新策略,es默认的数据刷新策略为NONE
|
||||
* data refresh policy 数据刷新策略,默认为NONE
|
||||
*/
|
||||
private RefreshPolicy refreshPolicy = RefreshPolicy.NONE;
|
||||
/**
|
||||
|
||||
@ -13,7 +13,7 @@ import org.dromara.easyes.annotation.rely.IdType;
|
||||
import org.dromara.easyes.common.constants.BaseEsConstants;
|
||||
import org.dromara.easyes.common.enums.EsQueryTypeEnum;
|
||||
import org.dromara.easyes.common.enums.MethodEnum;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
import org.dromara.easyes.common.enums.RefreshPolicy;
|
||||
import org.dromara.easyes.common.utils.*;
|
||||
import org.dromara.easyes.core.biz.*;
|
||||
import org.dromara.easyes.core.cache.BaseCache;
|
||||
@ -1485,7 +1485,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
&& searchResponse.getShardFailures() != null
|
||||
&& searchResponse.getShardFailures().length > ZERO) {
|
||||
String errorMsg = searchResponse.getShardFailures()[0].toString();
|
||||
throw ExceptionUtils.eee("es响应出错,search response failed ,failedShards: " + errorMsg);
|
||||
throw ExceptionUtils.eee("search response failed ,failedShards: " + errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1495,7 +1495,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
|
||||
* @return 刷新策略
|
||||
*/
|
||||
private String getRefreshPolicy() {
|
||||
return EntityInfoHelper.getEntityInfo(entityClass).getRefreshPolicy().getValue();
|
||||
return GlobalConfigCache.getGlobalConfig().getDbConfig().getRefreshPolicy().getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -8,11 +8,7 @@ import org.dromara.easyes.annotation.*;
|
||||
import org.dromara.easyes.annotation.rely.DefaultNestedClass;
|
||||
import org.dromara.easyes.annotation.rely.FieldType;
|
||||
import org.dromara.easyes.annotation.rely.IdType;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
import org.dromara.easyes.common.utils.ClassUtils;
|
||||
import org.dromara.easyes.common.utils.FastJsonUtils;
|
||||
import org.dromara.easyes.common.utils.ReflectionKit;
|
||||
import org.dromara.easyes.common.utils.StringUtils;
|
||||
import org.dromara.easyes.common.utils.*;
|
||||
import org.dromara.easyes.core.biz.EntityFieldInfo;
|
||||
import org.dromara.easyes.core.biz.EntityInfo;
|
||||
import org.dromara.easyes.core.biz.HighLightParam;
|
||||
@ -106,14 +102,14 @@ public class EntityInfoHelper {
|
||||
List<Field> list = getAllFields(clazz);
|
||||
// 标记是否读取到主键
|
||||
boolean isReadPK = false;
|
||||
// 是否存在 @TableId 注解
|
||||
boolean existTableId = isExistIndexId(list);
|
||||
// 是否存在 @IndexId 注解
|
||||
boolean existsIndexId = isExistIndexId(list);
|
||||
|
||||
List<EntityFieldInfo> fieldList = new ArrayList<>();
|
||||
for (Field field : list) {
|
||||
// 主键ID 初始化
|
||||
if (!isReadPK) {
|
||||
if (existTableId) {
|
||||
if (existsIndexId) {
|
||||
isReadPK = initIndexIdWithAnnotation(dbConfig, entityInfo, field);
|
||||
} else {
|
||||
isReadPK = initIndexIdWithoutAnnotation(dbConfig, entityInfo, field);
|
||||
@ -252,8 +248,8 @@ public class EntityInfoHelper {
|
||||
Field field, EntityInfo entityInfo) {
|
||||
boolean hasAnnotation = false;
|
||||
|
||||
// 初始化封装IndexField注解信息
|
||||
if (field.isAnnotationPresent(IndexField.class)) {
|
||||
// 初始化封装IndexField及MultiIndexField注解信息
|
||||
if (field.isAnnotationPresent(IndexField.class) || field.isAnnotationPresent(MultiIndexField.class)) {
|
||||
initIndexFieldAnnotation(dbConfig, entityInfo, field, fieldList);
|
||||
hasAnnotation = true;
|
||||
}
|
||||
@ -294,60 +290,73 @@ public class EntityInfoHelper {
|
||||
*/
|
||||
private static void initIndexFieldAnnotation(GlobalConfig.DbConfig dbConfig, EntityInfo entityInfo,
|
||||
Field field, List<EntityFieldInfo> fieldList) {
|
||||
IndexField tableField = field.getAnnotation(IndexField.class);
|
||||
if (tableField.exist()) {
|
||||
MultiIndexField multiIndexField = field.getAnnotation(MultiIndexField.class);
|
||||
IndexField indexField = Optional.ofNullable(multiIndexField).map(MultiIndexField::mainIndexField)
|
||||
.orElse(field.getAnnotation(IndexField.class));
|
||||
if (indexField.exist()) {
|
||||
// 存在字段处理
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, tableField);
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, indexField);
|
||||
|
||||
// 自定义字段名及驼峰下划线转换
|
||||
String mappingColumn;
|
||||
if (!StringUtils.isBlank(tableField.value().trim())) {
|
||||
if (!StringUtils.isBlank(indexField.value().trim())) {
|
||||
// 自定义注解指定的名称优先级最高
|
||||
entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), tableField.value());
|
||||
entityInfo.getColumnMappingMap().putIfAbsent(tableField.value(), field.getName());
|
||||
mappingColumn = tableField.value();
|
||||
entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), indexField.value());
|
||||
entityInfo.getColumnMappingMap().putIfAbsent(indexField.value(), field.getName());
|
||||
mappingColumn = indexField.value();
|
||||
} else {
|
||||
// 下划线驼峰
|
||||
mappingColumn = initMappingColumnMapAndGet(dbConfig, entityInfo, field);
|
||||
}
|
||||
|
||||
// 日期格式化
|
||||
if (StringUtils.isNotBlank(tableField.dateFormat())) {
|
||||
entityFieldInfo.setDateFormat(tableField.dateFormat());
|
||||
if (StringUtils.isNotBlank(indexField.dateFormat())) {
|
||||
entityFieldInfo.setDateFormat(indexField.dateFormat());
|
||||
}
|
||||
|
||||
// 是否忽略大小写
|
||||
FieldType fieldType = FieldType.getByType(IndexUtils.getEsFieldType(tableField.fieldType(), field.getType().getSimpleName()));
|
||||
FieldType fieldType = FieldType.getByType(IndexUtils.getEsFieldType(indexField.fieldType(), field.getType().getSimpleName()));
|
||||
if (FieldType.KEYWORD.equals(fieldType)) {
|
||||
// 仅对keyword类型设置,其它类型es不支持
|
||||
entityFieldInfo.setIgnoreCase(tableField.ignoreCase());
|
||||
entityFieldInfo.setIgnoreCase(indexField.ignoreCase());
|
||||
}
|
||||
|
||||
// 最大索引长度
|
||||
if (indexField.ignoreAbove() > ZERO) {
|
||||
entityFieldInfo.setIgnoreAbove(indexField.ignoreAbove());
|
||||
}
|
||||
|
||||
// 其它
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
entityFieldInfo.setAnalyzer(tableField.analyzer());
|
||||
entityFieldInfo.setSearchAnalyzer(tableField.searchAnalyzer());
|
||||
entityFieldInfo.setAnalyzer(indexField.analyzer());
|
||||
entityFieldInfo.setSearchAnalyzer(indexField.searchAnalyzer());
|
||||
entityFieldInfo.setFieldType(fieldType);
|
||||
entityFieldInfo.setFieldData(tableField.fieldData());
|
||||
entityFieldInfo.setFieldData(indexField.fieldData());
|
||||
entityFieldInfo.setColumnType(field.getType().getSimpleName());
|
||||
entityInfo.getFieldTypeMap().putIfAbsent(field.getName(), fieldType.getType());
|
||||
|
||||
// 父子类型
|
||||
if (FieldType.JOIN.equals(tableField.fieldType())) {
|
||||
entityFieldInfo.setParentName(tableField.parentName());
|
||||
entityFieldInfo.setChildName(tableField.childName());
|
||||
if (FieldType.JOIN.equals(indexField.fieldType())) {
|
||||
entityFieldInfo.setParentName(indexField.parentName());
|
||||
entityFieldInfo.setChildName(indexField.childName());
|
||||
|
||||
entityInfo.setJoinFieldName(mappingColumn);
|
||||
entityInfo.setJoinFieldClass(tableField.joinFieldClass());
|
||||
entityInfo.getPathClassMap().putIfAbsent(field.getName(), tableField.joinFieldClass());
|
||||
processNested(tableField.joinFieldClass(), dbConfig, entityInfo);
|
||||
entityInfo.setJoinFieldClass(indexField.joinFieldClass());
|
||||
entityInfo.getPathClassMap().putIfAbsent(field.getName(), indexField.joinFieldClass());
|
||||
processNested(indexField.joinFieldClass(), dbConfig, entityInfo);
|
||||
}
|
||||
|
||||
// 处理内部字段
|
||||
InnerIndexField[] innerIndexFields = Optional.ofNullable(multiIndexField).map(MultiIndexField::otherIndexFields).orElse(null);
|
||||
processInnerField(innerIndexFields, entityFieldInfo);
|
||||
|
||||
fieldList.add(entityFieldInfo);
|
||||
|
||||
// 嵌套类处理
|
||||
if (DefaultNestedClass.class != tableField.nestedClass()) {
|
||||
if (DefaultNestedClass.class != indexField.nestedClass()) {
|
||||
// 嵌套类
|
||||
entityInfo.getPathClassMap().putIfAbsent(field.getName(), tableField.nestedClass());
|
||||
processNested(tableField.nestedClass(), dbConfig, entityInfo);
|
||||
entityInfo.getPathClassMap().putIfAbsent(field.getName(), indexField.nestedClass());
|
||||
processNested(indexField.nestedClass(), dbConfig, entityInfo);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -405,8 +414,10 @@ public class EntityInfoHelper {
|
||||
String mappingColumn;
|
||||
FieldType fieldType;
|
||||
// 处理TableField注解
|
||||
IndexField tableField = field.getAnnotation(IndexField.class);
|
||||
if (Objects.isNull(tableField)) {
|
||||
MultiIndexField multiIndexField = field.getAnnotation(MultiIndexField.class);
|
||||
IndexField indexField = Optional.ofNullable(multiIndexField).map(MultiIndexField::mainIndexField)
|
||||
.orElse(field.getAnnotation(IndexField.class));
|
||||
if (Objects.isNull(indexField)) {
|
||||
mappingColumn = getMappingColumn(dbConfig, field);
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field);
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
@ -415,36 +426,41 @@ public class EntityInfoHelper {
|
||||
entityFieldInfo.setColumnType(field.getType().getSimpleName());
|
||||
entityFieldInfoList.add(entityFieldInfo);
|
||||
} else {
|
||||
if (tableField.exist()) {
|
||||
if (indexField.exist()) {
|
||||
// 子嵌套,递归处理
|
||||
if (DefaultNestedClass.class != tableField.nestedClass()) {
|
||||
entityInfo.getPathClassMap().putIfAbsent(field.getName(), tableField.nestedClass());
|
||||
processNested(tableField.nestedClass(), dbConfig, entityInfo);
|
||||
if (DefaultNestedClass.class != indexField.nestedClass()) {
|
||||
entityInfo.getPathClassMap().putIfAbsent(field.getName(), indexField.nestedClass());
|
||||
processNested(indexField.nestedClass(), dbConfig, entityInfo);
|
||||
}
|
||||
|
||||
// 字段名称
|
||||
if (StringUtils.isNotBlank(tableField.value().trim())) {
|
||||
mappingColumn = tableField.value();
|
||||
if (StringUtils.isNotBlank(indexField.value().trim())) {
|
||||
mappingColumn = indexField.value();
|
||||
} else {
|
||||
mappingColumn = getMappingColumn(dbConfig, field);
|
||||
}
|
||||
|
||||
// 设置实体字段信息
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, tableField);
|
||||
fieldType = FieldType.NONE.equals(tableField.fieldType()) ? FieldType.KEYWORD_TEXT : tableField.fieldType();
|
||||
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, indexField);
|
||||
fieldType = FieldType.NONE.equals(indexField.fieldType()) ? FieldType.KEYWORD_TEXT : indexField.fieldType();
|
||||
entityFieldInfo.setMappingColumn(mappingColumn);
|
||||
entityFieldInfo.setFieldType(fieldType);
|
||||
entityFieldInfo.setFieldData(tableField.fieldData());
|
||||
entityFieldInfo.setFieldData(indexField.fieldData());
|
||||
entityFieldInfo.setColumnType(fieldType.getType());
|
||||
entityFieldInfo.setAnalyzer(tableField.analyzer());
|
||||
entityFieldInfo.setSearchAnalyzer(tableField.searchAnalyzer());
|
||||
entityFieldInfo.setAnalyzer(indexField.analyzer());
|
||||
entityFieldInfo.setSearchAnalyzer(indexField.searchAnalyzer());
|
||||
if (FieldType.KEYWORD.equals(fieldType)) {
|
||||
// 仅对keyword类型设置,其它类型es不支持
|
||||
entityFieldInfo.setIgnoreCase(tableField.ignoreCase());
|
||||
entityFieldInfo.setIgnoreCase(indexField.ignoreCase());
|
||||
}
|
||||
if (StringUtils.isNotBlank(tableField.dateFormat())) {
|
||||
entityFieldInfo.setDateFormat(tableField.dateFormat());
|
||||
if (StringUtils.isNotBlank(indexField.dateFormat())) {
|
||||
entityFieldInfo.setDateFormat(indexField.dateFormat());
|
||||
}
|
||||
|
||||
// 处理内部字段
|
||||
InnerIndexField[] innerIndexFields = Optional.ofNullable(multiIndexField).map(MultiIndexField::otherIndexFields).orElse(null);
|
||||
processInnerField(innerIndexFields, entityFieldInfo);
|
||||
|
||||
entityFieldInfoList.add(entityFieldInfo);
|
||||
} else {
|
||||
mappingColumn = getMappingColumn(dbConfig, field);
|
||||
@ -464,6 +480,31 @@ public class EntityInfoHelper {
|
||||
entityInfo.getNestedFieldListMap().put(nestedClass, entityFieldInfoList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理内部字段
|
||||
*
|
||||
* @param innerIndexFields 内部字段注解数组
|
||||
* @param entityFieldInfo 内部字段信息
|
||||
*/
|
||||
private static void processInnerField(InnerIndexField[] innerIndexFields, EntityFieldInfo entityFieldInfo) {
|
||||
if (ArrayUtils.isNotEmpty(innerIndexFields)) {
|
||||
List<EntityFieldInfo.InnerFieldInfo> innerFieldInfoList = new ArrayList<>();
|
||||
Arrays.stream(innerIndexFields).forEach(innerField -> {
|
||||
Assert.notBlank(innerField.suffix(), "The Annotation MultiIndexField.InnerIndexField.value must has text");
|
||||
EntityFieldInfo.InnerFieldInfo innerFieldInfo = new EntityFieldInfo.InnerFieldInfo();
|
||||
innerFieldInfo.setColumn(innerField.suffix());
|
||||
innerFieldInfo.setFieldType(innerField.fieldType());
|
||||
innerFieldInfo.setAnalyzer(innerField.analyzer());
|
||||
innerFieldInfo.setSearchAnalyzer(innerField.searchAnalyzer());
|
||||
if (innerField.ignoreAbove() > 0){
|
||||
innerFieldInfo.setIgnoreAbove(innerField.ignoreAbove());
|
||||
}
|
||||
innerFieldInfoList.add(innerFieldInfo);
|
||||
});
|
||||
entityFieldInfo.setInnerFieldInfoList(innerFieldInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 字段属性初始化
|
||||
@ -617,12 +658,6 @@ public class EntityInfoHelper {
|
||||
entityInfo.setReplicasNum(table.replicasNum());
|
||||
entityInfo.setChild(table.child());
|
||||
entityInfo.setChildClass(table.childClass());
|
||||
|
||||
RefreshPolicy refreshPolicy = table.refreshPolicy();
|
||||
if (RefreshPolicy.GLOBAL.equals(refreshPolicy)) {
|
||||
refreshPolicy = dbConfig.getRefreshPolicy();
|
||||
}
|
||||
entityInfo.setRefreshPolicy(refreshPolicy);
|
||||
}
|
||||
|
||||
String targetIndexName = indexName;
|
||||
|
||||
@ -59,20 +59,14 @@ import static org.dromara.easyes.common.constants.BaseEsConstants.*;
|
||||
public class IndexUtils {
|
||||
|
||||
private static final String FIELDS_KEY;
|
||||
private static final Map<String, Object> FIELDS_MAP;
|
||||
private static final int IGNORE_ABOVE;
|
||||
private static final int DEFAULT_IGNORE_ABOVE;
|
||||
private static final String IGNORE_ABOVE_KEY;
|
||||
|
||||
|
||||
static {
|
||||
FIELDS_MAP = new HashMap<>();
|
||||
FIELDS_KEY = "fields";
|
||||
IGNORE_ABOVE = 256;
|
||||
DEFAULT_IGNORE_ABOVE = 256;
|
||||
IGNORE_ABOVE_KEY = "ignore_above";
|
||||
Map<String, Object> keywordsMap = new HashMap<>();
|
||||
keywordsMap.put(TYPE, FieldType.KEYWORD.getType());
|
||||
keywordsMap.put(IGNORE_ABOVE_KEY, IGNORE_ABOVE);
|
||||
FIELDS_MAP.put(FieldType.KEYWORD.getType(), keywordsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,7 +317,7 @@ public class IndexUtils {
|
||||
return fieldType.getType();
|
||||
}
|
||||
|
||||
// 否则根据类型推断,String以及找不到的类型一律被当做keyword处理
|
||||
// 否则根据类型推断,String以及找不到的类型一律被当做keyword_text复核类型处理
|
||||
JdkDataTypeEnum jdkDataType = JdkDataTypeEnum.getByType(typeName.toLowerCase());
|
||||
String type;
|
||||
switch (jdkDataType) {
|
||||
@ -414,9 +408,17 @@ public class IndexUtils {
|
||||
}
|
||||
|
||||
// 设置type
|
||||
Map<String, Object> fieldsMap = null;
|
||||
if (FieldType.KEYWORD_TEXT.getType().equals(indexParam.getFieldType())) {
|
||||
// 复合类型需特殊处理
|
||||
info.put(BaseEsConstants.TYPE, FieldType.TEXT.getType());
|
||||
info.put(FIELDS_KEY, FIELDS_MAP);
|
||||
fieldsMap = new HashMap<>();
|
||||
Map<String, Object> keywordMap = new HashMap<>();
|
||||
keywordMap.put(TYPE, FieldType.KEYWORD.getType());
|
||||
int ignoreAbove = Optional.ofNullable(indexParam.getIgnoreAbove()).orElse(DEFAULT_IGNORE_ABOVE);
|
||||
keywordMap.put(IGNORE_ABOVE_KEY, ignoreAbove);
|
||||
fieldsMap.put(FieldType.KEYWORD.getType(), keywordMap);
|
||||
info.put(FIELDS_KEY, fieldsMap);
|
||||
} else {
|
||||
info.put(BaseEsConstants.TYPE, indexParam.getFieldType());
|
||||
}
|
||||
@ -427,11 +429,10 @@ public class IndexUtils {
|
||||
if (containsTextType) {
|
||||
// 设置分词器
|
||||
Optional.ofNullable(indexParam.getAnalyzer())
|
||||
.ifPresent(analyzer ->
|
||||
info.put(BaseEsConstants.ANALYZER, indexParam.getAnalyzer().toLowerCase()));
|
||||
.ifPresent(analyzer -> info.put(BaseEsConstants.ANALYZER, analyzer.toLowerCase()));
|
||||
Optional.ofNullable(indexParam.getSearchAnalyzer())
|
||||
.ifPresent(searchAnalyzer ->
|
||||
info.put(BaseEsConstants.SEARCH_ANALYZER, indexParam.getSearchAnalyzer().toLowerCase()));
|
||||
info.put(BaseEsConstants.SEARCH_ANALYZER, searchAnalyzer.toLowerCase()));
|
||||
|
||||
// 设置是否对text类型进行聚合处理
|
||||
MyOptional.ofNullable(indexParam.getFieldData()).ifTrue(fieldData -> info.put(FIELD_DATA, fieldData));
|
||||
@ -462,6 +463,31 @@ public class IndexUtils {
|
||||
if (dbConfig.isMapUnderscoreToCamelCase()) {
|
||||
fieldName = StringUtils.camelToUnderline(fieldName);
|
||||
}
|
||||
|
||||
// 设置内部字段
|
||||
if (CollectionUtils.isNotEmpty(indexParam.getInnerFieldParamList())) {
|
||||
Map<String, Object> finalFieldsMap = Optional.ofNullable(fieldsMap).orElseGet(HashMap::new);
|
||||
indexParam.getInnerFieldParamList().forEach(innerFieldParam -> {
|
||||
Map<String, Object> innerInfo = new HashMap<>();
|
||||
if (FieldType.KEYWORD_TEXT.getType().equals(innerFieldParam.getFieldType())) {
|
||||
ExceptionUtils.eee("The fieldType FieldType.KEYWORD_TEXT just for mainIndexField, can not be used in @InnerIndexField");
|
||||
}
|
||||
innerInfo.put(TYPE, innerFieldParam.getFieldType());
|
||||
boolean innerContainsTextType = FieldType.TEXT.getType().equals(innerFieldParam.getFieldType()) ||
|
||||
FieldType.KEYWORD_TEXT.getType().equals(innerFieldParam.getFieldType());
|
||||
if (innerContainsTextType) {
|
||||
Optional.ofNullable(innerFieldParam.getAnalyzer()).ifPresent(i -> innerInfo.put(ANALYZER, i));
|
||||
Optional.ofNullable(innerFieldParam.getSearchAnalyzer())
|
||||
.ifPresent(i -> innerInfo.put(SEARCH_ANALYZER, i));
|
||||
}
|
||||
Optional.ofNullable(innerFieldParam.getIgnoreAbove())
|
||||
.ifPresent(i -> innerInfo.put(IGNORE_ABOVE_KEY, innerFieldParam.getIgnoreAbove()));
|
||||
finalFieldsMap.putIfAbsent(innerFieldParam.getColumn(), innerInfo);
|
||||
});
|
||||
|
||||
info.put(FIELDS_KEY, finalFieldsMap);
|
||||
}
|
||||
|
||||
properties.put(fieldName, info);
|
||||
});
|
||||
return properties;
|
||||
@ -589,6 +615,25 @@ public class IndexUtils {
|
||||
esIndexParam.setIgnoreCase(field.isIgnoreCase());
|
||||
Optional.ofNullable(field.getParentName()).ifPresent(esIndexParam::setParentName);
|
||||
Optional.ofNullable(field.getChildName()).ifPresent(esIndexParam::setChildName);
|
||||
|
||||
// 内部字段处理
|
||||
final List<EntityFieldInfo.InnerFieldInfo> innerFieldInfoList = field.getInnerFieldInfoList();
|
||||
if (CollectionUtils.isNotEmpty(innerFieldInfoList)) {
|
||||
List<EsIndexParam.InnerFieldParam> innerFieldParamList = new ArrayList<>();
|
||||
innerFieldInfoList.forEach(innerFieldInfo -> {
|
||||
EsIndexParam.InnerFieldParam innerFieldParam = new EsIndexParam.InnerFieldParam();
|
||||
innerFieldParam.setColumn(innerFieldInfo.getColumn());
|
||||
if (!Analyzer.NONE.equals(innerFieldInfo.getAnalyzer())) {
|
||||
innerFieldParam.setAnalyzer(innerFieldInfo.getAnalyzer());
|
||||
}
|
||||
if (!Analyzer.NONE.equals(innerFieldInfo.getSearchAnalyzer())) {
|
||||
innerFieldParam.setSearchAnalyzer(innerFieldInfo.getSearchAnalyzer());
|
||||
}
|
||||
innerFieldParam.setFieldType(innerFieldInfo.getFieldType().getType());
|
||||
innerFieldParamList.add(innerFieldParam);
|
||||
});
|
||||
esIndexParam.setInnerFieldParamList(innerFieldParamList);
|
||||
}
|
||||
esIndexParamList.add(esIndexParam);
|
||||
});
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.dromara.easyes.annotation.*;
|
||||
import org.dromara.easyes.annotation.rely.*;
|
||||
import org.dromara.easyes.annotation.rely.RefreshPolicy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -16,9 +15,7 @@ import java.util.List;
|
||||
**/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2,
|
||||
keepGlobalPrefix = true, childClass = Comment.class, routing = "testRouting",
|
||||
refreshPolicy = RefreshPolicy.IMMEDIATE)
|
||||
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, childClass = Comment.class, routing = "testRouting")
|
||||
public class Document {
|
||||
/**
|
||||
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.
|
||||
@ -126,4 +123,16 @@ public class Document {
|
||||
*/
|
||||
@Distance(decimalPlaces = 2)
|
||||
private Double distance2;
|
||||
|
||||
/**
|
||||
* 复合字段,此注解和SpringData中的MultiField用法类似 适用于对同一个字段通过多种分词器检索的场景
|
||||
*/
|
||||
@MultiIndexField(mainIndexField = @IndexField(fieldType = FieldType.KEYWORD),
|
||||
otherIndexFields = {@InnerIndexField(suffix = "zh", fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART),
|
||||
@InnerIndexField(suffix = "pinyin", fieldType = FieldType.TEXT, analyzer = "pinyin")})
|
||||
private String multiField;
|
||||
/**
|
||||
* 英文名
|
||||
*/
|
||||
private String english;
|
||||
}
|
||||
|
||||
@ -85,6 +85,8 @@ public class AllTest {
|
||||
Rectangle rectangle = new Rectangle(39.084509D, 41.187328D, 70.610461D, 20.498353D);
|
||||
document.setGeoLocation(rectangle.toString());
|
||||
document.setStarNum(1);
|
||||
document.setMultiField("葡萄糖酸钙口服溶液");
|
||||
document.setEnglish("Calcium Gluconate");
|
||||
int successCount = documentMapper.insert(document);
|
||||
Assertions.assertEquals(successCount, 1);
|
||||
|
||||
@ -880,6 +882,21 @@ public class AllTest {
|
||||
Assertions.assertEquals(22, documents.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
public void testMultiFieldSelect() {
|
||||
// 药品 中文名叫葡萄糖酸钙口服溶液 英文名叫 Calcium Gluconate 汉语拼音为 putaotangsuangaikoufurongye
|
||||
// 用户可以通过模糊检索,例如输入 Calcium 或 葡萄糖 或 putaotang时对应药品均可以被检索到
|
||||
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
|
||||
wrapper.match("english", "Calcium")
|
||||
.or()
|
||||
.match("multi_field.zh", "葡萄糖")
|
||||
.or()
|
||||
.match("multi_field.pinyin", "putaotang");
|
||||
List<Document> documents = documentMapper.selectList(wrapper);
|
||||
System.out.println(documents);
|
||||
}
|
||||
|
||||
// 4.删除
|
||||
@Test
|
||||
@Order(7)
|
||||
@ -939,4 +956,5 @@ public class AllTest {
|
||||
documentMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user