diff --git a/easy-es-annotation/pom.xml b/easy-es-annotation/pom.xml index a4acc306..a2ab8645 100644 --- a/easy-es-annotation/pom.xml +++ b/easy-es-annotation/pom.xml @@ -18,10 +18,4 @@ 8 - - - org.projectlombok - lombok - - \ No newline at end of file diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexField.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexField.java index 32bb48cf..de539e9d 100644 --- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexField.java +++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexField.java @@ -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; + /** * 默认嵌套类 * diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexName.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexName.java index 6de3a71a..5414b7f9 100644 --- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexName.java +++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/IndexName.java @@ -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; } diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/InnerIndexField.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/InnerIndexField.java new file mode 100644 index 00000000..1f6b7572 --- /dev/null +++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/InnerIndexField.java @@ -0,0 +1,48 @@ +package org.dromara.easyes.annotation; + + +import org.dromara.easyes.annotation.rely.Analyzer; +import org.dromara.easyes.annotation.rely.FieldType; + +/** + * 内部字段索引注解 + *

+ * + * @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; +} diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/MultiIndexField.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/MultiIndexField.java new file mode 100644 index 00000000..0a6a2c00 --- /dev/null +++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/MultiIndexField.java @@ -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; + +/** + * 多字段索引注解 + *

+ * + * @author yinlei + **/ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface MultiIndexField { + /** + * 主字段信息 + * + * @return 主字段信息 + */ + IndexField mainIndexField(); + + /** + * 内部字段信息 + * + * @return 内部字段信息 + */ + InnerIndexField[] otherIndexFields() default {}; +} diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/FieldType.java b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/FieldType.java index 25c15b73..032cd4a0 100644 --- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/FieldType.java +++ b/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/FieldType.java @@ -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"), /** diff --git a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/RefreshPolicy.java b/easy-es-common/src/main/java/org/dromara/easyes/common/enums/RefreshPolicy.java similarity index 65% rename from easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/RefreshPolicy.java rename to easy-es-common/src/main/java/org/dromara/easyes/common/enums/RefreshPolicy.java index f0dd2292..6ed5680f 100644 --- a/easy-es-annotation/src/main/java/org/dromara/easyes/annotation/rely/RefreshPolicy.java +++ b/easy-es-common/src/main/java/org/dromara/easyes/common/enums/RefreshPolicy.java @@ -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; * 数据刷新策略枚举 *

* 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"), /** diff --git a/easy-es-common/src/main/java/org/dromara/easyes/common/utils/Assert.java b/easy-es-common/src/main/java/org/dromara/easyes/common/utils/Assert.java index 89389d30..55d24594 100644 --- a/easy-es-common/src/main/java/org/dromara/easyes/common/utils/Assert.java +++ b/easy-es-common/src/main/java/org/dromara/easyes/common/utils/Assert.java @@ -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; } + } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityFieldInfo.java b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityFieldInfo.java index 1ef19f41..1e9506da 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityFieldInfo.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityFieldInfo.java @@ -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 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; + } + } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityInfo.java b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityInfo.java index a0915ee5..129c52a1 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityInfo.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EntityInfo.java @@ -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, List> classSimplePropertyPreFilterMap = new HashMap<>(); - private RefreshPolicy refreshPolicy; - /** * 获取需要进行查询的字段列表 * diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexParam.java b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexParam.java index bbd0ba74..ca1d6ebe 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexParam.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/biz/EsIndexParam.java @@ -2,6 +2,8 @@ package org.dromara.easyes.core.biz; import lombok.Data; +import java.util.List; + /** * 索引相关参数 *

@@ -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 innerFieldParamList; + + /** + * 内部段参数 + */ + @Data + public static class InnerFieldParam { + /** + * 内部字段名称 + */ + private String column; + /** + * 内部字段类型 + */ + private String fieldType; + /** + * 内部分词器 + */ + private String analyzer; + /** + * 内部查询分词器 + */ + private String searchAnalyzer; + /** + * 内部字段最大索引长度 + */ + private Integer ignoreAbove; + } } diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/config/GlobalConfig.java b/easy-es-core/src/main/java/org/dromara/easyes/core/config/GlobalConfig.java index c99f4d0c..9d3f1388 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/config/GlobalConfig.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/config/GlobalConfig.java @@ -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; /** diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java b/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java index 3697ef93..6ebf53b2 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/core/BaseEsMapperImpl.java @@ -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 implements BaseEsMapper { && 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 implements BaseEsMapper { * @return 刷新策略 */ private String getRefreshPolicy() { - return EntityInfoHelper.getEntityInfo(entityClass).getRefreshPolicy().getValue(); + return GlobalConfigCache.getGlobalConfig().getDbConfig().getRefreshPolicy().getValue(); } /** diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java index 427ed5bb..5eb8ee9d 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/EntityInfoHelper.java @@ -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 list = getAllFields(clazz); // 标记是否读取到主键 boolean isReadPK = false; - // 是否存在 @TableId 注解 - boolean existTableId = isExistIndexId(list); + // 是否存在 @IndexId 注解 + boolean existsIndexId = isExistIndexId(list); List 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 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 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; diff --git a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java index b923c51e..9be2800f 100644 --- a/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java +++ b/easy-es-core/src/main/java/org/dromara/easyes/core/toolkit/IndexUtils.java @@ -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 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 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 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 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 finalFieldsMap = Optional.ofNullable(fieldsMap).orElseGet(HashMap::new); + indexParam.getInnerFieldParamList().forEach(innerFieldParam -> { + Map 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 innerFieldInfoList = field.getInnerFieldInfoList(); + if (CollectionUtils.isNotEmpty(innerFieldInfoList)) { + List 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); }); } diff --git a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java index 4e43d87d..a129c64d 100644 --- a/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java +++ b/easy-es-test/src/main/java/org/dromara/easyes/test/entity/Document.java @@ -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; } diff --git a/easy-es-test/src/test/java/org/dromara/easyes/test/all/AllTest.java b/easy-es-test/src/test/java/org/dromara/easyes/test/all/AllTest.java index a464c1ad..cc60de82 100644 --- a/easy-es-test/src/test/java/org/dromara/easyes/test/all/AllTest.java +++ b/easy-es-test/src/test/java/org/dromara/easyes/test/all/AllTest.java @@ -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 wrapper = new LambdaEsQueryWrapper<>(); + wrapper.match("english", "Calcium") + .or() + .match("multi_field.zh", "葡萄糖") + .or() + .match("multi_field.pinyin", "putaotang"); + List documents = documentMapper.selectList(wrapper); + System.out.println(documents); + } + // 4.删除 @Test @Order(7) @@ -939,4 +956,5 @@ public class AllTest { documentMapper.selectList(wrapper); } + }