!84 新增@MultiIndexField多字段注解,并完成相关索引创建功能,实现预期效果

Merge pull request !84 from yinlei1006/ospp-2023
This commit is contained in:
elasticsearch 2023-08-09 06:53:39 +00:00 committed by Gitee
commit 6d8e6daa8d
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
17 changed files with 371 additions and 103 deletions

View File

@ -18,10 +18,4 @@
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>8</maven.compiler.target>
</properties> </properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project> </project>

View File

@ -1,7 +1,6 @@
package org.dromara.easyes.annotation; package org.dromara.easyes.annotation;
import org.dromara.easyes.annotation.rely.*; import org.dromara.easyes.annotation.rely.*;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
@ -80,6 +79,13 @@ public @interface IndexField {
*/ */
boolean ignoreCase() default false; boolean ignoreCase() default false;
/**
* 长度超过ignore_above设置的字符串将不会被索引或存储 keyword_text默认值为256
*
* @return 索引字段最大长度
*/
int ignoreAbove() default -1;
/** /**
* 默认嵌套类 * 默认嵌套类
* *

View File

@ -1,7 +1,6 @@
package org.dromara.easyes.annotation; package org.dromara.easyes.annotation;
import org.dromara.easyes.annotation.rely.DefaultChildClass; import org.dromara.easyes.annotation.rely.DefaultChildClass;
import org.dromara.easyes.annotation.rely.RefreshPolicy;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -82,6 +81,4 @@ public @interface IndexName {
* @return CRUD作用的路由 * @return CRUD作用的路由
*/ */
String routing() default ""; String routing() default "";
RefreshPolicy refreshPolicy() default RefreshPolicy.GLOBAL;
} }

View File

@ -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;
}

View File

@ -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 {};
}

View File

@ -29,6 +29,9 @@ public enum FieldType {
BINARY("binary"), BINARY("binary"),
KEYWORD("keyword"), KEYWORD("keyword"),
TEXT("text"), TEXT("text"),
/**
* This type can not be used for @InnerIndexField
*/
KEYWORD_TEXT("keyword&text"), KEYWORD_TEXT("keyword&text"),
WILDCARD("wildcard"), WILDCARD("wildcard"),
/** /**

View File

@ -1,4 +1,4 @@
package org.dromara.easyes.annotation.rely; package org.dromara.easyes.common.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
@ -7,17 +7,11 @@ import lombok.Getter;
* 数据刷新策略枚举 * 数据刷新策略枚举
* <p> * <p>
* Copyright © 2021 xpc1024 All Rights Reserved * Copyright © 2021 xpc1024 All Rights Reserved
*
* @see org.elasticsearch.action.support.WriteRequest.RefreshPolicy
**/ **/
@AllArgsConstructor @AllArgsConstructor
public enum RefreshPolicy { public enum RefreshPolicy {
/** /**
* 使用全局设置: easy-es.global-config.db-config.refresh-policy * 默认不刷新
*/
GLOBAL(""),
/**
* 不立即刷新 (es默认的数据刷新策略)
*/ */
NONE("false"), NONE("false"),
/** /**

View File

@ -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) { private static boolean isEmpty(Object[] array) {
return array == null || array.length == 0; return array == null || array.length == 0;
} }
} }

View File

@ -1,16 +1,17 @@
package org.dromara.easyes.core.biz; 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 com.alibaba.fastjson.serializer.NameFilter;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; 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.lang.reflect.Field;
import java.util.List;
/** /**
* es实体字段信息 * es实体字段信息
@ -47,6 +48,10 @@ public class EntityFieldInfo {
* 字段是否忽略大小写默认不忽略 为true时则忽略大小写 * 字段是否忽略大小写默认不忽略 为true时则忽略大小写
*/ */
private boolean ignoreCase; private boolean ignoreCase;
/**
* 字段最大索引长度
*/
private Integer ignoreAbove;
/** /**
* 分词器 * 分词器
*/ */
@ -86,6 +91,11 @@ public class EntityFieldInfo {
private String sqlSelect; private String sqlSelect;
private NameFilter nameFilter; private NameFilter nameFilter;
/**
* 内部字段列表
*/
private List<InnerFieldInfo> innerFieldInfoList;
/** /**
* 存在 TableField 注解时, 使用的构造函数 * 存在 TableField 注解时, 使用的构造函数
* *
@ -95,7 +105,6 @@ public class EntityFieldInfo {
*/ */
public EntityFieldInfo(GlobalConfig.DbConfig dbConfig, Field field, IndexField tableField) { public EntityFieldInfo(GlobalConfig.DbConfig dbConfig, Field field, IndexField tableField) {
this.column = field.getName(); this.column = field.getName();
// 优先使用单个字段注解否则使用全局配置 // 优先使用单个字段注解否则使用全局配置
if (tableField.strategy() == FieldStrategy.DEFAULT) { if (tableField.strategy() == FieldStrategy.DEFAULT) {
this.fieldStrategy = dbConfig.getFieldStrategy(); this.fieldStrategy = dbConfig.getFieldStrategy();
@ -115,4 +124,31 @@ public class EntityFieldInfo {
this.column = field.getName(); this.column = field.getName();
} }
/**
* 内部字段
*/
@Data
public static class InnerFieldInfo {
/**
* 内部字段名
*/
private String column;
/**
* 内部字段类型
*/
private FieldType fieldType;
/**
* 内部字段分词器
*/
private String analyzer;
/**
* 内部字段查询分词器
*/
private String searchAnalyzer;
/**
* 字段最大索引长度
*/
private Integer ignoreAbove;
}
} }

View File

@ -8,7 +8,6 @@ import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.serializer.SerializeFilter; import com.alibaba.fastjson.serializer.SerializeFilter;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.dromara.easyes.annotation.rely.RefreshPolicy;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.*; import java.util.*;
@ -178,8 +177,6 @@ public class EntityInfo {
*/ */
private final Map<Class<?>, List<SerializeFilter>> classSimplePropertyPreFilterMap = new HashMap<>(); private final Map<Class<?>, List<SerializeFilter>> classSimplePropertyPreFilterMap = new HashMap<>();
private RefreshPolicy refreshPolicy;
/** /**
* 获取需要进行查询的字段列表 * 获取需要进行查询的字段列表
* *

View File

@ -2,6 +2,8 @@ package org.dromara.easyes.core.biz;
import lombok.Data; import lombok.Data;
import java.util.List;
/** /**
* 索引相关参数 * 索引相关参数
* <p> * <p>
@ -45,6 +47,10 @@ public class EsIndexParam {
* 字段是否忽略大小写默认不忽略 为true时则忽略大小写 * 字段是否忽略大小写默认不忽略 为true时则忽略大小写
*/ */
private boolean ignoreCase; private boolean ignoreCase;
/**
* 字段最大索引长度 默认256
*/
private Integer ignoreAbove;
/** /**
* 父名称 * 父名称
*/ */
@ -53,4 +59,35 @@ public class EsIndexParam {
* 子名称 * 子名称
*/ */
private String childName; 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;
}
} }

View File

@ -5,7 +5,7 @@ import lombok.Data;
import org.dromara.easyes.annotation.rely.FieldStrategy; import org.dromara.easyes.annotation.rely.FieldStrategy;
import org.dromara.easyes.annotation.rely.IdType; import org.dromara.easyes.annotation.rely.IdType;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum; 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 org.springframework.boot.context.properties.NestedConfigurationProperty;
import static org.dromara.easyes.common.constants.BaseEsConstants.EMPTY_STR; import static org.dromara.easyes.common.constants.BaseEsConstants.EMPTY_STR;
@ -79,7 +79,7 @@ public class GlobalConfig {
*/ */
private boolean enableTrackTotalHits = true; private boolean enableTrackTotalHits = true;
/** /**
* data refresh policy 数据刷新策略,es默认的数据刷新策略为NONE * data refresh policy 数据刷新策略,默认为NONE
*/ */
private RefreshPolicy refreshPolicy = RefreshPolicy.NONE; private RefreshPolicy refreshPolicy = RefreshPolicy.NONE;
/** /**

View File

@ -13,7 +13,7 @@ import org.dromara.easyes.annotation.rely.IdType;
import org.dromara.easyes.common.constants.BaseEsConstants; import org.dromara.easyes.common.constants.BaseEsConstants;
import org.dromara.easyes.common.enums.EsQueryTypeEnum; import org.dromara.easyes.common.enums.EsQueryTypeEnum;
import org.dromara.easyes.common.enums.MethodEnum; 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.common.utils.*;
import org.dromara.easyes.core.biz.*; import org.dromara.easyes.core.biz.*;
import org.dromara.easyes.core.cache.BaseCache; import org.dromara.easyes.core.cache.BaseCache;
@ -1485,7 +1485,7 @@ public class BaseEsMapperImpl<T> implements BaseEsMapper<T> {
&& searchResponse.getShardFailures() != null && searchResponse.getShardFailures() != null
&& searchResponse.getShardFailures().length > ZERO) { && searchResponse.getShardFailures().length > ZERO) {
String errorMsg = searchResponse.getShardFailures()[0].toString(); 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 刷新策略 * @return 刷新策略
*/ */
private String getRefreshPolicy() { private String getRefreshPolicy() {
return EntityInfoHelper.getEntityInfo(entityClass).getRefreshPolicy().getValue(); return GlobalConfigCache.getGlobalConfig().getDbConfig().getRefreshPolicy().getValue();
} }
/** /**

View File

@ -8,11 +8,7 @@ import org.dromara.easyes.annotation.*;
import org.dromara.easyes.annotation.rely.DefaultNestedClass; import org.dromara.easyes.annotation.rely.DefaultNestedClass;
import org.dromara.easyes.annotation.rely.FieldType; import org.dromara.easyes.annotation.rely.FieldType;
import org.dromara.easyes.annotation.rely.IdType; import org.dromara.easyes.annotation.rely.IdType;
import org.dromara.easyes.annotation.rely.RefreshPolicy; import org.dromara.easyes.common.utils.*;
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.core.biz.EntityFieldInfo; import org.dromara.easyes.core.biz.EntityFieldInfo;
import org.dromara.easyes.core.biz.EntityInfo; import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.HighLightParam; import org.dromara.easyes.core.biz.HighLightParam;
@ -106,14 +102,14 @@ public class EntityInfoHelper {
List<Field> list = getAllFields(clazz); List<Field> list = getAllFields(clazz);
// 标记是否读取到主键 // 标记是否读取到主键
boolean isReadPK = false; boolean isReadPK = false;
// 是否存在 @TableId 注解 // 是否存在 @IndexId 注解
boolean existTableId = isExistIndexId(list); boolean existsIndexId = isExistIndexId(list);
List<EntityFieldInfo> fieldList = new ArrayList<>(); List<EntityFieldInfo> fieldList = new ArrayList<>();
for (Field field : list) { for (Field field : list) {
// 主键ID 初始化 // 主键ID 初始化
if (!isReadPK) { if (!isReadPK) {
if (existTableId) { if (existsIndexId) {
isReadPK = initIndexIdWithAnnotation(dbConfig, entityInfo, field); isReadPK = initIndexIdWithAnnotation(dbConfig, entityInfo, field);
} else { } else {
isReadPK = initIndexIdWithoutAnnotation(dbConfig, entityInfo, field); isReadPK = initIndexIdWithoutAnnotation(dbConfig, entityInfo, field);
@ -252,8 +248,8 @@ public class EntityInfoHelper {
Field field, EntityInfo entityInfo) { Field field, EntityInfo entityInfo) {
boolean hasAnnotation = false; boolean hasAnnotation = false;
// 初始化封装IndexField注解信息 // 初始化封装IndexField及MultiIndexField注解信息
if (field.isAnnotationPresent(IndexField.class)) { if (field.isAnnotationPresent(IndexField.class) || field.isAnnotationPresent(MultiIndexField.class)) {
initIndexFieldAnnotation(dbConfig, entityInfo, field, fieldList); initIndexFieldAnnotation(dbConfig, entityInfo, field, fieldList);
hasAnnotation = true; hasAnnotation = true;
} }
@ -294,60 +290,73 @@ public class EntityInfoHelper {
*/ */
private static void initIndexFieldAnnotation(GlobalConfig.DbConfig dbConfig, EntityInfo entityInfo, private static void initIndexFieldAnnotation(GlobalConfig.DbConfig dbConfig, EntityInfo entityInfo,
Field field, List<EntityFieldInfo> fieldList) { Field field, List<EntityFieldInfo> fieldList) {
IndexField tableField = field.getAnnotation(IndexField.class); MultiIndexField multiIndexField = field.getAnnotation(MultiIndexField.class);
if (tableField.exist()) { 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; String mappingColumn;
if (!StringUtils.isBlank(tableField.value().trim())) { if (!StringUtils.isBlank(indexField.value().trim())) {
// 自定义注解指定的名称优先级最高 // 自定义注解指定的名称优先级最高
entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), tableField.value()); entityInfo.getMappingColumnMap().putIfAbsent(field.getName(), indexField.value());
entityInfo.getColumnMappingMap().putIfAbsent(tableField.value(), field.getName()); entityInfo.getColumnMappingMap().putIfAbsent(indexField.value(), field.getName());
mappingColumn = tableField.value(); mappingColumn = indexField.value();
} else { } else {
// 下划线驼峰 // 下划线驼峰
mappingColumn = initMappingColumnMapAndGet(dbConfig, entityInfo, field); mappingColumn = initMappingColumnMapAndGet(dbConfig, entityInfo, field);
} }
// 日期格式化 // 日期格式化
if (StringUtils.isNotBlank(tableField.dateFormat())) { if (StringUtils.isNotBlank(indexField.dateFormat())) {
entityFieldInfo.setDateFormat(tableField.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)) { if (FieldType.KEYWORD.equals(fieldType)) {
// 仅对keyword类型设置,其它类型es不支持 // 仅对keyword类型设置,其它类型es不支持
entityFieldInfo.setIgnoreCase(tableField.ignoreCase()); entityFieldInfo.setIgnoreCase(indexField.ignoreCase());
} }
// 最大索引长度
if (indexField.ignoreAbove() > ZERO) {
entityFieldInfo.setIgnoreAbove(indexField.ignoreAbove());
}
// 其它 // 其它
entityFieldInfo.setMappingColumn(mappingColumn); entityFieldInfo.setMappingColumn(mappingColumn);
entityFieldInfo.setAnalyzer(tableField.analyzer()); entityFieldInfo.setAnalyzer(indexField.analyzer());
entityFieldInfo.setSearchAnalyzer(tableField.searchAnalyzer()); entityFieldInfo.setSearchAnalyzer(indexField.searchAnalyzer());
entityFieldInfo.setFieldType(fieldType); entityFieldInfo.setFieldType(fieldType);
entityFieldInfo.setFieldData(tableField.fieldData()); entityFieldInfo.setFieldData(indexField.fieldData());
entityFieldInfo.setColumnType(field.getType().getSimpleName()); entityFieldInfo.setColumnType(field.getType().getSimpleName());
entityInfo.getFieldTypeMap().putIfAbsent(field.getName(), fieldType.getType()); entityInfo.getFieldTypeMap().putIfAbsent(field.getName(), fieldType.getType());
// 父子类型 // 父子类型
if (FieldType.JOIN.equals(tableField.fieldType())) { if (FieldType.JOIN.equals(indexField.fieldType())) {
entityFieldInfo.setParentName(tableField.parentName()); entityFieldInfo.setParentName(indexField.parentName());
entityFieldInfo.setChildName(tableField.childName()); entityFieldInfo.setChildName(indexField.childName());
entityInfo.setJoinFieldName(mappingColumn); entityInfo.setJoinFieldName(mappingColumn);
entityInfo.setJoinFieldClass(tableField.joinFieldClass()); entityInfo.setJoinFieldClass(indexField.joinFieldClass());
entityInfo.getPathClassMap().putIfAbsent(field.getName(), tableField.joinFieldClass()); entityInfo.getPathClassMap().putIfAbsent(field.getName(), indexField.joinFieldClass());
processNested(tableField.joinFieldClass(), dbConfig, entityInfo); processNested(indexField.joinFieldClass(), dbConfig, entityInfo);
} }
// 处理内部字段
InnerIndexField[] innerIndexFields = Optional.ofNullable(multiIndexField).map(MultiIndexField::otherIndexFields).orElse(null);
processInnerField(innerIndexFields, entityFieldInfo);
fieldList.add(entityFieldInfo); fieldList.add(entityFieldInfo);
// 嵌套类处理 // 嵌套类处理
if (DefaultNestedClass.class != tableField.nestedClass()) { if (DefaultNestedClass.class != indexField.nestedClass()) {
// 嵌套类 // 嵌套类
entityInfo.getPathClassMap().putIfAbsent(field.getName(), tableField.nestedClass()); entityInfo.getPathClassMap().putIfAbsent(field.getName(), indexField.nestedClass());
processNested(tableField.nestedClass(), dbConfig, entityInfo); processNested(indexField.nestedClass(), dbConfig, entityInfo);
} }
} else { } else {
@ -405,8 +414,10 @@ public class EntityInfoHelper {
String mappingColumn; String mappingColumn;
FieldType fieldType; FieldType fieldType;
// 处理TableField注解 // 处理TableField注解
IndexField tableField = field.getAnnotation(IndexField.class); MultiIndexField multiIndexField = field.getAnnotation(MultiIndexField.class);
if (Objects.isNull(tableField)) { IndexField indexField = Optional.ofNullable(multiIndexField).map(MultiIndexField::mainIndexField)
.orElse(field.getAnnotation(IndexField.class));
if (Objects.isNull(indexField)) {
mappingColumn = getMappingColumn(dbConfig, field); mappingColumn = getMappingColumn(dbConfig, field);
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field); EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field);
entityFieldInfo.setMappingColumn(mappingColumn); entityFieldInfo.setMappingColumn(mappingColumn);
@ -415,36 +426,41 @@ public class EntityInfoHelper {
entityFieldInfo.setColumnType(field.getType().getSimpleName()); entityFieldInfo.setColumnType(field.getType().getSimpleName());
entityFieldInfoList.add(entityFieldInfo); entityFieldInfoList.add(entityFieldInfo);
} else { } else {
if (tableField.exist()) { if (indexField.exist()) {
// 子嵌套,递归处理 // 子嵌套,递归处理
if (DefaultNestedClass.class != tableField.nestedClass()) { if (DefaultNestedClass.class != indexField.nestedClass()) {
entityInfo.getPathClassMap().putIfAbsent(field.getName(), tableField.nestedClass()); entityInfo.getPathClassMap().putIfAbsent(field.getName(), indexField.nestedClass());
processNested(tableField.nestedClass(), dbConfig, entityInfo); processNested(indexField.nestedClass(), dbConfig, entityInfo);
} }
// 字段名称 // 字段名称
if (StringUtils.isNotBlank(tableField.value().trim())) { if (StringUtils.isNotBlank(indexField.value().trim())) {
mappingColumn = tableField.value(); mappingColumn = indexField.value();
} else { } else {
mappingColumn = getMappingColumn(dbConfig, field); mappingColumn = getMappingColumn(dbConfig, field);
} }
// 设置实体字段信息 // 设置实体字段信息
EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, tableField); EntityFieldInfo entityFieldInfo = new EntityFieldInfo(dbConfig, field, indexField);
fieldType = FieldType.NONE.equals(tableField.fieldType()) ? FieldType.KEYWORD_TEXT : tableField.fieldType(); fieldType = FieldType.NONE.equals(indexField.fieldType()) ? FieldType.KEYWORD_TEXT : indexField.fieldType();
entityFieldInfo.setMappingColumn(mappingColumn); entityFieldInfo.setMappingColumn(mappingColumn);
entityFieldInfo.setFieldType(fieldType); entityFieldInfo.setFieldType(fieldType);
entityFieldInfo.setFieldData(tableField.fieldData()); entityFieldInfo.setFieldData(indexField.fieldData());
entityFieldInfo.setColumnType(fieldType.getType()); entityFieldInfo.setColumnType(fieldType.getType());
entityFieldInfo.setAnalyzer(tableField.analyzer()); entityFieldInfo.setAnalyzer(indexField.analyzer());
entityFieldInfo.setSearchAnalyzer(tableField.searchAnalyzer()); entityFieldInfo.setSearchAnalyzer(indexField.searchAnalyzer());
if (FieldType.KEYWORD.equals(fieldType)) { if (FieldType.KEYWORD.equals(fieldType)) {
// 仅对keyword类型设置,其它类型es不支持 // 仅对keyword类型设置,其它类型es不支持
entityFieldInfo.setIgnoreCase(tableField.ignoreCase()); entityFieldInfo.setIgnoreCase(indexField.ignoreCase());
} }
if (StringUtils.isNotBlank(tableField.dateFormat())) { if (StringUtils.isNotBlank(indexField.dateFormat())) {
entityFieldInfo.setDateFormat(tableField.dateFormat()); entityFieldInfo.setDateFormat(indexField.dateFormat());
} }
// 处理内部字段
InnerIndexField[] innerIndexFields = Optional.ofNullable(multiIndexField).map(MultiIndexField::otherIndexFields).orElse(null);
processInnerField(innerIndexFields, entityFieldInfo);
entityFieldInfoList.add(entityFieldInfo); entityFieldInfoList.add(entityFieldInfo);
} else { } else {
mappingColumn = getMappingColumn(dbConfig, field); mappingColumn = getMappingColumn(dbConfig, field);
@ -464,6 +480,31 @@ public class EntityInfoHelper {
entityInfo.getNestedFieldListMap().put(nestedClass, entityFieldInfoList); 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.setReplicasNum(table.replicasNum());
entityInfo.setChild(table.child()); entityInfo.setChild(table.child());
entityInfo.setChildClass(table.childClass()); entityInfo.setChildClass(table.childClass());
RefreshPolicy refreshPolicy = table.refreshPolicy();
if (RefreshPolicy.GLOBAL.equals(refreshPolicy)) {
refreshPolicy = dbConfig.getRefreshPolicy();
}
entityInfo.setRefreshPolicy(refreshPolicy);
} }
String targetIndexName = indexName; String targetIndexName = indexName;

View File

@ -59,20 +59,14 @@ import static org.dromara.easyes.common.constants.BaseEsConstants.*;
public class IndexUtils { public class IndexUtils {
private static final String FIELDS_KEY; private static final String FIELDS_KEY;
private static final Map<String, Object> FIELDS_MAP; private static final int DEFAULT_IGNORE_ABOVE;
private static final int IGNORE_ABOVE;
private static final String IGNORE_ABOVE_KEY; private static final String IGNORE_ABOVE_KEY;
static { static {
FIELDS_MAP = new HashMap<>();
FIELDS_KEY = "fields"; FIELDS_KEY = "fields";
IGNORE_ABOVE = 256; DEFAULT_IGNORE_ABOVE = 256;
IGNORE_ABOVE_KEY = "ignore_above"; 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(); return fieldType.getType();
} }
// 否则根据类型推断,String以及找不到的类型一律被当做keyword处理 // 否则根据类型推断,String以及找不到的类型一律被当做keyword_text复核类型处理
JdkDataTypeEnum jdkDataType = JdkDataTypeEnum.getByType(typeName.toLowerCase()); JdkDataTypeEnum jdkDataType = JdkDataTypeEnum.getByType(typeName.toLowerCase());
String type; String type;
switch (jdkDataType) { switch (jdkDataType) {
@ -414,9 +408,17 @@ public class IndexUtils {
} }
// 设置type // 设置type
Map<String, Object> fieldsMap = null;
if (FieldType.KEYWORD_TEXT.getType().equals(indexParam.getFieldType())) { if (FieldType.KEYWORD_TEXT.getType().equals(indexParam.getFieldType())) {
// 复合类型需特殊处理
info.put(BaseEsConstants.TYPE, FieldType.TEXT.getType()); 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 { } else {
info.put(BaseEsConstants.TYPE, indexParam.getFieldType()); info.put(BaseEsConstants.TYPE, indexParam.getFieldType());
} }
@ -427,11 +429,10 @@ public class IndexUtils {
if (containsTextType) { if (containsTextType) {
// 设置分词器 // 设置分词器
Optional.ofNullable(indexParam.getAnalyzer()) Optional.ofNullable(indexParam.getAnalyzer())
.ifPresent(analyzer -> .ifPresent(analyzer -> info.put(BaseEsConstants.ANALYZER, analyzer.toLowerCase()));
info.put(BaseEsConstants.ANALYZER, indexParam.getAnalyzer().toLowerCase()));
Optional.ofNullable(indexParam.getSearchAnalyzer()) Optional.ofNullable(indexParam.getSearchAnalyzer())
.ifPresent(searchAnalyzer -> .ifPresent(searchAnalyzer ->
info.put(BaseEsConstants.SEARCH_ANALYZER, indexParam.getSearchAnalyzer().toLowerCase())); info.put(BaseEsConstants.SEARCH_ANALYZER, searchAnalyzer.toLowerCase()));
// 设置是否对text类型进行聚合处理 // 设置是否对text类型进行聚合处理
MyOptional.ofNullable(indexParam.getFieldData()).ifTrue(fieldData -> info.put(FIELD_DATA, fieldData)); MyOptional.ofNullable(indexParam.getFieldData()).ifTrue(fieldData -> info.put(FIELD_DATA, fieldData));
@ -462,6 +463,31 @@ public class IndexUtils {
if (dbConfig.isMapUnderscoreToCamelCase()) { if (dbConfig.isMapUnderscoreToCamelCase()) {
fieldName = StringUtils.camelToUnderline(fieldName); 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); properties.put(fieldName, info);
}); });
return properties; return properties;
@ -589,6 +615,25 @@ public class IndexUtils {
esIndexParam.setIgnoreCase(field.isIgnoreCase()); esIndexParam.setIgnoreCase(field.isIgnoreCase());
Optional.ofNullable(field.getParentName()).ifPresent(esIndexParam::setParentName); Optional.ofNullable(field.getParentName()).ifPresent(esIndexParam::setParentName);
Optional.ofNullable(field.getChildName()).ifPresent(esIndexParam::setChildName); 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); esIndexParamList.add(esIndexParam);
}); });
} }

View File

@ -5,7 +5,6 @@ import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.dromara.easyes.annotation.*; import org.dromara.easyes.annotation.*;
import org.dromara.easyes.annotation.rely.*; import org.dromara.easyes.annotation.rely.*;
import org.dromara.easyes.annotation.rely.RefreshPolicy;
import java.util.List; import java.util.List;
@ -16,9 +15,7 @@ import java.util.List;
**/ **/
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
@IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, @IndexName(value = "easyes_document", shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true, childClass = Comment.class, routing = "testRouting")
keepGlobalPrefix = true, childClass = Comment.class, routing = "testRouting",
refreshPolicy = RefreshPolicy.IMMEDIATE)
public class Document { public class Document {
/** /**
* es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等. * es中的唯一id,字段名随便起,我这里演示用esId,你也可以用id(推荐),bizId等.
@ -126,4 +123,16 @@ public class Document {
*/ */
@Distance(decimalPlaces = 2) @Distance(decimalPlaces = 2)
private Double distance2; 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;
} }

View File

@ -85,6 +85,8 @@ public class AllTest {
Rectangle rectangle = new Rectangle(39.084509D, 41.187328D, 70.610461D, 20.498353D); Rectangle rectangle = new Rectangle(39.084509D, 41.187328D, 70.610461D, 20.498353D);
document.setGeoLocation(rectangle.toString()); document.setGeoLocation(rectangle.toString());
document.setStarNum(1); document.setStarNum(1);
document.setMultiField("葡萄糖酸钙口服溶液");
document.setEnglish("Calcium Gluconate");
int successCount = documentMapper.insert(document); int successCount = documentMapper.insert(document);
Assertions.assertEquals(successCount, 1); Assertions.assertEquals(successCount, 1);
@ -880,6 +882,21 @@ public class AllTest {
Assertions.assertEquals(22, documents.size()); 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.删除 // 4.删除
@Test @Test
@Order(7) @Order(7)
@ -939,4 +956,5 @@ public class AllTest {
documentMapper.selectList(wrapper); documentMapper.selectList(wrapper);
} }
} }