├── src └── main │ ├── resources │ └── META-INF │ │ └── spring.factories │ └── java │ └── com │ └── elastic │ └── search │ ├── elasticsearch │ ├── search │ │ ├── index │ │ │ ├── AnalyzedType.java │ │ │ ├── Option.java │ │ │ ├── TermVector.java │ │ │ ├── Field.java │ │ │ ├── DataType.java │ │ │ ├── IndexStruct.java │ │ │ └── ScanDocuments.java │ │ ├── log │ │ │ └── SearchLogger.java │ │ ├── api │ │ │ └── SearchService.java │ │ └── utils │ │ │ └── ModifyIndexFactory.java │ ├── dataobject │ │ ├── enums │ │ │ ├── SortEnum.java │ │ │ ├── OperateTypeEnum.java │ │ │ ├── SqlFunctionEnum.java │ │ │ └── ConditionExpressionEnum.java │ │ ├── ESDocument.java │ │ ├── BatchDeleteESObject.java │ │ ├── BatchSaveESObject.java │ │ ├── ConditionUpdateESObject.java │ │ ├── conditions │ │ │ ├── HavingCondition.java │ │ │ ├── OrderCondition.java │ │ │ ├── PageCondition.java │ │ │ ├── FunctionCondition.java │ │ │ ├── GroupByCondition.java │ │ │ └── InnerHitsCondition.java │ │ ├── ConditionDeleteESObject.java │ │ ├── BatchUpdateESObject.java │ │ ├── DeleteESObject.java │ │ ├── BaseESObject.java │ │ ├── StatisticESObject.java │ │ ├── ESResponse.java │ │ ├── UpdateESObject.java │ │ ├── NestedESObject.java │ │ ├── SaveESObject.java │ │ └── CollapseQueryObject.java │ ├── infrastructure │ │ ├── constants │ │ │ └── TypeIndexConstants.java │ │ ├── annotation │ │ │ ├── EsObject.java │ │ │ ├── Cascades.java │ │ │ └── Cascade.java │ │ ├── executor │ │ │ ├── SearchExecutor.java │ │ │ └── impl │ │ │ │ ├── BaseSearchTypeIndexModifyExecutor.java │ │ │ │ └── BaseSearchSaveExecutor.java │ │ ├── enums │ │ │ └── FieldTypeEnum.java │ │ ├── utils │ │ │ ├── PageConditionUtils.java │ │ │ └── OrderConditionUtils.java │ │ ├── consts │ │ │ └── FrameworkExceptionConstants.java │ │ ├── handler │ │ │ ├── ESStatisticResponseHandler.java │ │ │ └── CollapseResponseHandler.java │ │ ├── bean │ │ │ └── Field.java │ │ └── conf │ │ │ └── BaseTypeIndexConfiguration.java │ ├── serialize │ │ ├── SerializeApi.java │ │ ├── bytes │ │ │ ├── SerializeByteApi.java │ │ │ ├── JDKSerialize.java │ │ │ └── KryoSerialize.java │ │ └── api │ │ │ ├── json │ │ │ ├── parser │ │ │ │ ├── LongType.java │ │ │ │ ├── DateTimeType.java │ │ │ │ ├── YmdDateType.java │ │ │ │ ├── GMTDateTimeType.java │ │ │ │ └── ParserDateFactory.java │ │ │ ├── SerializeJsonApi.java │ │ │ ├── GsonSerialize.java │ │ │ ├── SerializeJsonFactory.java │ │ │ ├── DateDeserializer.java │ │ │ └── JacksonSerialize.java │ │ │ └── xml │ │ │ ├── SerializeXml.java │ │ │ └── XStreamAlias.java │ ├── evo │ │ ├── ESClient.java │ │ ├── ESQueryBuilder.java │ │ ├── ESBoolQueryBuilder.java │ │ └── ESSearchRequestBuilder.java │ ├── validator │ │ ├── ESDeleteValidator.java │ │ ├── ESQueryValidator.java │ │ ├── ESUpdateValidator.java │ │ ├── ESSaveValidator.java │ │ ├── ESConditionUpdateValidator.java │ │ ├── ESConditionDeleteValidator.java │ │ ├── ESBatchDeleteValidator.java │ │ ├── BaseValidator.java │ │ ├── ESBatchSaveValidator.java │ │ ├── ESBatchUpdateValidator.java │ │ ├── StatisticByConditionsValidator.java │ │ ├── CollapseQueryValidator.java │ │ └── BaseUpdateValidator.java │ ├── condition │ │ ├── RelationConditionBuilder.java │ │ ├── CollapseConditionBuilder.java │ │ ├── QueryConditionBuilder.java │ │ ├── SearchSourceBuilder.java │ │ └── GroupConditionBuilder.java │ ├── searchservice │ │ ├── ESStatisticService.java │ │ ├── ESStatisticServiceImpl.java │ │ └── ESSearchService.java │ ├── config │ │ ├── IndexHelper.java │ │ ├── IndexUtils.java │ │ ├── IndexAdmin.java │ │ └── CanalBean.java │ └── convert │ │ └── ESSearchConvertor.java │ ├── common │ ├── exception │ │ ├── RpcException.java │ │ ├── SearchBusinessException.java │ │ ├── OpenSystemException.java │ │ ├── ExceptionFactory.java │ │ ├── SystemException.java │ │ ├── FrameworkException.java │ │ ├── BusinessException.java │ │ ├── ErrorCode.java │ │ └── StatusDefinition.java │ ├── utils │ │ ├── ListUtils.java │ │ ├── EmptyUtils.java │ │ └── Ognl.java │ ├── domain │ │ ├── GlobalConstant.java │ │ ├── ESErrorCode.java │ │ ├── BaseResult.java │ │ ├── Status.java │ │ ├── PagedList.java │ │ └── SystemManager.java │ └── boot │ │ └── SearchBeanContext.java │ ├── starter │ └── EtcElasticSearchProperties.java │ └── listener │ └── SpringBootEnvironmentListener.java ├── .gitignore └── pom.xml /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.elastic.search.starter.ElasticSearchStarter -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/AnalyzedType.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | public enum AnalyzedType { 4 | 5 | // 分词 6 | ANALYZED, 7 | // 不分词 8 | NOT_ANALYZED, 9 | // 设置成no,字段将不会被索引 10 | NO; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/enums/SortEnum.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.enums; 2 | 3 | /** 4 | *

5 | * 排序条件枚举 6 | * 7 | * @author niuzhiwei 8 | */ 9 | public enum SortEnum { 10 | 11 | ASC(), DESC(); 12 | 13 | SortEnum() { 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/enums/OperateTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.enums; 2 | 3 | /** 4 | *

5 | * 操作类型 增删改 6 | * 7 | * @author niuzhiwei 8 | */ 9 | public enum OperateTypeEnum { 10 | ADD, DELETE, UPDATE; 11 | 12 | OperateTypeEnum() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/enums/SqlFunctionEnum.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.enums; 2 | 3 | /** 4 | *

5 | * es 组合函数 6 | * 7 | * @author niuzhiwei 8 | */ 9 | public enum SqlFunctionEnum { 10 | SUM, AVG, MIN, MAX, COUNT; 11 | 12 | SqlFunctionEnum() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/constants/TypeIndexConstants.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.constants; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class TypeIndexConstants { 7 | /** 8 | * 系统名 9 | */ 10 | public static final String SYSTEM_NAME = "search"; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/Option.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | public enum Option { 4 | // 分词字段默认是position,其他的默认是docs 5 | // 索引文档号 6 | docs, 7 | // 文档号+词频 8 | freqs, 9 | // 文档号+词频+位置,通常用来距离查询 10 | positions, 11 | // 文档号+词频+位置+偏移量,通常被使用在高亮字段 12 | offsets 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/annotation/EsObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | @Target(ElementType.FIELD) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface EsObject { 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/annotation/Cascades.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @author niuzhiwei 7 | */ 8 | @Target({ElementType.TYPE}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | @Inherited 12 | public @interface Cascades { 13 | 14 | Cascade[] value(); 15 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/TermVector.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | public enum TermVector { 4 | // 默认不存储向量信息, 5 | no, 6 | // 支持term存储 7 | yes, 8 | // term+位置 9 | with_positions, 10 | // (term+偏移量) 11 | with_offsets, 12 | // term+位置+偏移量 对快速高亮fast vector 13 | with_positions_offsets, 14 | // highlighter能提升性能,但开启又会加大索引体积,不适合大数据量用 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/executor/SearchExecutor.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.executor; 2 | 3 | 4 | import com.elastic.search.elasticsearch.infrastructure.conf.BaseTypeIndexConfiguration; 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | public interface SearchExecutor { 10 | 11 | /** 12 | * 获取索引配置 13 | * 14 | * @return 15 | */ 16 | BaseTypeIndexConfiguration getConfig(); 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | *.classpath 10 | *.factorypath 11 | *.project 12 | *.iml 13 | 14 | # Mobile Tools for Java (J2ME) 15 | .mtj.tmp/ 16 | 17 | # Package Files # 18 | *.jar 19 | *.war 20 | *.nar 21 | *.ear 22 | *.zip 23 | *.tar.gz 24 | *.rar 25 | 26 | 27 | #失效目录 28 | target/ 29 | .settings/ 30 | .idea/ 31 | 32 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 33 | hs_err_pid* 34 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/RpcException.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * RPC 调用异常类,例如A服务 调用->B服务时,如果B服务返回消息为非成功状态时, 5 | * 抛出这类异常,这类异常在DataResult中不会增加当前系统的系统编码。 6 | * 7 | * @author niuzhiwei 8 | */ 9 | public class RpcException extends SystemException { 10 | 11 | private static final long serialVersionUID = -8747374925065155821L; 12 | 13 | public RpcException(int errorCode, String errorReason) { 14 | super(errorCode, errorReason); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/SerializeApi.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public interface SerializeApi { 7 | /** 8 | * 序列化API 9 | * 10 | * @param t 11 | * @return 12 | */ 13 | public R encode(Object t); 14 | 15 | /** 16 | * 反序列化API 17 | * 18 | * @param data 19 | * @param type 20 | * @return 21 | */ 22 | public T decode(R data, Class type); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/utils/ListUtils.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.utils; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author niuzhiwei 7 | */ 8 | public class ListUtils { 9 | 10 | public ListUtils() { 11 | } 12 | 13 | public static synchronized Boolean isBlank(List list) { 14 | return null == list || list.size() == 0; 15 | } 16 | 17 | public static synchronized Boolean isNotBlank(List list) { 18 | return null != list && list.size() != 0; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/evo/ESClient.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.evo; 2 | 3 | import org.elasticsearch.client.transport.TransportClient; 4 | 5 | import javax.annotation.Resource; 6 | 7 | /** 8 | * @author niuzhiwei 9 | */ 10 | public class ESClient { 11 | 12 | @Resource 13 | private TransportClient transportClient; 14 | 15 | public ESSearchRequestBuilder prepareSearch(String index, String type) { 16 | return new ESSearchRequestBuilder(transportClient.prepareSearch(index).setTypes(type)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESDeleteValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.SearchBaseResult; 5 | import com.elastic.search.elasticsearch.dataobject.DeleteESObject; 6 | 7 | /** 8 | * @author niuzhiwei 9 | */ 10 | public class ESDeleteValidator extends BaseValidator { 11 | 12 | public SearchBaseResult validate(DeleteESObject obj) { 13 | final SearchBaseResult baseValidateResult = super.baseValidate(obj); 14 | 15 | return baseValidateResult; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/SearchBusinessException.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class SearchBusinessException extends BusinessException { 7 | 8 | private static final long serialVersionUID = -3460524052435971680L; 9 | 10 | public SearchBusinessException(Throwable t) { 11 | super(t); 12 | } 13 | 14 | public SearchBusinessException(Integer errorCode, String errorMsg) { 15 | super(errorCode, errorMsg); 16 | } 17 | 18 | public SearchBusinessException(Integer errorCode, String errorMsg, Throwable cause) { 19 | super(errorCode, errorMsg, cause); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/OpenSystemException.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | 4 | 5 | /** 6 | * @author niuzhiwei 7 | */ 8 | public class OpenSystemException extends SystemException { 9 | 10 | private static final long serialVersionUID = -427919774313417519L; 11 | 12 | public OpenSystemException(int errorCode, String desc) { 13 | super(errorCode, desc); 14 | } 15 | 16 | public OpenSystemException(ErrorCode errorCode) { 17 | this(errorCode.getErrorCode(), errorCode.getErrorReason()); 18 | } 19 | 20 | @Override 21 | public String getMessage() { 22 | return getErrorCode() + "-" + getErrorReason(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/annotation/Cascade.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | 6 | /** 7 | * 关联模糊查询需要用到此注解 8 | * 9 | * @author niuzhiwei 10 | */ 11 | @Target(ElementType.TYPE) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Documented 14 | @Inherited 15 | @Repeatable(Cascades.class) 16 | public @interface Cascade { 17 | /** 18 | * 关联字段名称 19 | * 20 | * @return 21 | * @Author 22 | */ 23 | String value() default ""; 24 | 25 | /** 26 | * 关联字段名称 27 | * 28 | * @return 29 | * @Author 30 | */ 31 | String[] fields() default {}; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/starter/EtcElasticSearchProperties.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.starter; 2 | 3 | 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import lombok.ToString; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | 9 | /** 10 | * ES配置 11 | * 12 | * @author niuzhiwei 13 | */ 14 | @Getter 15 | @Setter 16 | @ToString 17 | @ConfigurationProperties(prefix = "search.es") 18 | public class EtcElasticSearchProperties { 19 | 20 | /** 21 | * es地址 22 | */ 23 | private String host; 24 | 25 | /** 26 | * es端口 27 | */ 28 | private Integer port; 29 | 30 | /** 31 | * 集群名称 32 | */ 33 | private String clusterName; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/bytes/SerializeByteApi.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.bytes; 2 | 3 | import com.elastic.search.elasticsearch.serialize.SerializeApi; 4 | 5 | /** 6 | * 序列化POJO->Byte->POJO类型API 7 | * 8 | * @author SHOUSHEN LUAN 9 | */ 10 | public interface SerializeByteApi extends SerializeApi { 11 | 12 | /** 13 | * 编码 14 | * 15 | * @param t 16 | * @return 17 | */ 18 | @Override 19 | public byte[] encode(Object t); 20 | 21 | /** 22 | * 解码 23 | * 24 | * @param data 25 | * @param type 26 | * @param 27 | * @return 28 | */ 29 | @Override 30 | public T decode(byte[] data, Class type); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/parser/LongType.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json.parser; 2 | 3 | 4 | import java.util.Date; 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | public class LongType implements ParserDateFactory.DateType { 10 | @Override 11 | public boolean matches(String value) { 12 | if (value != null) { 13 | try { 14 | Long.parseLong(value.trim()); 15 | return true; 16 | } catch (Exception e) { 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | @Override 23 | public Date parse(String value) { 24 | return new Date(Long.parseLong(value.trim())); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/log/SearchLogger.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.log; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | /** 6 | * @author niuzhiwei 7 | */ 8 | @Slf4j 9 | public class SearchLogger { 10 | 11 | public static void error(String msg, Exception ex) { 12 | log.error(msg, ex); 13 | } 14 | 15 | public static void log(Object obj) { 16 | if (log.isDebugEnabled()) { 17 | log.debug(obj.toString().replace("\n", " ").replace("\t", " ")); 18 | } 19 | } 20 | 21 | public static void log(String msg) { 22 | if (log.isDebugEnabled()) { 23 | log.debug(msg.replace("\n", " ").replace("\t", " ")); 24 | } 25 | } 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/SerializeJsonApi.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json; 2 | 3 | import com.elastic.search.elasticsearch.serialize.SerializeApi; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | /** 8 | * @author niuzhiwei 9 | */ 10 | public interface SerializeJsonApi extends SerializeApi { 11 | 12 | public static final Logger LOGGER = LoggerFactory.getLogger(SerializeApi.class); 13 | 14 | /** 15 | * 序列化 16 | */ 17 | @Override 18 | public String encode(Object t); 19 | 20 | /** 21 | * 反序列化 22 | */ 23 | @Override 24 | public T decode(String json, Class type); 25 | 26 | public SerializeJsonApi getInstance(); 27 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/enums/FieldTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.enums; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | 7 | public enum FieldTypeEnum { 8 | 9 | /** 10 | * 字段类型 11 | */ 12 | STRING("string"), 13 | INTEGER("integer"), 14 | LONG("long"), 15 | SHORT("short"), 16 | BYTE("byte"), 17 | DOUBLE("double"), 18 | BIG_DECIMAL("double"), 19 | FLOAT("float"); 20 | 21 | String type; 22 | 23 | private FieldTypeEnum(String type) { 24 | this.type = type; 25 | } 26 | 27 | public String getType() { 28 | return this.type; 29 | } 30 | 31 | public void setType(String type) { 32 | this.type = type; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/GsonSerialize.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json; 2 | 3 | import com.google.gson.Gson; 4 | 5 | /** 6 | * @author niuzhiwei 7 | */ 8 | public class GsonSerialize implements SerializeJsonApi { 9 | 10 | public static GsonSerialize INSTANCE = new GsonSerialize(); 11 | 12 | private static Gson gson = new Gson(); 13 | 14 | @Override 15 | public String encode(Object t) { 16 | return gson.toJson(t); 17 | } 18 | 19 | @Override 20 | public T decode(String json, Class clazz) { 21 | return (T) gson.fromJson(json, clazz); 22 | } 23 | 24 | @Override 25 | public SerializeJsonApi getInstance() { 26 | return INSTANCE; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/parser/DateTimeType.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json.parser; 2 | 3 | 4 | import java.text.ParseException; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | 8 | /** 9 | * @author niuzhiwei 10 | */ 11 | public class DateTimeType implements ParserDateFactory.DateType { 12 | 13 | @Override 14 | public boolean matches(String value) { 15 | if (value != null) { 16 | return value.length() >= "yyyy-MM-dd HH:mm:ss".length(); 17 | } 18 | return false; 19 | } 20 | 21 | @Override 22 | public Date parse(String value) throws ParseException { 23 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/parser/YmdDateType.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json.parser; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | /** 8 | * @author niuzhiwei 9 | */ 10 | public class YmdDateType implements ParserDateFactory.DateType { 11 | 12 | @Override 13 | public boolean matches(String value) { 14 | if (value != null) { 15 | if (value.length() == "yyyy-MM-dd".length()) { 16 | return true; 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | @Override 23 | public Date parse(String value) throws ParseException { 24 | return new SimpleDateFormat("yyyy-MM-dd").parse(value); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/parser/GMTDateTimeType.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json.parser; 2 | 3 | 4 | 5 | import java.text.ParseException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Date; 8 | 9 | /** 10 | * @author niuzhiwei 11 | */ 12 | public class GMTDateTimeType implements ParserDateFactory.DateType { 13 | 14 | @Override 15 | public boolean matches(String value) { 16 | if (value != null) { 17 | if (value.contains("T")) { 18 | return true; 19 | } 20 | } 21 | return false; 22 | } 23 | 24 | @Override 25 | public Date parse(String value) throws ParseException { 26 | return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").parse(value); 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/utils/EmptyUtils.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.utils; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | public class EmptyUtils { 10 | 11 | public static boolean isEmpty(Object s) { 12 | if (s == null) { 13 | return true; 14 | } 15 | if ((s instanceof String) && (((String) s).trim().length() == 0)) { 16 | return true; 17 | } 18 | if (s instanceof Map) { 19 | return ((Map) s).isEmpty(); 20 | } 21 | if (s instanceof List) { 22 | return ((List) s).isEmpty(); 23 | } 24 | if (s instanceof Object[]) { 25 | return (((Object[]) s).length == 0); 26 | } 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/utils/PageConditionUtils.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.utils; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.PageCondition; 5 | 6 | /** 7 | *

8 | * 分页工具类 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class PageConditionUtils { 13 | 14 | private PageConditionUtils() { 15 | 16 | } 17 | 18 | /** 19 | * 创建分页条件 20 | * 21 | * @param pageSize 22 | * @param currentPage 23 | * @return 24 | */ 25 | public static PageCondition create(int pageSize, int currentPage) { 26 | PageCondition pageCondition = new PageCondition(); 27 | pageCondition.setCurrentPage(currentPage); 28 | pageCondition.setPageSize(pageSize); 29 | return pageCondition; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/condition/RelationConditionBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.condition; 2 | 3 | import org.elasticsearch.index.query.BoolQueryBuilder; 4 | import org.elasticsearch.index.query.QueryBuilder; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | *

9 | * 检索条件关系 构建器 10 | * @author jack 11 | */ 12 | public class RelationConditionBuilder { 13 | 14 | /** 15 | * 构建 根查询 与 当前查询 的嵌套关系 16 | *

17 | * 若有条件分组查询(OR 链接),那么所有关系均为 should ;否则为must 18 | * 19 | * @param groupCondition 是否条件分组 20 | * @param currentQuery 当前查询 21 | * @param rootQuery 根查询 22 | * @return 根查询 23 | */ 24 | public QueryBuilder builder(boolean groupCondition, QueryBuilder currentQuery, BoolQueryBuilder rootQuery) { 25 | return groupCondition ? rootQuery.should(currentQuery) : rootQuery.must(currentQuery); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/evo/ESQueryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.evo; 2 | 3 | import org.elasticsearch.index.query.QueryBuilder; 4 | import org.elasticsearch.index.query.QueryBuilders; 5 | 6 | public class ESQueryBuilder { 7 | 8 | private QueryBuilder queryBuilder; 9 | 10 | public ESQueryBuilder(QueryBuilder queryBuilder) { 11 | this.queryBuilder = queryBuilder; 12 | } 13 | 14 | public static ESQueryBuilder match(String name, Object value) { 15 | QueryBuilder builder = QueryBuilders.matchQuery(name, value); 16 | return new ESQueryBuilder(builder); 17 | } 18 | 19 | public static ESQueryBuilder lt(String name, Object value) { 20 | QueryBuilder builder = QueryBuilders.rangeQuery(name).lt(value); 21 | return new ESQueryBuilder(builder); 22 | } 23 | 24 | public QueryBuilder getQueryBuilder() { 25 | return queryBuilder; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/enums/ConditionExpressionEnum.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.enums; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | *

7 | * es 查询条件表达式 8 | * 9 | * @author niuzhiwei 10 | */ 11 | @Getter 12 | public enum ConditionExpressionEnum { 13 | /** 14 | * 查询条件表达式枚举 15 | */ 16 | EQUAL("等于"), 17 | UNEQUAL("不等"), 18 | GREATER("大于"), 19 | GREATER_OR_EQUAL("大于等于"), 20 | LESSER("小于"), 21 | LESSER_OR_EQUAL("小于等于"), 22 | LIKE("模糊查询"), 23 | NULL("空值"), 24 | NOT_NULL("非空"), 25 | IN("在"), 26 | NOT_IN("不在"), 27 | BETWEEN("不包含边界值"), 28 | BETWEEN_AND("包含边界值"), 29 | BETWEEN_LEFT("含左不含右"), 30 | BETWEEN_RIGHR("含右不含左"), 31 | MATCH("匹配查询,主要用于分词字段的全文检索"); 32 | 33 | /** 34 | * 描述 35 | */ 36 | 37 | private String desc; 38 | 39 | ConditionExpressionEnum(String desc) { 40 | this.desc = desc; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/evo/ESBoolQueryBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.evo; 2 | 3 | import org.elasticsearch.index.query.BoolQueryBuilder; 4 | import org.elasticsearch.index.query.QueryBuilder; 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | public class ESBoolQueryBuilder { 10 | 11 | private BoolQueryBuilder boolQueryBuilder; 12 | 13 | public ESBoolQueryBuilder(BoolQueryBuilder boolQueryBuilder) { 14 | this.boolQueryBuilder = boolQueryBuilder; 15 | } 16 | 17 | public void must(QueryBuilder builder) { 18 | this.boolQueryBuilder.must(builder); 19 | } 20 | 21 | public void should(QueryBuilder builder) { 22 | this.boolQueryBuilder.should(builder); 23 | } 24 | 25 | public void mustNot(QueryBuilder builder) { 26 | this.boolQueryBuilder.mustNot(builder); 27 | } 28 | 29 | public BoolQueryBuilder getBoolQueryBuilder() { 30 | return boolQueryBuilder; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/Field.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Field { 7 | Map keyword = new HashMap<>(); 8 | 9 | public static Field make() { 10 | return new Field(); 11 | } 12 | 13 | public Field setType(DataType type) { 14 | keyword.put("type", type.name().toLowerCase()); 15 | return this; 16 | } 17 | 18 | /** 19 | * 忽略字符长度ignore_above以外的字符,不被索引 20 | * 21 | * @param ignore_above 22 | * @return 23 | */ 24 | public Field setIgnoreAbove(int ignore_above) { 25 | keyword.put("ignore_above", ignore_above); 26 | return this; 27 | } 28 | 29 | /** 30 | * 超过256个字符的文本,将会被忽略,不被索引 31 | * 32 | * @return 33 | */ 34 | public Field setIgnoreAbove() { 35 | keyword.put("ignore_above", 256); 36 | return this; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/DataType.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | /** 4 | * elasticsearch 数据类型 5 | * https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 6 | * 7 | * @author jack 8 | */ 9 | public enum DataType { 10 | 11 | TEXT, KEYWORD, 12 | // 13 | DATE, IP, BOOLEAN, 14 | // number类型 15 | LONG, INTEGER, SHORT, BYTE, DOUBLE, FLOAT, 16 | // nested object mapping 17 | NESTED; 18 | 19 | // { 20 | // "mappings": { 21 | // "blogpost": { 22 | // "properties": { 23 | // "comments": { 24 | // "type": "nested", 25 | // "properties": { 26 | // "name": { "type": "string" }, 27 | // "comment": { "type": "string" }, 28 | // "age": { "type": "short" }, 29 | // "stars": { "type": "short" }, 30 | // "date": { "type": "date" } 31 | // } 32 | // } 33 | // } 34 | // } 35 | // } 36 | // } 37 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESQueryValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.SearchBaseResult; 5 | import com.elastic.search.elasticsearch.dataobject.QueryESObject; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import javax.annotation.Resource; 11 | 12 | @Slf4j 13 | public class ESQueryValidator extends BaseValidator { 14 | 15 | @Resource 16 | private SearchConditionValidator searchConditionValidator; 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(ESQueryValidator.class); 19 | 20 | public SearchBaseResult validate(QueryESObject obj) { 21 | final SearchBaseResult baseValidateResult = super.baseValidate(obj); 22 | if (baseValidateResult.isFailed()) { 23 | return baseValidateResult; 24 | } 25 | return searchConditionValidator 26 | .validator(obj.getSearchConditions()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/ExceptionFactory.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class ExceptionFactory { 7 | 8 | public ExceptionFactory() { 9 | } 10 | 11 | public static synchronized SearchBusinessException ex(Throwable throwable) { 12 | return new SearchBusinessException(throwable); 13 | } 14 | 15 | public static synchronized SearchBusinessException ex(Integer errorCode, String errorMsg) { 16 | return new SearchBusinessException(errorCode, errorMsg); 17 | } 18 | 19 | public static synchronized SearchBusinessException ex(Integer errorCode, String errorMsg, Object... regex) { 20 | return new SearchBusinessException(errorCode, String.format(errorMsg, regex)); 21 | } 22 | 23 | public static synchronized SearchBusinessException ex(Integer errorCode, Throwable throwable, String errorMsg, Object... regex) { 24 | return new SearchBusinessException(errorCode, String.format(errorMsg, regex), throwable); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/searchservice/ESStatisticService.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.searchservice; 2 | 3 | 4 | import com.elastic.search.common.domain.SearchBaseResult; 5 | import com.elastic.search.elasticsearch.dataobject.CollapseQueryObject; 6 | import com.elastic.search.elasticsearch.dataobject.ESResponse; 7 | import com.elastic.search.elasticsearch.dataobject.StatisticESObject; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | *

13 | * ES 统计相关服务 14 | * @author niuzhiwei 15 | */ 16 | public interface ESStatisticService { 17 | 18 | /** 19 | * 全局统计服务,不受分页效果影响 20 | * 21 | * @param esObject ES 统计请求参数 22 | * @return key:functionName;value:statistic value 23 | */ 24 | SearchBaseResult> statisticByConditions(StatisticESObject esObject); 25 | 26 | /** 27 | * 按 field value 去重,返回指定数目的 doc 28 | * 29 | * @param esObject 去重请求参数 30 | * @return ES 通用响应结果 31 | */ 32 | SearchBaseResult> collapse(CollapseQueryObject esObject); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/SystemException.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class SystemException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = -8995909169223941100L; 9 | /** 10 | * 错误码 11 | */ 12 | private int errorCode; 13 | /** 14 | * 错误描述 15 | */ 16 | private String errorReason; 17 | 18 | public SystemException(int errorCode, String errorReason) { 19 | super("errorCode:"+errorCode+"-errorReason:"+errorReason); 20 | this.errorCode = errorCode; 21 | this.errorReason = errorReason; 22 | } 23 | 24 | public SystemException(ErrorCode errorCode) { 25 | this(errorCode.getErrorCode(), errorCode.getErrorReason()); 26 | } 27 | 28 | public int getErrorCode() { 29 | return errorCode; 30 | } 31 | 32 | public String getErrorReason() { 33 | return errorReason; 34 | } 35 | 36 | public SystemException setCause(Throwable t) { 37 | super.initCause(t); 38 | return this; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/ESDocument.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.Map; 5 | 6 | /** 7 | *

8 | * es 单文档响应结果 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class ESDocument implements Serializable { 13 | private static final long serialVersionUID = -9005544083555928843L; 14 | /** 15 | * 文档数据内容 或 按指定 Fields 返回 16 | */ 17 | private Map dataMap; 18 | 19 | public ESDocument() { 20 | } 21 | 22 | public ESDocument(Map dataMap) { 23 | this.dataMap = dataMap; 24 | } 25 | 26 | public Map getDataMap() { 27 | return dataMap; 28 | } 29 | 30 | public void setDataMap(Map dataMap) { 31 | this.dataMap = dataMap; 32 | } 33 | 34 | /** 35 | * 格式未进行约束,调用方请勿尝试解析该字符串 36 | */ 37 | @Override 38 | public String toString() { 39 | final StringBuilder sb = new StringBuilder("ESDocument{"); 40 | sb.append("dataMap=").append(dataMap); 41 | sb.append('}'); 42 | return sb.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESUpdateValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.UpdateESObject; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * @author niuzhiwei 14 | */ 15 | @Slf4j 16 | public class ESUpdateValidator extends BaseUpdateValidator { 17 | 18 | @Override 19 | public SearchBaseResult validate(UpdateESObject obj) { 20 | final SearchBaseResult superValidateResult = super.validate(obj); 21 | if (superValidateResult.isFailed()) { 22 | return superValidateResult; 23 | } 24 | final Map ukMap = obj.getUkMap(); 25 | if (ukMap == null || ukMap.isEmpty()) { 26 | log.warn("update es object ,ukMap should not null!"); 27 | superValidateResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "更新ES,ukMap为空")); 28 | } 29 | return superValidateResult; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESSaveValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.SaveESObject; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * es保存数据验证 14 | * 15 | * @author niuzhiwei 16 | */ 17 | @Slf4j 18 | public class ESSaveValidator extends BaseValidator { 19 | 20 | 21 | public SearchBaseResult validate(SaveESObject obj) { 22 | final SearchBaseResult baseValidateResult = super.baseValidate(obj); 23 | if (baseValidateResult.isFailed()) { 24 | return baseValidateResult; 25 | } 26 | 27 | final Map dataMap = obj.getDataMap(); 28 | if (dataMap == null || dataMap.isEmpty()) { 29 | log.warn("save es object ,dataMap is null!"); 30 | baseValidateResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "存储ES, dataMap 为空")); 31 | } 32 | 33 | return baseValidateResult; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/SerializeJsonFactory.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json; 2 | 3 | 4 | import com.elastic.search.common.exception.ErrorCode; 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | public class SerializeJsonFactory { 10 | 11 | private static boolean support_jackson = false, support_gson = false; 12 | 13 | static { 14 | init(); 15 | } 16 | 17 | private static void init() { 18 | try { 19 | Class.forName("com.google.gson.Gson"); 20 | support_gson = true; 21 | } catch (ClassNotFoundException e) { 22 | } 23 | try { 24 | Class.forName("com.fasterxml.jackson.databind.ObjectMapper"); 25 | support_jackson = true; 26 | } catch (ClassNotFoundException e) { 27 | } 28 | } 29 | 30 | public static SerializeJsonApi getInstance() { 31 | if (support_jackson) { 32 | return JacksonSerialize.INSTANCE; 33 | } else if (support_gson) { 34 | return GsonSerialize.INSTANCE; 35 | } else { 36 | throw ErrorCode.JSON_SERIALIZE_FAIL.throwError("没有支持的JSON序列化实现"); 37 | } 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/FrameworkException.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class FrameworkException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = 7988894630081319767L; 9 | private int errorCode; 10 | private String errorMsg; 11 | 12 | public FrameworkException(Integer errorCode, String errorMsg) { 13 | super(String.format("[errorCode:%s errorMsg:%s]", errorCode, errorMsg)); 14 | this.errorCode = errorCode; 15 | this.errorMsg = errorMsg; 16 | } 17 | 18 | public FrameworkException(Integer errorCode, String errorMsg, Throwable cause) { 19 | super(String.format("[errorCode:%s errorMsg:%s]", errorCode, errorMsg), cause); 20 | this.errorCode = errorCode; 21 | this.errorMsg = errorMsg; 22 | } 23 | 24 | public int getErrorCode() { 25 | return this.errorCode; 26 | } 27 | 28 | public void setErrorCode(int errorCode) { 29 | this.errorCode = errorCode; 30 | } 31 | 32 | public String getErrorMsg() { 33 | return this.errorMsg; 34 | } 35 | 36 | public void setErrorMsg(String errorMsg) { 37 | this.errorMsg = errorMsg; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/DateDeserializer.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.JsonDeserializer; 7 | import com.elastic.search.elasticsearch.serialize.api.json.parser.ParserDateFactory; 8 | import org.apache.commons.lang3.StringUtils; 9 | 10 | import java.io.IOException; 11 | import java.util.Date; 12 | 13 | /** 14 | * @author niuzhiwei 15 | */ 16 | public class DateDeserializer extends JsonDeserializer { 17 | 18 | @Override 19 | public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 20 | String value = jp.getText(); 21 | if (StringUtils.isBlank(value)) { 22 | return null; 23 | } 24 | try { 25 | Date date = ParserDateFactory.parser(value); 26 | if (date != null) { 27 | return date; 28 | } 29 | } catch (Exception e) { 30 | 31 | } 32 | throw new IllegalArgumentException("解析`" + value + "`到java.util.Date类型错误"); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/BatchDeleteESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | *

8 | * 批量删除请求参数 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class BatchDeleteESObject implements Serializable { 13 | 14 | private static final long serialVersionUID = 6716761733351922128L; 15 | private List deleteDatas; 16 | /** 17 | * 设置是否立即刷新到磁盘 18 | */ 19 | private boolean refresh = true; 20 | 21 | public BatchDeleteESObject() { 22 | } 23 | 24 | public List getDeleteDatas() { 25 | return deleteDatas; 26 | } 27 | 28 | public void setDeleteDatas(List deleteDatas) { 29 | this.deleteDatas = deleteDatas; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | final StringBuilder sb = new StringBuilder("BatchDeleteESObject{"); 35 | sb.append("deleteDatas=").append(deleteDatas); 36 | sb.append('}'); 37 | return sb.toString(); 38 | } 39 | 40 | public boolean isRefresh() { 41 | return refresh; 42 | } 43 | 44 | public void setRefresh(boolean refresh) { 45 | this.refresh = refresh; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/consts/FrameworkExceptionConstants.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.consts; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class FrameworkExceptionConstants { 7 | 8 | public static int ERROR_DEPENDENCY = 2001; 9 | public static int ERROR_ENTITY_CONVERT_ERROR = 2002; 10 | public static int ERROR_MESSAGE_SEND = 2003; 11 | public static int ERROR_GEN_CONDITION = 2004; 12 | public static final int ERROR_SEARCH_ENGINES = 2005; 13 | public static final int ERROR_SEND_SMS = 2006; 14 | public static final int ERROR_REQUIRED_VALIDATION = 2007; 15 | public static final int ERROR_LOGIN_INFO = 2008; 16 | public static final int ERROR_APP_PUSH = 2009; 17 | public static final int ERROR_HTTPHEADER_INFO = 2010; 18 | public static final int ERROR_IDEMPOTENCY = 2011; 19 | public static final int ERROR_SERVICE_TRANSACTION = 2012; 20 | public static final int ERROR_FEIGN_ERROR = 2013; 21 | public static final int ERROR_BEAN_UTILS = 2014; 22 | public static final int ERROR_TENCENT_MAP = 2015; 23 | public static final int ERROR_HTTPCLIENT_UTIL = 2016; 24 | public static final int ERROR_DISTRIBUTED_LOCK = 2017; 25 | 26 | public FrameworkExceptionConstants() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/listener/SpringBootEnvironmentListener.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.listener; 2 | 3 | import com.elastic.search.common.domain.SystemManager; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.boot.context.event.ApplicationPreparedEvent; 6 | import org.springframework.context.ApplicationListener; 7 | import org.springframework.core.env.Environment; 8 | 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | /** 12 | * SpringBoot 环境监听 13 | * 14 | * @author SHOUSHEN LUAN 15 | */ 16 | @Slf4j 17 | public class SpringBootEnvironmentListener implements ApplicationListener { 18 | 19 | private static AtomicBoolean isInit = new AtomicBoolean(false); 20 | 21 | @Override 22 | public void onApplicationEvent(ApplicationPreparedEvent event) { 23 | Environment environment = event.getApplicationContext().getEnvironment(); 24 | if (isInit.compareAndSet(false, true)) { 25 | setManagerConfig(environment); 26 | } 27 | } 28 | 29 | private void setManagerConfig(Environment environment) { 30 | log.info("-----------------spring boot admin--------------------"); 31 | SystemManager.initEnvironment(environment); 32 | log.info("-----------------over--------------------"); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/utils/OrderConditionUtils.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.utils; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.OrderCondition; 5 | import com.elastic.search.elasticsearch.dataobject.enums.SortEnum; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | /** 12 | *

13 | * 搜索引擎排序条件工具类 14 | * 15 | * @author niuzhiwei\ 16 | */ 17 | public class OrderConditionUtils { 18 | 19 | private OrderConditionUtils() { 20 | 21 | } 22 | 23 | private static final ThreadLocal> LIST = new ThreadLocal<>(); 24 | 25 | public static OrderConditionUtils start() { 26 | OrderConditionUtils utils = new OrderConditionUtils(); 27 | LIST.set(new ArrayList<>()); 28 | ; 29 | return utils; 30 | } 31 | 32 | public OrderConditionUtils addCondition(String fieldName, SortEnum sort) { 33 | OrderCondition order = new OrderCondition(); 34 | order.setFieldName(fieldName); 35 | order.setOrderCondition(sort); 36 | LIST.get().add(order); 37 | return this; 38 | } 39 | 40 | public List end() { 41 | return LIST.get(); 42 | } 43 | 44 | @Override 45 | protected void finalize() { 46 | LIST.remove(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class BusinessException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = 7988894630081319767L; 9 | private int errorCode; 10 | private String errorMsg; 11 | 12 | protected BusinessException(Throwable t) { 13 | super(t); 14 | } 15 | 16 | protected BusinessException(Integer errorCode, String errorMsg) { 17 | super(String.format("[errorCode:%s errorMsg:%s]", errorCode, errorMsg)); 18 | this.errorCode = errorCode; 19 | this.errorMsg = errorMsg; 20 | } 21 | 22 | protected BusinessException(Integer errorCode, String errorMsg, Throwable cause) { 23 | super(String.format("[errorCode:%s errorMsg:%s]", errorCode, errorMsg), cause); 24 | this.errorCode = errorCode; 25 | this.errorMsg = errorMsg; 26 | } 27 | 28 | public int getErrorCode() { 29 | return this.errorCode; 30 | } 31 | 32 | public void setErrorCode(int errorCode) { 33 | this.errorCode = errorCode; 34 | } 35 | 36 | public String getErrorMsg() { 37 | return this.errorMsg; 38 | } 39 | 40 | public void setErrorMsg(String errorMsg) { 41 | this.errorMsg = errorMsg; 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/domain/GlobalConstant.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.domain; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | public class GlobalConstant { 7 | 8 | /** 9 | * 项目名称 10 | */ 11 | public static final String PROJECT_NAME = "PROJECT_NAME"; 12 | public static final String PREFIX = "prefix"; 13 | /** 14 | * 服务IP 15 | */ 16 | public static final String SERVER_IP = "SERVER_IP"; 17 | /** 18 | * 用户IP 19 | */ 20 | public static final String USER_IP = "USER_IP"; 21 | public static final String TRACE_ID = "traceID"; 22 | /** 23 | * 系统编码 24 | */ 25 | public static final String SYSTEM_CODE = "system.code"; 26 | /** 27 | * 开放平台API 调用签名secret配置key 28 | */ 29 | public static final String OPEN_SECRET_CONFIG_KEY = "system.open.secret"; 30 | /** 31 | * 错误码 32 | */ 33 | public static final String ERROR_CODE = "errorCode"; 34 | /** 35 | * 错误描述 36 | */ 37 | public static final String ERROR_REASON = "errorReason"; 38 | public static final String USE_TIME = "useTime"; 39 | /** 40 | * 日志分隔符`|` 41 | */ 42 | public static final String SEPARATOR = "|"; 43 | /** 44 | * 日志格式拆分符号`:` 45 | */ 46 | public static final String SPLIT = ":"; 47 | /** 48 | * 请求URI 49 | */ 50 | public static String requestURI = "requestURI"; 51 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/BatchSaveESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | *

8 | * 批量新增请求参数 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class BatchSaveESObject implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = 6434788994136588315L; 16 | private List saveDatas; 17 | /** 18 | * 设置是否立即刷新到磁盘 19 | */ 20 | private boolean refresh = true; 21 | 22 | public BatchSaveESObject() { 23 | } 24 | 25 | public List getSaveDatas() { 26 | return saveDatas; 27 | } 28 | 29 | public void setSaveDatas(List saveDatas) { 30 | this.saveDatas = saveDatas; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | final StringBuilder sb = new StringBuilder("BatchSaveESObject{"); 36 | sb.append("saveDatas=").append(saveDatas); 37 | sb.append('}'); 38 | return sb.toString(); 39 | } 40 | 41 | public boolean isRefresh() { 42 | return refresh; 43 | } 44 | 45 | /** 46 | * 设置是否立即刷新到磁盘 47 | * 48 | * @param refresh 49 | */ 50 | public BatchSaveESObject setRefresh(boolean refresh) { 51 | this.refresh = refresh; 52 | return this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/ConditionUpdateESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 按条件更新 请求参数 12 | * 13 | * @author niuzhiwei 14 | */ 15 | public class ConditionUpdateESObject extends UpdateESObject implements Serializable { 16 | 17 | 18 | private static final long serialVersionUID = 4730396395563341460L; 19 | /** 20 | * 筛选条件 21 | */ 22 | private List conditions; 23 | 24 | public ConditionUpdateESObject() { 25 | } 26 | 27 | public ConditionUpdateESObject(String systemName, String indexName, String typeName) { 28 | super(systemName, indexName, typeName); 29 | } 30 | 31 | public List getConditions() { 32 | return conditions; 33 | } 34 | 35 | public void setConditions(List conditions) { 36 | this.conditions = conditions; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | final StringBuilder sb = new StringBuilder("ConditionUpdateESObject{"); 42 | sb.append(super.toString()); 43 | sb.append("conditions=").append(conditions); 44 | sb.append('}'); 45 | return sb.toString(); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/handler/ESStatisticResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.handler; 2 | 3 | import org.elasticsearch.search.aggregations.Aggregation; 4 | import org.elasticsearch.search.aggregations.Aggregations; 5 | import org.elasticsearch.search.aggregations.metrics.NumericMetricsAggregation; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | /** 12 | * @author niuzhiwei 13 | */ 14 | public class ESStatisticResponseHandler { 15 | 16 | public Map handler(final Aggregations aggregations) { 17 | Map statisticResult = new HashMap<>(); 18 | if (aggregations == null) { 19 | return null; 20 | } 21 | 22 | for (Aggregation aggregation : aggregations.asList()) { 23 | if (aggregation instanceof NumericMetricsAggregation.SingleValue) { 24 | final NumericMetricsAggregation.SingleValue numericProperty = (NumericMetricsAggregation 25 | .SingleValue) aggregation; 26 | final String functionName = numericProperty.getName(); 27 | final double value = numericProperty.value(); 28 | 29 | statisticResult.put(functionName, value); 30 | } 31 | } 32 | return statisticResult; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/domain/ESErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.domain; 2 | 3 | /** 4 | *

5 | * es 搜索引擎错误码定义 6 | *

7 | * 1(操作类型) + 00(错误码); 8 | * 操作类型 0 通用操作;1 索引操作; 2 删除操作;3 更新操作; 4 查询操作; 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class ESErrorCode { 13 | 14 | /** 15 | * Escenter 异常 16 | */ 17 | public static final int ESCENTER_ERROR_CODE = 5555; 18 | 19 | /** 20 | * 索引发送mq消息失败 21 | */ 22 | public static final int INDEX_SEND_MQ_ERROR_CODE = 5001; 23 | 24 | /** 25 | * Client 异常 26 | */ 27 | public static final int CLIETN_ERROR_CODE = 1111; 28 | 29 | /** 30 | * 请求参数错误 31 | */ 32 | public static final int REQUEST_PARAM_ERROR_CODE = 1001; 33 | 34 | /** 35 | * 索引请求异常 36 | */ 37 | public static final int INDEX_ERROR_CODE = 2222; 38 | /** 39 | * 重复索引请求 40 | */ 41 | public static final int REPETITION_INDEX_ERROR_CODE = 2001; 42 | 43 | /** 44 | * Elastic 异常 45 | */ 46 | public static final int ELASTIC_ERROR_CODE = 9999; 47 | 48 | /** 49 | * 索引不存在 50 | */ 51 | public static final int INDEX_NOT_EXIST_ERROR_CODE = 9001; 52 | 53 | /** 54 | * 查询错误 55 | */ 56 | public static final int QUERY_PHASE_ERROR_CODE = 9002; 57 | 58 | /** 59 | * 文档不存在 60 | */ 61 | public static final int DOC_NOT_EXIST_ERROR_CODE = 9002; 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/api/SearchService.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.api; 2 | 3 | import org.elasticsearch.action.bulk.BulkRequestBuilder; 4 | import org.elasticsearch.action.index.IndexRequestBuilder; 5 | import org.elasticsearch.action.search.SearchResponse; 6 | import org.elasticsearch.client.Client; 7 | 8 | import javax.annotation.Resource; 9 | import java.util.List; 10 | 11 | /** 12 | * @author niuzhiwei 13 | */ 14 | public class SearchService { 15 | 16 | @Resource 17 | private Client client; 18 | 19 | /** 20 | * 统一索引中数据总数量 21 | * 22 | * @param index 23 | * @param type 24 | * @return 25 | */ 26 | public long countAll(String index, String type) { 27 | SearchResponse response = client.prepareSearch(index).setTypes(type).setSize(1).get(); 28 | return response.getHits().totalHits; 29 | } 30 | 31 | /** 32 | * 批量保存 33 | * 34 | * @param batchList 35 | * @return 36 | */ 37 | public boolean batchSave(List batchList) { 38 | if (batchList.size() > 0) { 39 | BulkRequestBuilder bulkRequestBuilder = client.prepareBulk(); 40 | for (IndexRequestBuilder requestBuilder : batchList) { 41 | bulkRequestBuilder.add(requestBuilder); 42 | } 43 | return !bulkRequestBuilder.get().hasFailures(); 44 | } else { 45 | return false; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/conditions/HavingCondition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.conditions; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.enums.ConditionExpressionEnum; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | *

10 | * SQL 分组筛选条件 11 | * 12 | * @author niuzhiwei 13 | */ 14 | public class HavingCondition implements Serializable { 15 | 16 | private static final long serialVersionUID = -8856231949172866442L; 17 | /** 18 | * 字段 19 | */ 20 | private String filedName; 21 | /** 22 | * 筛选表达式 23 | */ 24 | private ConditionExpressionEnum conditionExpressionEnum; 25 | /** 26 | * 字段值 27 | */ 28 | private Object fieldValue; 29 | 30 | public HavingCondition() { 31 | } 32 | 33 | public HavingCondition(String filedName, ConditionExpressionEnum conditionExpressionEnum, Object fieldValue) { 34 | this.filedName = filedName; 35 | this.conditionExpressionEnum = conditionExpressionEnum; 36 | this.fieldValue = fieldValue; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | final StringBuilder sb = new StringBuilder("HavingCondition{"); 42 | sb.append("filedName='").append(filedName).append('\''); 43 | sb.append(", conditionExpressionEnum=").append(conditionExpressionEnum); 44 | sb.append(", fieldValue=").append(fieldValue); 45 | sb.append('}'); 46 | return sb.toString(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/ConditionDeleteESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 按条件删除 请求参数 12 | * 13 | * @author niuzhiwei 14 | */ 15 | public class ConditionDeleteESObject extends DeleteESObject implements Serializable { 16 | 17 | 18 | private static final long serialVersionUID = 5343879260893305208L; 19 | /** 20 | * 筛选条件 21 | */ 22 | private List conditions; 23 | 24 | public ConditionDeleteESObject() { 25 | } 26 | 27 | public ConditionDeleteESObject(String systemName, String indexName, String typeName) { 28 | super(systemName, indexName, typeName); 29 | } 30 | 31 | public ConditionDeleteESObject(List conditions) { 32 | this.conditions = conditions; 33 | } 34 | 35 | public List getConditions() { 36 | return conditions; 37 | } 38 | 39 | public void setConditions(List conditions) { 40 | this.conditions = conditions; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | final StringBuilder sb = new StringBuilder("ConditionDeleteESObject{"); 46 | sb.append(super.toString()); 47 | sb.append("conditions=").append(conditions); 48 | sb.append('}'); 49 | return sb.toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/BatchUpdateESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | *

8 | * 批量更新请求参数 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class BatchUpdateESObject implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = 3151467153073294811L; 16 | private List updateDatas; 17 | 18 | public BatchUpdateESObject() { 19 | } 20 | 21 | /** 22 | * 设置是否立即刷新到磁盘 23 | */ 24 | private boolean refresh = true; 25 | 26 | public static long getSerialVersionUID() { 27 | return serialVersionUID; 28 | } 29 | 30 | public List getUpdateDatas() { 31 | return updateDatas; 32 | } 33 | 34 | public void setUpdateDatas(List updateDatas) { 35 | this.updateDatas = updateDatas; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | final StringBuilder sb = new StringBuilder("BatchUpdateESObject{"); 41 | sb.append("updateDatas=").append(updateDatas); 42 | sb.append('}'); 43 | return sb.toString(); 44 | } 45 | 46 | /** 47 | * 设置是否立即刷新到磁盘 48 | * 49 | * @param refresh 50 | */ 51 | public BatchUpdateESObject setRefresh(boolean refresh) { 52 | this.refresh = refresh; 53 | return this; 54 | } 55 | 56 | public boolean isRefresh() { 57 | return refresh; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/domain/BaseResult.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.domain; 2 | 3 | import com.google.gson.Gson; 4 | import com.elastic.search.common.exception.ErrorCode; 5 | import com.elastic.search.common.exception.RpcException; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author niuzhiwei 11 | */ 12 | abstract class BaseResult implements Serializable { 13 | 14 | private static final long serialVersionUID = 610503329211184167L; 15 | 16 | /** 17 | * 获取状态 18 | * 19 | * @return 20 | */ 21 | public abstract Status getStatus(); 22 | 23 | @Deprecated 24 | public void throwOpenException() { 25 | throwRpcException(); 26 | } 27 | 28 | public void throwRpcException() { 29 | if (getStatus().getStatusCode() != 0) { 30 | throw new RpcException(getStatus().getStatusCode(), getStatus().getStatusReason()); 31 | } 32 | } 33 | 34 | /** 35 | * 断言RPC OK 全部成功或部分成功 36 | */ 37 | public void assertRpcOK() { 38 | 39 | if (getStatus().getStatusCode() != 0 && getStatus().getStatusCode() != ErrorCode.PART_ERROR.getErrorCode()) { 40 | throwRpcException(); 41 | } 42 | } 43 | 44 | /** 45 | * 断言RPC调用全部成功 46 | */ 47 | public void assertRpcAllSuccess() { 48 | if (getStatus().getStatusCode() != 0) { 49 | throwRpcException(); 50 | } 51 | } 52 | 53 | 54 | private static final Gson gson = new Gson(); 55 | 56 | 57 | public String toJSON() { 58 | return gson.toJson(this); 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/xml/SerializeXml.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.xml; 2 | 3 | import com.elastic.search.common.domain.SearchBaseResult; 4 | import com.thoughtworks.xstream.XStream; 5 | 6 | /** 7 | * @author niuzhiwei 8 | */ 9 | public class SerializeXml { 10 | 11 | XStream XSTREAM = new XStream(); 12 | 13 | private XStreamAlias xStreamAlias = XStreamAlias.create(); 14 | 15 | { 16 | alias(SearchBaseResult.class); 17 | } 18 | 19 | public SerializeXml() { 20 | } 21 | 22 | public SerializeXml alias(String name, Class type) { 23 | XSTREAM.alias(name, type); 24 | return this; 25 | } 26 | 27 | public SerializeXml alias(Object root) { 28 | if (this.xStreamAlias != null) { 29 | this.xStreamAlias.initAlias(XSTREAM, root); 30 | } 31 | return this; 32 | } 33 | 34 | public SerializeXml alias(Class type) { 35 | XSTREAM.alias(type.getSimpleName(), type); 36 | return this; 37 | } 38 | 39 | public SerializeXml alias(Class... types) { 40 | for (Class type : types) { 41 | alias(type); 42 | } 43 | return this; 44 | } 45 | 46 | public String encode(Object obj) { 47 | xStreamAlias.initAlias(XSTREAM, obj); 48 | return XSTREAM.toXML(obj); 49 | } 50 | 51 | @SuppressWarnings("unchecked") 52 | public T decode(String xml, Object root) { 53 | xStreamAlias.initAlias(XSTREAM, root); 54 | return (T) XSTREAM.fromXML(xml, root); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/conditions/OrderCondition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.conditions; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.enums.SortEnum; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | *

10 | * es 排序条件 11 | * 12 | * @author niuzhiwei 13 | */ 14 | public class OrderCondition implements Serializable { 15 | 16 | private static final long serialVersionUID = 8349437527187326208L; 17 | /** 18 | * 字段名称 19 | */ 20 | private String fieldName; 21 | 22 | /** 23 | * 排序条件 24 | */ 25 | private SortEnum orderCondition; 26 | 27 | 28 | public OrderCondition() { 29 | } 30 | 31 | public OrderCondition(String fieldName, SortEnum orderCondition) { 32 | this.fieldName = fieldName; 33 | this.orderCondition = orderCondition; 34 | } 35 | 36 | public String getFieldName() { 37 | return fieldName; 38 | } 39 | 40 | public void setFieldName(String fieldName) { 41 | this.fieldName = fieldName; 42 | } 43 | 44 | public SortEnum getOrderCondition() { 45 | return orderCondition; 46 | } 47 | 48 | public void setOrderCondition(SortEnum orderCondition) { 49 | this.orderCondition = orderCondition; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | final StringBuilder sb = new StringBuilder("OrderCondition{"); 55 | sb.append("fieldName='").append(fieldName).append('\''); 56 | sb.append(", orderCondition=").append(orderCondition); 57 | sb.append('}'); 58 | return sb.toString(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/conditions/PageCondition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.conditions; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | *

7 | * es 分页条件 8 | * 9 | * @author niuzhiwei 10 | */ 11 | public class PageCondition implements Serializable { 12 | 13 | 14 | private static final long serialVersionUID = -1740674755812239502L; 15 | /** 16 | * 页大小 17 | */ 18 | private Integer pageSize; 19 | /** 20 | * 当前页 21 | */ 22 | private Integer currentPage; 23 | /** 24 | * 总文档数 25 | */ 26 | private Long totalDocs; 27 | 28 | public PageCondition() { 29 | } 30 | 31 | public Integer getPageSize() { 32 | return pageSize; 33 | } 34 | 35 | public void setPageSize(Integer pageSize) { 36 | this.pageSize = pageSize; 37 | } 38 | 39 | public Integer getCurrentPage() { 40 | return currentPage; 41 | } 42 | 43 | public void setCurrentPage(Integer currentPage) { 44 | this.currentPage = currentPage; 45 | } 46 | 47 | public Long getTotalDocs() { 48 | return totalDocs; 49 | } 50 | 51 | public void setTotalDocs(Long totalDocs) { 52 | this.totalDocs = totalDocs; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | final StringBuilder sb = new StringBuilder("PageCondition{"); 58 | sb.append("pageSize=").append(pageSize); 59 | sb.append(", currentPage=").append(currentPage); 60 | sb.append(", totalDocs=").append(totalDocs); 61 | sb.append('}'); 62 | return sb.toString(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESConditionUpdateValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 8 | import com.elastic.search.elasticsearch.dataobject.ConditionUpdateESObject; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | /** 16 | * @author niuzhiwei 17 | */ 18 | @Slf4j 19 | public class ESConditionUpdateValidator extends BaseUpdateValidator { 20 | 21 | @Resource 22 | private ESUpdateValidator esUpdateValidator; 23 | 24 | public SearchBaseResult validate(ConditionUpdateESObject obj) { 25 | SearchBaseResult dataResult = new SearchBaseResult<>(); 26 | if (null == obj) { 27 | log.warn("条件更新请求参数为空"); 28 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "条件更新请求参数为空")); 29 | } 30 | 31 | final List conditions = obj.getConditions(); 32 | if (CollectionUtils.isEmpty(conditions)) { 33 | log.warn("条件更新[conditions]数据为空."); 34 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "条件更新请求参数【conditions】为空")); 35 | } 36 | 37 | if (dataResult.isFailed()) { 38 | return dataResult; 39 | } 40 | 41 | return super.validate(obj); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESConditionDeleteValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.ConditionDeleteESObject; 8 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.List; 15 | 16 | /** 17 | * @author niuzhiwei 18 | */ 19 | public class ESConditionDeleteValidator { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(ESConditionUpdateValidator.class); 22 | 23 | @Resource 24 | private ESDeleteValidator esDeleteValidator; 25 | 26 | public SearchBaseResult validate(ConditionDeleteESObject obj) { 27 | SearchBaseResult dataResult = new SearchBaseResult<>(); 28 | if (null == obj) { 29 | LOGGER.warn("条件删除请求参数为空."); 30 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "条件删除请求参数为空")); 31 | } 32 | 33 | final List conditions = obj.getConditions(); 34 | if (CollectionUtils.isEmpty(conditions)) { 35 | LOGGER.warn("条件删除[conditions]数据为空."); 36 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "条件删除请求参数【conditions】为空")); 37 | } 38 | 39 | if (dataResult.isFailed()) { 40 | return dataResult; 41 | } 42 | 43 | return esDeleteValidator.validate(obj); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/bytes/JDKSerialize.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.bytes; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * @author niuzhiwei 7 | */ 8 | public class JDKSerialize implements SerializeByteApi { 9 | 10 | public static JDKSerialize INSTANCE = new JDKSerialize(); 11 | 12 | @Override 13 | public byte[] encode(Object t) { 14 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 15 | ObjectOutputStream oos = null; 16 | try { 17 | oos = new ObjectOutputStream(bos); 18 | oos.writeObject(t); 19 | oos.close(); 20 | return bos.toByteArray(); 21 | } catch (IOException e) { 22 | throw new IllegalArgumentException(e); 23 | } finally { 24 | try { 25 | if (null != oos) { 26 | oos.close(); 27 | } 28 | bos.close(); 29 | } catch (IOException e) { 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | @SuppressWarnings({ "unchecked" }) 36 | public T decode(byte[] bytes, Class clazz) { 37 | ObjectInputStream ois = null; 38 | if (null != bytes) { 39 | try { 40 | ois = new ObjectInputStream(new ByteArrayInputStream(bytes)); 41 | return (T) ois.readObject(); 42 | } catch (Exception e) { 43 | throw new IllegalArgumentException(e); 44 | } finally { 45 | try { 46 | if (null != ois) { 47 | ois.close(); 48 | } 49 | } catch (IOException e) { 50 | } 51 | } 52 | } 53 | return null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESBatchDeleteValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.BatchDeleteESObject; 8 | import com.elastic.search.elasticsearch.dataobject.DeleteESObject; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | /** 16 | * @author niuzhiwei 17 | */ 18 | @Slf4j 19 | public class ESBatchDeleteValidator extends BaseValidator { 20 | 21 | @Resource 22 | private ESDeleteValidator esDeleteValidator; 23 | 24 | public SearchBaseResult validate(BatchDeleteESObject obj) { 25 | SearchBaseResult dataResult = new SearchBaseResult<>(); 26 | if (null == obj) { 27 | log.warn("批量删除请求参数为空."); 28 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "批量删除请求参数为空")); 29 | } 30 | final List deleteDatas = obj.getDeleteDatas(); 31 | if (CollectionUtils.isEmpty(deleteDatas)) { 32 | log.warn("批量删除[deleteDatas]数据为空."); 33 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "批量删除请求参数【deleteDatas】为空")); 34 | } 35 | 36 | for (DeleteESObject deleteData : deleteDatas) { 37 | final SearchBaseResult validateResult = esDeleteValidator.validate(deleteData); 38 | if (validateResult.isFailed()) { 39 | return validateResult; 40 | } 41 | } 42 | return dataResult; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/BaseValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.BaseESObject; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.apache.commons.lang3.StringUtils; 10 | 11 | /** 12 | * @author niuzhiwei 13 | */ 14 | @Slf4j 15 | public class BaseValidator { 16 | 17 | public SearchBaseResult baseValidate(BaseESObject baseObj) { 18 | SearchBaseResult dataResult = new SearchBaseResult<>(); 19 | if (null == baseObj) { 20 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "hase requesr is null")); 21 | } 22 | 23 | final String systemName = baseObj.getSystemName(); 24 | if (StringUtils.isBlank(systemName)) { 25 | log.warn("es search base request parameter systemName is null !"); 26 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "request systemName is null ")); 27 | } 28 | 29 | final String indexName = baseObj.getIndexName(); 30 | if (StringUtils.isBlank(indexName)) { 31 | log.warn("es search base indexName is null "); 32 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "request indexName is null ")); 33 | } 34 | final String typeName = baseObj.getTypeName(); 35 | if (StringUtils.isBlank(typeName)) { 36 | log.warn("es search typeName is null"); 37 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "request typeName is null ")); 38 | } 39 | return dataResult; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/DeleteESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.Collections; 5 | import java.util.Map; 6 | 7 | /** 8 | *

9 | * es 删除请求参数 10 | * 11 | * @author niuzhiwei 12 | */ 13 | public class DeleteESObject extends BaseESObject implements Serializable { 14 | private static final long serialVersionUID = 7438197271883469477L; 15 | 16 | /** 17 | * 文档唯一标志 18 | */ 19 | private Map ukMap; 20 | 21 | /** 22 | * 嵌套文档删除 23 | */ 24 | private Map nestedMap; 25 | /** 26 | * 设置是否立即刷新到磁盘 27 | */ 28 | private boolean refresh = true; 29 | 30 | public DeleteESObject() { 31 | } 32 | 33 | public DeleteESObject(String systemName, String indexName, String typeName) { 34 | super(systemName, indexName, typeName); 35 | } 36 | 37 | public Map getUkMap() { 38 | return ukMap; 39 | } 40 | 41 | /** 42 | * 请使用setId 43 | */ 44 | @Deprecated 45 | public void setUkMap(Map ukMap) { 46 | this.ukMap = ukMap; 47 | } 48 | 49 | public void setId(Object id) { 50 | this.setUkMap(Collections.singletonMap("id", id)); 51 | } 52 | 53 | /** 54 | * 格式未进行约束,调用方请勿尝试解析该字符串 55 | */ 56 | @Override 57 | public String toString() { 58 | final StringBuilder sb = new StringBuilder("DeleteESObject{"); 59 | sb.append(super.toString()); 60 | sb.append("ukMap=").append(ukMap); 61 | sb.append('}'); 62 | return sb.toString(); 63 | } 64 | 65 | public boolean isRefresh() { 66 | return refresh; 67 | } 68 | 69 | public void setRefresh(boolean refresh) { 70 | this.refresh = refresh; 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESBatchSaveValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.BatchSaveESObject; 8 | import com.elastic.search.elasticsearch.dataobject.SaveESObject; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | /** 16 | * @author niuzhiwei 17 | */ 18 | @Slf4j 19 | public class ESBatchSaveValidator extends BaseValidator { 20 | 21 | @Resource 22 | private ESSaveValidator esSaveValidator; 23 | 24 | public SearchBaseResult validate(BatchSaveESObject obj) { 25 | SearchBaseResult dataResult = new SearchBaseResult<>(); 26 | if (null == obj) { 27 | log.warn("批量新增请求参数为空."); 28 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "批量新增请求参数为空")); 29 | } 30 | final List saveDatas = obj.getSaveDatas(); 31 | if (CollectionUtils.isEmpty(saveDatas)) { 32 | log.warn("批量新增[saveDatas]数据为空."); 33 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "批量新增请求参数【saveDatas】为空")); 34 | } 35 | 36 | if (dataResult.isFailed()) { 37 | return dataResult; 38 | } 39 | 40 | for (SaveESObject saveData : saveDatas) { 41 | final SearchBaseResult validateResult = esSaveValidator.validate(saveData); 42 | if (validateResult.isFailed()) { 43 | return validateResult; 44 | } 45 | } 46 | 47 | return dataResult; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/ESBatchUpdateValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.BatchUpdateESObject; 8 | import com.elastic.search.elasticsearch.dataobject.UpdateESObject; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.util.CollectionUtils; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.List; 14 | 15 | /** 16 | * @author niuzhiwei 17 | */ 18 | @Slf4j 19 | public class ESBatchUpdateValidator extends BaseValidator { 20 | 21 | @Resource 22 | private ESUpdateValidator esUpdateValidator; 23 | 24 | public SearchBaseResult validate(BatchUpdateESObject obj) { 25 | SearchBaseResult dataResult = new SearchBaseResult<>(); 26 | if (null == obj) { 27 | log.warn("批量更新请求参数为空"); 28 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "批量更新请求参数为空")); 29 | } 30 | final List updateDatas = obj.getUpdateDatas(); 31 | if (CollectionUtils.isEmpty(updateDatas)) { 32 | log.warn("批量更新[updateDatas]数据为空."); 33 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "批量更新请求参数【updateDatas】为空")); 34 | } 35 | 36 | if (dataResult.isFailed()) { 37 | return dataResult; 38 | } 39 | 40 | for (UpdateESObject updateData : updateDatas) { 41 | final SearchBaseResult validateResult = esUpdateValidator.validate(updateData); 42 | if (validateResult.isFailed()) { 43 | return validateResult; 44 | } 45 | } 46 | 47 | return dataResult; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/BaseESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | *

7 | * 访问 es 必需参数 8 | * 9 | * @author niuzhiwei 10 | */ 11 | public class BaseESObject implements Serializable { 12 | 13 | private static final long serialVersionUID = -8766919218680214602L; 14 | /** 15 | * 系统名称 16 | */ 17 | private String systemName; 18 | /** 19 | * 索引 20 | */ 21 | private String indexName; 22 | 23 | /** 24 | * 类型 25 | */ 26 | private String typeName; 27 | 28 | BaseESObject() { 29 | } 30 | 31 | BaseESObject(String systemName, String indexName, String typeName) { 32 | this.systemName = systemName; 33 | this.indexName = indexName; 34 | this.typeName = typeName; 35 | } 36 | 37 | public String getSystemName() { 38 | return systemName; 39 | } 40 | 41 | public void setSystemName(String systemName) { 42 | this.systemName = systemName; 43 | } 44 | 45 | public String getIndexName() { 46 | return indexName; 47 | } 48 | 49 | public void setIndexName(String indexName) { 50 | this.indexName = indexName; 51 | } 52 | 53 | public String getTypeName() { 54 | return typeName; 55 | } 56 | 57 | public void setTypeName(String typeName) { 58 | this.typeName = typeName; 59 | } 60 | 61 | /** 62 | * 格式未进行约束,调用方请勿尝试解析该字符串 63 | */ 64 | @Override 65 | public String toString() { 66 | final StringBuilder sb = new StringBuilder("BaseESObject{"); 67 | sb.append("systemName='").append(systemName).append('\''); 68 | sb.append(", indexName='").append(indexName).append('\''); 69 | sb.append(", typeName='").append(typeName).append('\''); 70 | sb.append('}'); 71 | return sb.toString(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/StatisticByConditionsValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.StatisticESObject; 8 | import com.elastic.search.elasticsearch.dataobject.conditions.FunctionCondition; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | /** 17 | * @author niuzhiwei 18 | */ 19 | @Slf4j 20 | public class StatisticByConditionsValidator { 21 | 22 | public SearchBaseResult> validate(StatisticESObject obj) { 23 | SearchBaseResult> dataResult = new SearchBaseResult<>(); 24 | if (obj == null) { 25 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "统计服务,请求参数不得为空")); 26 | } 27 | 28 | final String systemName = obj.getSystemName(); 29 | if (StringUtils.isBlank(systemName)) { 30 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "统计服务,【systemName】不得为空")); 31 | } 32 | 33 | final String indexName = obj.getIndexName(); 34 | if (StringUtils.isBlank(indexName)) { 35 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "统计服务,【indexName】不得为空")); 36 | } 37 | 38 | final List functionConditions = obj.getFunctionConditions(); 39 | if (CollectionUtils.isEmpty(functionConditions)) { 40 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "统计服务,【functionConditions】不得为空")); 41 | } 42 | 43 | return dataResult; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/StatisticESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.FunctionCondition; 5 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 6 | 7 | import java.io.Serializable; 8 | import java.util.List; 9 | 10 | /** 11 | *

12 | * 统计请求参数 13 | * 14 | * @author niuzhiwei 15 | */ 16 | public class StatisticESObject extends BaseESObject implements Serializable { 17 | 18 | private static final long serialVersionUID = -6208691852851782250L; 19 | /** 20 | * 过滤条件 21 | */ 22 | private List searchConditions; 23 | 24 | /** 25 | * 统计函数 26 | */ 27 | private List functionConditions; 28 | 29 | public StatisticESObject() { 30 | } 31 | 32 | public StatisticESObject(String systemName, String indexName, String typeName) { 33 | super(systemName, indexName, typeName); 34 | } 35 | 36 | public List getSearchConditions() { 37 | return searchConditions; 38 | } 39 | 40 | public void setSearchConditions(List searchConditions) { 41 | this.searchConditions = searchConditions; 42 | } 43 | 44 | public List getFunctionConditions() { 45 | return functionConditions; 46 | } 47 | 48 | public void setFunctionConditions(List functionConditions) { 49 | this.functionConditions = functionConditions; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | final StringBuilder sb = new StringBuilder("StatisticESObject{"); 55 | sb.append(super.toString()); 56 | sb.append("searchConditions=").append(searchConditions); 57 | sb.append(", functionConditions=").append(functionConditions); 58 | sb.append('}'); 59 | return sb.toString(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/conditions/FunctionCondition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.conditions; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.enums.SqlFunctionEnum; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | *

10 | * SQL 函数 11 | * 12 | * @author niuzhiwei 13 | */ 14 | public class FunctionCondition implements Serializable { 15 | 16 | 17 | private static final long serialVersionUID = -3354861095722124185L; 18 | /** 19 | * 字段 20 | */ 21 | private String field; 22 | 23 | /** 24 | * 函数 25 | */ 26 | private SqlFunctionEnum function; 27 | 28 | /** 29 | * 函数的别名,响应结果中获取响应统计结果 30 | */ 31 | private String functionName; 32 | 33 | public FunctionCondition() { 34 | } 35 | 36 | public FunctionCondition(String field, SqlFunctionEnum function, String functionName) { 37 | this.field = field; 38 | this.function = function; 39 | this.functionName = functionName; 40 | } 41 | 42 | public String getField() { 43 | return field; 44 | } 45 | 46 | public void setField(String field) { 47 | this.field = field; 48 | } 49 | 50 | public SqlFunctionEnum getFunction() { 51 | return function; 52 | } 53 | 54 | public void setFunction(SqlFunctionEnum function) { 55 | this.function = function; 56 | } 57 | 58 | public String getFunctionName() { 59 | return functionName; 60 | } 61 | 62 | public void setFunctionName(String functionName) { 63 | this.functionName = functionName; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | final StringBuilder sb = new StringBuilder("FunctionCondition{"); 69 | sb.append("field='").append(field).append('\''); 70 | sb.append(", function=").append(function); 71 | sb.append(", functionName=").append(functionName); 72 | sb.append('}'); 73 | return sb.toString(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/IndexStruct.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | 4 | import com.elastic.search.elasticsearch.serialize.api.json.GsonSerialize; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | 10 | /** 11 | * @author niuzhiwei 12 | */ 13 | public class IndexStruct { 14 | 15 | public Map mappings = new HashMap<>(); 16 | private transient IndexType indexType; 17 | private transient String type; 18 | private transient String index; 19 | 20 | public String getType() { 21 | return type; 22 | } 23 | 24 | public String getIndex() { 25 | return index; 26 | } 27 | 28 | /** 29 | * 创建索引结构体 30 | * 31 | * @param type 索引类型名称 32 | * @return 33 | */ 34 | public static IndexStruct make(String index, String type) { 35 | return new IndexStruct().init(index, type); 36 | } 37 | 38 | private IndexStruct init(String index, String type) { 39 | this.indexType = new IndexType(); 40 | this.index = index; 41 | this.type = type; 42 | this.mappings.put(type, indexType); 43 | return this; 44 | } 45 | 46 | public IndexStruct addColumn(String name, IndexField column) { 47 | this.indexType.properties.put(name, column.getResult()); 48 | return this; 49 | } 50 | 51 | public String getIndexJson() { 52 | return GsonSerialize.INSTANCE.encode(this); 53 | } 54 | 55 | public Map getIndexAsMap() { 56 | return GsonSerialize.INSTANCE.decode(getIndexJson(), Map.class); 57 | } 58 | 59 | public static class IndexType { 60 | public Map> properties = new HashMap<>(); 61 | } 62 | 63 | public Map> getProperties() { 64 | return indexType.properties; 65 | } 66 | 67 | public String getPropertiesJson() { 68 | return GsonSerialize.INSTANCE.encode(indexType); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/ErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | /** 4 | * @author niuzhiwei 5 | */ 6 | 7 | public enum ErrorCode implements StatusDefinition { 8 | 9 | // 1001 ~1500 系统异常 10 | PART_ERROR(1000, "部分成功"), 11 | OTHER_ERROR(1001, "其他错误"), 12 | CALC_MD5_ERROR(1002, "calc MD5 error"), 13 | SYSTEM_LIMITER(1003, "系统限流保护"), 14 | API_LIMITER(1004, "API限流保护"), 15 | ILLEGAL_CONCURRENT_CALL(1005, "非法重复调用"), 16 | TIME_OUT(1006, "系统超时"), 17 | CONNECTION_TIME_OUT(1007, "连接超时"), 18 | VERIFY_FAILED(1008, "验签失败"), 19 | VERIFY_EXPIRE(1009, "签名已过期"), 20 | UNZIP_FAILED(1010, "解压失败"), 21 | ENCODER_FAILED(1011, "编码失败"), 22 | DECODER_FAILED(1012, "解码失败"), 23 | CONNECT_ERROR(1013, "连接异常"), 24 | MISSING_SERVER_PROVIDER(1014, "缺失服务提供者"), 25 | SYSTEM_ERROR(1015, "系统错误"), 26 | 27 | PARAM_ERROR(1500, "参数错误"), 28 | // Request method 'POST|GET' not supported 29 | NOT_SUPPORT_METHOD(1501, "不支持的调用"), 30 | NOT_SUPPORT_OPERATOR(1502, "不支持的操作"), 31 | SERVER_REFUSE(1502, "服务拒绝"), 32 | ILLEGAL_ARGUMENT(1503, "非法参数"), 33 | JSON_SERIALIZE_FAIL(1504, "json序列化失败"), 34 | // cache穿透并发超时 35 | CONCURRENT_CACHE_KEY_TIMEOUT(1505, "concurrent cache key timeout"), 36 | PARAM_MISSING(1506, "缺少参数"); 37 | private int errorCode; 38 | private String errorReason; 39 | 40 | @Override 41 | public int getErrorCode() { 42 | return this.errorCode; 43 | } 44 | 45 | @Override 46 | public String getErrorReason() { 47 | return this.errorReason; 48 | } 49 | 50 | private ErrorCode(int errorCode, String errorReason) { 51 | this.errorCode = errorCode; 52 | this.errorReason = errorReason; 53 | } 54 | 55 | public static boolean isMember(int code) { 56 | for (ErrorCode errorCode : ErrorCode.values()) { 57 | if (code == errorCode.getErrorCode()) { 58 | return true; 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/bytes/KryoSerialize.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.bytes; 2 | 3 | import com.esotericsoftware.kryo.Kryo; 4 | import com.esotericsoftware.kryo.io.Input; 5 | import com.esotericsoftware.kryo.io.Output; 6 | import com.esotericsoftware.kryo.serializers.JavaSerializer; 7 | 8 | import java.io.ByteArrayInputStream; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author niuzhiwei 14 | */ 15 | public class KryoSerialize implements SerializeByteApi { 16 | 17 | public static KryoSerialize INSTANCE = new KryoSerialize(); 18 | 19 | @Override 20 | public byte[] encode(Object t) { 21 | Kryo kryo = new Kryo(); 22 | kryo.setReferences(false); 23 | kryo.register(t.getClass(), new JavaSerializer()); 24 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 25 | Output output = new Output(baos); 26 | try { 27 | kryo.writeClassAndObject(output, t); 28 | output.flush(); 29 | output.close(); 30 | return baos.toByteArray(); 31 | } finally { 32 | try { 33 | baos.flush(); 34 | baos.close(); 35 | } catch (IOException e) { 36 | } 37 | } 38 | } 39 | 40 | @Override 41 | @SuppressWarnings({ "unchecked" }) 42 | public T decode(byte[] bytes, Class clazz) { 43 | Kryo kryo = new Kryo(); 44 | kryo.setReferences(false); 45 | kryo.register(clazz, new JavaSerializer()); 46 | 47 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 48 | Input input = new Input(byteArrayInputStream); 49 | try { 50 | return (T) kryo.readClassAndObject(input); 51 | } finally { 52 | input.close(); 53 | try { 54 | byteArrayInputStream.close(); 55 | } catch (IOException e) { 56 | } 57 | } 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/conditions/GroupByCondition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.conditions; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | *

8 | * SQL 分组条件 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class GroupByCondition implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = -9062303883253151334L; 16 | /** 17 | * 分组字段 18 | */ 19 | private List groupFields; 20 | 21 | /** 22 | * 统计函数 23 | */ 24 | private List functionConditions; 25 | 26 | /** 27 | * having 筛选 28 | *

29 | * TODO 目前考察es的过滤API,未提供对聚合结果的过滤 30 | * 1、继续学习,自定义桶过滤器; 31 | * 2、在封装结果层面进行简单过滤; 32 | */ 33 | //private List havingConditions; 34 | public GroupByCondition() { 35 | } 36 | 37 | public List getGroupFields() { 38 | return groupFields; 39 | } 40 | 41 | public void setGroupFields(List groupFields) { 42 | this.groupFields = groupFields; 43 | } 44 | 45 | public List getFunctionConditions() { 46 | return functionConditions; 47 | } 48 | 49 | public void setFunctionConditions(List functionConditions) { 50 | this.functionConditions = functionConditions; 51 | } 52 | 53 | /*public List getHavingConditions() { 54 | return havingConditions; 55 | } 56 | 57 | public void setHavingConditions(List havingConditions) { 58 | this.havingConditions = havingConditions; 59 | }*/ 60 | 61 | @Override 62 | public String toString() { 63 | final StringBuilder sb = new StringBuilder("GroupByCondition{"); 64 | sb.append("groupFields=").append(groupFields); 65 | sb.append(", functionConditions=").append(functionConditions); 66 | //sb.append(", havingConditions=").append(havingConditions); 67 | sb.append('}'); 68 | return sb.toString(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/parser/ParserDateFactory.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json.parser; 2 | 3 | 4 | import java.text.ParseException; 5 | import java.util.Date; 6 | import java.util.HashSet; 7 | import java.util.Iterator; 8 | import java.util.Set; 9 | 10 | /** 11 | * @author niuzhiwei 12 | */ 13 | public class ParserDateFactory { 14 | 15 | private static final Set dateTypes = new HashSet<>(); 16 | public static final DateType DEFAULT = new DateTimeType(); 17 | static { 18 | dateTypes.add(new LongType()); 19 | dateTypes.add(new YmdDateType()); 20 | dateTypes.add(new DateTimeType()); 21 | dateTypes.add(new GMTDateTimeType()); 22 | } 23 | 24 | /** 25 | * 注册日期类型解析器 26 | * 27 | * @param dateType 28 | * @return 29 | */ 30 | public static boolean registerDateType(DateType dateType) { 31 | return dateTypes.add(dateType); 32 | } 33 | 34 | public static Date parser(String value) throws ParseException { 35 | Iterator iterator = dateTypes.iterator(); 36 | while (iterator.hasNext()) { 37 | DateType dateType = iterator.next(); 38 | if (dateType.matches(value)) { 39 | try { 40 | Date date = dateType.parse(value); 41 | if (date != null) { 42 | return date; 43 | } 44 | } catch (Exception e) { 45 | } 46 | } 47 | } 48 | return DEFAULT.parse(value); 49 | } 50 | 51 | public static interface DateType { 52 | /** 53 | * 验证是否匹配解析格式 54 | * 55 | * @param value 56 | * @return 57 | */ 58 | public boolean matches(String value); 59 | 60 | /** 61 | * 解析Value到Date类型 62 | * 63 | * @param value 64 | * @return 65 | */ 66 | public Date parse(String value) throws ParseException; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/ESResponse.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.PageCondition; 5 | 6 | import java.io.Serializable; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | *

12 | * ES响应对象 13 | * 14 | * @author niuzhiwei 15 | */ 16 | public class ESResponse extends BaseESObject implements Serializable { 17 | 18 | private static final long serialVersionUID = 4936774622586572237L; 19 | 20 | private List esDocuments; 21 | 22 | /** 23 | * 根据提供的函数名称进行相关取值操作 24 | */ 25 | private Map>> countResult; 26 | /** 27 | * 分页条件,当且仅当调用方分页后有值 28 | */ 29 | private PageCondition pageCondition; 30 | 31 | public ESResponse() { 32 | } 33 | 34 | public List getEsDocuments() { 35 | return esDocuments; 36 | } 37 | 38 | public void setEsDocuments(List esDocuments) { 39 | this.esDocuments = esDocuments; 40 | } 41 | 42 | public Map>> getCountResult() { 43 | return countResult; 44 | } 45 | 46 | public void setCountResult(Map>> countResult) { 47 | this.countResult = countResult; 48 | } 49 | 50 | public PageCondition getPageCondition() { 51 | return pageCondition; 52 | } 53 | 54 | public void setPageCondition(PageCondition pageCondition) { 55 | this.pageCondition = pageCondition; 56 | } 57 | 58 | /** 59 | * 格式未进行约束,调用方请勿尝试解析该字符串 60 | */ 61 | @Override 62 | public String toString() { 63 | final StringBuilder sb = new StringBuilder("ESResponse{"); 64 | sb.append(super.toString()).append(","); 65 | sb.append("esDocuments=").append(esDocuments); 66 | sb.append(", countResult=").append(countResult); 67 | sb.append(", pageCondition=").append(pageCondition); 68 | sb.append('}'); 69 | return sb.toString(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/conditions/InnerHitsCondition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject.conditions; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | *

8 | * 内部击中条件控制,目前用于去重使用 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class InnerHitsCondition implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = -7164665005840381704L; 16 | /** 17 | * 此次命中的名字 18 | */ 19 | private String hitName; 20 | 21 | /** 22 | * 内部小范围的排序条件 23 | */ 24 | private List orderConditions; 25 | 26 | /** 27 | * 所需域过滤 28 | */ 29 | private List fieldNames; 30 | 31 | /** 32 | * 此次命中需要返回上部文档数目 33 | */ 34 | private int hitSize = 1; 35 | 36 | public InnerHitsCondition() { 37 | } 38 | 39 | public String getHitName() { 40 | return hitName; 41 | } 42 | 43 | public void setHitName(String hitName) { 44 | this.hitName = hitName; 45 | } 46 | 47 | public List getOrderConditions() { 48 | return orderConditions; 49 | } 50 | 51 | public void setOrderConditions(List orderConditions) { 52 | this.orderConditions = orderConditions; 53 | } 54 | 55 | public List getFieldNames() { 56 | return fieldNames; 57 | } 58 | 59 | public void setFieldNames(List fieldNames) { 60 | this.fieldNames = fieldNames; 61 | } 62 | 63 | public int getHitSize() { 64 | return hitSize; 65 | } 66 | 67 | public void setHitSize(int hitSize) { 68 | this.hitSize = hitSize; 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | final StringBuilder sb = new StringBuilder("InnerHitsCondition{"); 74 | sb.append("hitName='").append(hitName).append('\''); 75 | sb.append(", orderConditions=").append(orderConditions); 76 | sb.append(", fieldNames=").append(fieldNames); 77 | sb.append(", hitSize=").append(hitSize); 78 | sb.append('}'); 79 | return sb.toString(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/json/JacksonSerialize.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.json; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.SerializationFeature; 7 | import com.fasterxml.jackson.databind.module.SimpleModule; 8 | import com.elastic.search.common.exception.ErrorCode; 9 | 10 | import java.io.IOException; 11 | import java.util.Date; 12 | import java.util.TimeZone; 13 | 14 | public class JacksonSerialize implements SerializeJsonApi { 15 | public static final ObjectMapper mapper = new ObjectMapper(); 16 | static { 17 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 18 | mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 19 | // mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false); 20 | // mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); 21 | SimpleModule module = new SimpleModule(); 22 | module.addDeserializer(Date.class, new DateDeserializer()); 23 | mapper.registerModule(module); 24 | // 解决jackson序列化时默认的时区是UTC导致Date类型慢8小时问题 25 | mapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); 26 | } 27 | public static JacksonSerialize INSTANCE = new JacksonSerialize(); 28 | 29 | @Override 30 | public String encode(Object obj) { 31 | try { 32 | return mapper.writeValueAsString(obj); 33 | } catch (JsonProcessingException e) { 34 | throw ErrorCode.JSON_SERIALIZE_FAIL.throwError("encode(" + obj + ")error").setCause(e); 35 | } 36 | } 37 | 38 | @Override 39 | public T decode(String json, Class type) { 40 | try { 41 | return mapper.readValue(json, type); 42 | } catch (IOException e) { 43 | throw ErrorCode.JSON_SERIALIZE_FAIL.throwError("decode(" + json + "," + type + ")error").setCause(e); 44 | } 45 | } 46 | 47 | @Override 48 | public SerializeJsonApi getInstance() { 49 | return INSTANCE; 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/boot/SearchBeanContext.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.boot; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * es 上下文 14 | * 15 | * @author niuzhiwei 16 | */ 17 | public class SearchBeanContext implements ApplicationContextAware { 18 | 19 | /** 20 | * 上下文 21 | */ 22 | private static ApplicationContext applicationContext; 23 | 24 | /** 25 | * 默认构造方法,注入上下文, 26 | * implements ApplicationContextAware 自动调用 27 | * 28 | * @param applicationContext 29 | * @return 30 | */ 31 | @Override 32 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 33 | SearchBeanContext.applicationContext = applicationContext; 34 | } 35 | 36 | /** 37 | * 获取 bean 38 | */ 39 | public static T getBean(Class clazz) { 40 | T obj; 41 | try { 42 | //从上下文获取 bean 43 | obj = applicationContext.getBean(clazz); 44 | } catch (Exception e) { 45 | obj = null; 46 | } 47 | //返回 bean 48 | return obj; 49 | } 50 | 51 | 52 | /** 53 | * 获取 bean 的类型 54 | */ 55 | public static List getBeansOfType(Class clazz) { 56 | //声明一个结果 57 | Map map; 58 | try { 59 | //获取类型 60 | map = applicationContext.getBeansOfType(clazz); 61 | } catch (Exception e) { 62 | map = null; 63 | } 64 | //返回 bean 的类型 65 | return map == null ? null : new ArrayList<>(map.values()); 66 | } 67 | 68 | 69 | /** 70 | * 获取所有被注解的 bean 71 | */ 72 | public static Map getBeansWithAnnotation(Class annotation) { 73 | Map map; 74 | try { 75 | //获取注解的 bean 76 | map = applicationContext.getBeansWithAnnotation(annotation); 77 | } catch (Exception e) { 78 | map = null; 79 | } 80 | return map; 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/UpdateESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.enums.OperateTypeEnum; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | *

10 | * es 更新请求参数 11 | * 12 | * @author niuzhiwei 13 | */ 14 | public class UpdateESObject extends SaveESObject implements Serializable { 15 | 16 | private static final long serialVersionUID = -6759532047078992621L; 17 | 18 | /** 19 | * 若要实现数据一致,请指定,要更新文档的版本 当es中文档版本与指定版本一致时更新成功,否则失败; 20 | */ 21 | private int docVersion; 22 | 23 | /** 24 | * nested数据类型更新 25 | */ 26 | private NestedESObject nestedESObject; 27 | 28 | /** 29 | * 嵌套数据操作类型 30 | */ 31 | private OperateTypeEnum nestedOperateType; 32 | 33 | public UpdateESObject() { 34 | } 35 | 36 | public UpdateESObject(String systemName, String indexName, String typeName) { 37 | super(systemName, indexName, typeName); 38 | } 39 | 40 | /** 41 | * 更新类型 42 | * 43 | * @return 44 | */ 45 | public boolean nestedUpdate() { 46 | return nestedESObject != null; 47 | } 48 | 49 | public int getDocVersion() { 50 | return docVersion; 51 | } 52 | 53 | public void setDocVersion(int docVersion) { 54 | this.docVersion = docVersion; 55 | } 56 | 57 | public NestedESObject getNestedESObject() { 58 | return nestedESObject; 59 | } 60 | 61 | public void setNestedESObject(NestedESObject nestedESObject) { 62 | this.nestedESObject = nestedESObject; 63 | } 64 | 65 | public OperateTypeEnum getNestedOperateType() { 66 | return nestedOperateType; 67 | } 68 | 69 | public void setNestedOperateType(OperateTypeEnum nestedOperateType) { 70 | this.nestedOperateType = nestedOperateType; 71 | } 72 | 73 | /** 74 | * 格式未进行约束,调用方请勿尝试解析该字符串 75 | */ 76 | @Override 77 | public String toString() { 78 | final StringBuilder sb = new StringBuilder("UpdateESObject{"); 79 | sb.append(super.toString()); 80 | sb.append(", docVersion=").append(docVersion); 81 | sb.append(", nestedESObject=").append(nestedESObject); 82 | sb.append(", nestedOperateType=").append(nestedOperateType); 83 | sb.append('}'); 84 | return sb.toString(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/bean/Field.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.bean; 2 | 3 | 4 | import com.elastic.search.elasticsearch.infrastructure.enums.FieldTypeEnum; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.io.Serializable; 8 | import java.util.Objects; 9 | 10 | /** 11 | * 字段类型变更实体 12 | */ 13 | public class Field implements Serializable { 14 | private static final long serialVersionUID = 4819211937495431355L; 15 | /** 16 | * 原字段名 17 | */ 18 | private String originName; 19 | /** 20 | * 新字段名 21 | */ 22 | private String currentName; 23 | /** 24 | * 字段类型 25 | */ 26 | private FieldTypeEnum fieldType; 27 | 28 | public Boolean isValid() { 29 | return null != this.fieldType && !StringUtils.isBlank(this.originName) && !StringUtils.isBlank(this.currentName) ? true : false; 30 | } 31 | 32 | public Field() { 33 | } 34 | 35 | public String getOriginName() { 36 | return this.originName; 37 | } 38 | 39 | public String getCurrentName() { 40 | return this.currentName; 41 | } 42 | 43 | public FieldTypeEnum getFieldType() { 44 | return this.fieldType; 45 | } 46 | 47 | public void setOriginName(String originName) { 48 | this.originName = originName; 49 | } 50 | 51 | public void setCurrentName(String currentName) { 52 | this.currentName = currentName; 53 | } 54 | 55 | public void setFieldType(FieldTypeEnum fieldType) { 56 | this.fieldType = fieldType; 57 | } 58 | 59 | @Override 60 | public boolean equals(Object o) { 61 | if (this == o) { 62 | return true; 63 | } 64 | if (!(o instanceof Field)) { 65 | return false; 66 | } 67 | Field field = (Field) o; 68 | return Objects.equals(originName, field.originName) && 69 | Objects.equals(currentName, field.currentName) && 70 | fieldType == field.fieldType; 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | return Objects.hash(originName, currentName, fieldType); 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return "Field(originName=" + this.getOriginName() + ", currentName=" + this.getCurrentName() + ", fieldType=" + this.getFieldType() + ")"; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/searchservice/ESStatisticServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.searchservice; 2 | 3 | 4 | import com.elastic.search.common.domain.SearchBaseResult; 5 | import com.elastic.search.elasticsearch.service.ESStatisticOperatorService; 6 | import com.elastic.search.elasticsearch.dataobject.CollapseQueryObject; 7 | import com.elastic.search.elasticsearch.dataobject.ESResponse; 8 | import com.elastic.search.elasticsearch.dataobject.StatisticESObject; 9 | import com.elastic.search.elasticsearch.validator.CollapseQueryValidator; 10 | import com.elastic.search.elasticsearch.validator.StatisticByConditionsValidator; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | import java.util.Map; 16 | 17 | /** 18 | * @author niuzhiwei 19 | */ 20 | public class ESStatisticServiceImpl implements ESStatisticService { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(ESStatisticServiceImpl.class); 23 | 24 | @Autowired 25 | private StatisticByConditionsValidator statisticByConditionsValidator; 26 | 27 | @Autowired 28 | private CollapseQueryValidator collapseQueryValidator; 29 | 30 | @Autowired 31 | private ESStatisticOperatorService esStatisticOperatorService; 32 | 33 | @Override 34 | public SearchBaseResult> statisticByConditions(StatisticESObject esObject) { 35 | LOGGER.info("statistic service request param:{}.", esObject); 36 | final SearchBaseResult> validateResult = statisticByConditionsValidator.validate(esObject); 37 | if (validateResult.isFailed()) { 38 | return validateResult; 39 | } 40 | return esStatisticOperatorService.statisticByConditions(esObject); 41 | } 42 | 43 | @Override 44 | public SearchBaseResult> collapse(CollapseQueryObject esObject) { 45 | LOGGER.info("collapse service request param:{}.", esObject); 46 | 47 | final SearchBaseResult validateResult = collapseQueryValidator.validator(esObject); 48 | if (validateResult.isFailed()) { 49 | final SearchBaseResult> dataResult = new SearchBaseResult<>(); 50 | dataResult.setStatus(validateResult.getStatus()); 51 | return dataResult; 52 | } 53 | return esStatisticOperatorService.collapse(esObject); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/domain/Status.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author niuzhiwei 10 | */ 11 | public class Status implements Serializable { 12 | 13 | private static final long serialVersionUID = -8847081762490398492L; 14 | @JsonProperty("statusCode") 15 | @JsonInclude(JsonInclude.Include.NON_NULL) 16 | private int statusCode = 0; 17 | @JsonProperty("statusReason") 18 | @JsonInclude(JsonInclude.Include.NON_NULL) 19 | private String statusReason; 20 | 21 | public Status() { 22 | 23 | } 24 | 25 | public Status(int statusCode, String message) { 26 | this(statusCode, message, true); 27 | } 28 | 29 | /** 30 | * @param statusCode 31 | * @param message 32 | * @param appendSysCode 是否追加系统编码 33 | */ 34 | public Status(int statusCode, String message, boolean appendSysCode) { 35 | if (appendSysCode) { 36 | if (statusCode != 0) { 37 | this.statusCode = SystemManager.appendSysCode(statusCode); 38 | } 39 | } else { 40 | this.statusCode = statusCode; 41 | } 42 | this.statusReason = message; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "{\"statusCode\":" + statusCode + ",\"statusReason\":\"" + statusReason + "\"}"; 48 | } 49 | 50 | public int getStatusCode() { 51 | return statusCode; 52 | } 53 | 54 | /** 55 | * 注意该种方式只在是使用序列化框架是使用,如果编码是调用请使用 56 | *

57 | * 58 | * setStatusCode(int statusCode, boolean appendSysCode) 59 | * 60 | * 61 | * @param statusCode 62 | */ 63 | @SuppressWarnings("unused") 64 | private void setStatusCode(int statusCode) { 65 | this.statusCode = statusCode; 66 | } 67 | 68 | /** 69 | * 注意编程式方式调用 70 | * 71 | * @param statusCode 72 | * @param appendSysCode 73 | */ 74 | public void setStatusCode(int statusCode, boolean appendSysCode) { 75 | if (statusCode != 0) { 76 | if (appendSysCode) { 77 | this.statusCode = SystemManager.appendSysCode(statusCode); 78 | } else { 79 | this.statusCode = statusCode; 80 | } 81 | } 82 | } 83 | 84 | public String getStatusReason() { 85 | return statusReason; 86 | } 87 | 88 | public void setStatusReason(String statusReason) { 89 | this.statusReason = statusReason; 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/NestedESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.Arrays; 5 | 6 | /** 7 | *

8 | * 嵌套对象的增删改请求参数(目前支持3级嵌套) 9 | * 10 | * @author niuzhiwei 11 | */ 12 | public class NestedESObject implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = -1318856812842748868L; 16 | /** 17 | * 结构文档的根域 18 | */ 19 | private String fieldName; 20 | 21 | /** 22 | * {@link #fieldName} 是否为集合 23 | */ 24 | private boolean isList; 25 | 26 | /** 27 | * 若 {@link #isList} 是集合, 28 | * 需要修改内嵌对象的id,若为空,则进行全部匹配进行更新 29 | */ 30 | private String[] idValues; 31 | 32 | /** 33 | * 下级嵌套说明 34 | */ 35 | private NestedESObject nextNestedESObject; 36 | 37 | public NestedESObject() { 38 | } 39 | 40 | /** 41 | * 判断是否有条件限制 42 | * 43 | * @return true 有条件限制;false 无条件限制; 44 | */ 45 | public boolean hasRestriction() { 46 | return idValues != null && idValues.length > 0; 47 | } 48 | 49 | /** 50 | * 判断是否有下一个 51 | * 52 | * @return true 有;false 无; 53 | */ 54 | public boolean hasNext() { 55 | return nextNestedESObject != null; 56 | } 57 | 58 | public String getFieldName() { 59 | return fieldName; 60 | } 61 | 62 | public void setFieldName(String fieldName) { 63 | this.fieldName = fieldName; 64 | } 65 | 66 | public boolean isList() { 67 | return isList; 68 | } 69 | 70 | public void setList(boolean list) { 71 | isList = list; 72 | } 73 | 74 | public String[] getIdValues() { 75 | return idValues; 76 | } 77 | 78 | public void setIdValues(String[] idValues) { 79 | this.idValues = idValues; 80 | } 81 | 82 | public NestedESObject getNextNestedESObject() { 83 | return nextNestedESObject; 84 | } 85 | 86 | public void setNextNestedESObject(NestedESObject nextNestedESObject) { 87 | this.nextNestedESObject = nextNestedESObject; 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | final StringBuilder sb = new StringBuilder("NestedESObject{"); 93 | sb.append("fieldName='").append(fieldName).append('\''); 94 | sb.append(", isList=").append(isList); 95 | sb.append(", idValues=").append(Arrays.toString(idValues)); 96 | sb.append(", nextNestedESObject=").append(nextNestedESObject); 97 | sb.append('}'); 98 | return sb.toString(); 99 | } 100 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/executor/impl/BaseSearchTypeIndexModifyExecutor.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.executor.impl; 2 | 3 | 4 | import com.elastic.search.common.boot.SearchBeanContext; 5 | import com.elastic.search.common.exception.FrameworkException; 6 | import com.elastic.search.elasticsearch.infrastructure.bean.Field; 7 | import com.elastic.search.elasticsearch.infrastructure.conf.BaseTypeIndexConfiguration; 8 | import com.elastic.search.elasticsearch.infrastructure.consts.FrameworkExceptionConstants; 9 | import com.elastic.search.elasticsearch.search.utils.ModifyIndexFactory; 10 | import org.elasticsearch.search.sort.SortOrder; 11 | 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | /** 17 | * ES索引类型字段变更 18 | * 19 | * @author niuzhiwei 20 | */ 21 | public abstract class BaseSearchTypeIndexModifyExecutor { 22 | 23 | /** 24 | * 获取索引胚子 25 | * 26 | * @return 27 | */ 28 | public abstract BaseTypeIndexConfiguration getConfig(); 29 | 30 | 31 | public synchronized Boolean execute(List fields) { 32 | if (null == fields || fields.size() == 0) { 33 | return false; 34 | } 35 | BaseTypeIndexConfiguration conf = this.getConfig(); 36 | try { 37 | boolean result = SearchBeanContext.getBean(ModifyIndexFactory.class).reindex(conf.getIndexName(), conf.getTypeName(), properties -> { 38 | fields.forEach(field -> { 39 | if (field.isValid()) { 40 | Map f = (Map) properties.get(field.getOriginName()); 41 | if (null == f) {//新增字段 42 | f = new HashMap<>(); 43 | f.put("type", field.getFieldType().getType()); 44 | properties.put(field.getCurrentName(), f); 45 | } else if (!field.getCurrentName().equals(field.getOriginName())) {//字段名与类型变更 46 | f = new HashMap<>(); 47 | f.put("type", field.getFieldType().getType()); 48 | properties.put(field.getCurrentName(), f); 49 | properties.remove(field.getOriginName()); 50 | } else {//变更字段类型 51 | f.put("type", field.getFieldType().getType()); 52 | } 53 | } 54 | }); 55 | return properties; 56 | }, "id", SortOrder.ASC); 57 | return result; 58 | } catch (Exception e) { 59 | throw new FrameworkException(FrameworkExceptionConstants.ERROR_SEARCH_ENGINES, "搜索引擎字段变更异常", e); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/SaveESObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | import java.io.Serializable; 4 | import java.util.Collections; 5 | import java.util.Map; 6 | 7 | /** 8 | *

9 | * es 存储数请求参数 10 | *

11 | * 注意: 1、针对valueMap属性,value 为集合类型的实际类型需保持一致,否则会导致es索引失败; 2、es 12 | * 存储的浮点型数字会有精度缺失问题,建议以long或String存储相关数据; 13 | * 14 | * @author niuzhiwei 15 | */ 16 | public class SaveESObject extends BaseESObject implements Serializable { 17 | 18 | private static final long serialVersionUID = 3203853796997438161L; 19 | 20 | /** 21 | * {@link SaveESObject#dataMap} 唯一标志 22 | */ 23 | private Map ukMap; 24 | 25 | /** 26 | * 文档数据内容 27 | */ 28 | private Map dataMap; 29 | /** 30 | * 设置是否立即刷新到磁盘 31 | */ 32 | private boolean refresh = true; 33 | 34 | public SaveESObject() { 35 | } 36 | 37 | public SaveESObject(String systemName, String indexName, String typeName) { 38 | super(systemName, indexName, typeName); 39 | } 40 | 41 | public Map getUkMap() { 42 | return ukMap; 43 | } 44 | 45 | /** 46 | * 请使用setId 47 | */ 48 | @Deprecated 49 | public void setUkMap(Map ukMap) { 50 | if (ukMap != null && ukMap.size() == 1) { 51 | if (ukMap.containsKey("id")) { 52 | this.ukMap = ukMap; 53 | return; 54 | } 55 | } 56 | throw new IllegalArgumentException("无效的参数(只支持id属性),建议统一使用setId(...)方法"); 57 | } 58 | 59 | /** 60 | * 设置Document主键ID (可以使用业务数据主键ID) 61 | * 62 | * @param id 63 | */ 64 | public void setId(Object id) { 65 | this.setUkMap(Collections.singletonMap("id", id)); 66 | } 67 | 68 | public Map getDataMap() { 69 | return dataMap; 70 | } 71 | 72 | public void setDataMap(Map dataMap) { 73 | this.dataMap = dataMap; 74 | } 75 | 76 | /** 77 | * 格式未进行约束,调用方请勿尝试解析该字符串 78 | */ 79 | @Override 80 | public String toString() { 81 | final StringBuilder sb = new StringBuilder("SaveESObject{"); 82 | sb.append(super.toString()); 83 | sb.append(", ukMap=").append(ukMap); 84 | sb.append(", dataMap=").append(dataMap); 85 | sb.append('}'); 86 | return sb.toString(); 87 | } 88 | 89 | public boolean isRefresh() { 90 | return refresh; 91 | } 92 | 93 | /** 94 | * 设置是否立即刷新到磁盘 95 | * 96 | * @param refresh 97 | */ 98 | public SaveESObject setRefresh(boolean refresh) { 99 | this.refresh = refresh; 100 | return this; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/CollapseQueryValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.CollapseQueryObject; 8 | import com.elastic.search.elasticsearch.dataobject.conditions.InnerHitsCondition; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @author niuzhiwei 17 | */ 18 | @Slf4j 19 | public class CollapseQueryValidator { 20 | 21 | public SearchBaseResult validator(CollapseQueryObject esObject) { 22 | SearchBaseResult dataResult = new SearchBaseResult<>(); 23 | 24 | if (null == esObject) { 25 | log.warn("瓦解查询请求参数为空"); 26 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数为空")); 27 | } 28 | 29 | final String systemName = esObject.getSystemName(); 30 | if (StringUtils.isBlank(systemName)) { 31 | log.warn("瓦解查询请求参数【systemName】为空"); 32 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数【systemName】为空")); 33 | } 34 | 35 | final String indexName = esObject.getIndexName(); 36 | if (StringUtils.isBlank(indexName)) { 37 | log.warn("瓦解查询请求参数【indexName】为空"); 38 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数【indexName】为空")); 39 | } 40 | 41 | final String fieldName = esObject.getFieldName(); 42 | if (StringUtils.isBlank(fieldName)) { 43 | log.warn("瓦解查询请求参数【fieldName】为空"); 44 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数【fieldName】为空")); 45 | } 46 | 47 | final List innerHitsConditions = esObject.getInnerHitsConditions(); 48 | if (CollectionUtils.isEmpty(innerHitsConditions)) { 49 | log.warn("瓦解查询请求参数【innerHitsConditions】为空"); 50 | dataResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数【innerHitsConditions】为空")); 51 | } 52 | 53 | for (InnerHitsCondition innerHitsCondition : innerHitsConditions) { 54 | final String hitName = innerHitsCondition.getHitName(); 55 | if (StringUtils.isBlank(hitName)) { 56 | log.warn("瓦解查询请求参数【InnerHitsCondition#hitName】为空"); 57 | dataResult 58 | .setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数【InnerHitsCondition#hitName】为空")); 59 | } 60 | } 61 | 62 | return dataResult; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/index/ScanDocuments.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.index; 2 | 3 | import org.elasticsearch.action.search.SearchResponse; 4 | import org.elasticsearch.client.Client; 5 | import org.elasticsearch.search.SearchHit; 6 | import org.elasticsearch.search.SearchHits; 7 | import org.elasticsearch.search.sort.SortOrder; 8 | 9 | import java.util.Iterator; 10 | import java.util.concurrent.atomic.AtomicBoolean; 11 | import java.util.concurrent.atomic.AtomicInteger; 12 | 13 | /** 14 | * @author niuzhiwei 15 | */ 16 | public class ScanDocuments implements Iterator { 17 | 18 | private String index; 19 | private String type; 20 | private int size; 21 | private SearchHits hits; 22 | private AtomicInteger next_pos = new AtomicInteger(0); 23 | private int tmp_index = 0; 24 | private Client esClient; 25 | long totalHits = 0; 26 | String sortName; 27 | SortOrder sortOrder; 28 | private AtomicBoolean isStart = new AtomicBoolean(false); 29 | 30 | public ScanDocuments(String index, String type, int size) { 31 | this.index = index; 32 | this.type = type; 33 | this.size = size; 34 | 35 | } 36 | 37 | @Override 38 | public boolean hasNext() { 39 | if (isStart.get()) { 40 | if (hits != null && hits.getHits().length > tmp_index) { 41 | return true; 42 | } 43 | execute(); 44 | return hits.getHits().length > 0; 45 | } 46 | throw new IllegalArgumentException("请先调用start()"); 47 | } 48 | 49 | @Override 50 | public SearchHit next() { 51 | if (hits.getHits().length > tmp_index) { 52 | try { 53 | return hits.getAt(tmp_index); 54 | } finally { 55 | tmp_index++; 56 | } 57 | } else { 58 | return null; 59 | } 60 | } 61 | 62 | public void start(Client esClient, String sortName, SortOrder order) { 63 | this.esClient = esClient; 64 | this.sortName = sortName; 65 | this.sortOrder = order; 66 | isStart.set(true); 67 | // SearchResponse response = 68 | // esClient.prepareSearch(index).setTypes(type).setQuery(QueryBuilders.matchAllQuery()) 69 | // .setSearchType(SearchType.DEFAULT).setScroll(timeValue).setSize(size).get(); 70 | // this.scrollId = response.getScrollId(); 71 | } 72 | 73 | public void execute() { 74 | SearchResponse response = esClient.prepareSearch(index).setTypes(type).setFrom(next_pos.get()) 75 | .addSort(sortName, sortOrder).setSize(size).get(); 76 | this.hits = response.getHits(); 77 | // 调整下一次加载数据的偏移量 78 | next_pos.getAndAdd(size); 79 | // 重置数据索引偏移量 80 | tmp_index = 0; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/domain/PagedList.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * @param 10 | * @author niuzhiwei 11 | */ 12 | public class PagedList implements Serializable { 13 | 14 | 15 | private static final long serialVersionUID = 8160823395759291587L; 16 | 17 | /** 18 | * 数据项 19 | */ 20 | private List items; 21 | /** 22 | * 总数量 23 | */ 24 | private int totalCount; 25 | /** 26 | * 当前页码 27 | */ 28 | private int currentPage; 29 | /** 30 | * 每页条数 31 | */ 32 | private int pageSize; 33 | 34 | public List getItems() { 35 | return items; 36 | } 37 | 38 | public void setItems(List items) { 39 | this.items = items; 40 | } 41 | 42 | public int getTotalCount() { 43 | return totalCount; 44 | } 45 | 46 | public void setTotalCount(int totalCount) { 47 | this.totalCount = totalCount; 48 | } 49 | 50 | public int getCurrentPage() { 51 | return currentPage; 52 | } 53 | 54 | public void setCurrentPage(int currentPage) { 55 | this.currentPage = currentPage; 56 | } 57 | 58 | public int getPageSize() { 59 | return pageSize; 60 | } 61 | 62 | public void setPageSize(int pageSize) { 63 | this.pageSize = pageSize; 64 | } 65 | 66 | public static PagedList createInstance(int pageNo, int pageSize, int totalCount, List items) { 67 | PagedList pagedList = new PagedList(); 68 | pagedList.setCurrentPage(pageNo); 69 | pagedList.setPageSize(pageSize); 70 | pagedList.setTotalCount(totalCount); 71 | pagedList.setItems(items); 72 | return pagedList; 73 | } 74 | 75 | public static PagedList createInstance(int pageNo, int pageSize, int totalCount, Class t) { 76 | PagedList pagedList = new PagedList(); 77 | pagedList.setCurrentPage(pageNo); 78 | pagedList.setPageSize(pageSize); 79 | pagedList.setTotalCount(totalCount); 80 | return pagedList; 81 | } 82 | 83 | @JsonIgnore 84 | public int getFirstIndex() { 85 | return (this.getCurrentPage() - 1) * pageSize; 86 | } 87 | 88 | @JsonIgnore 89 | public boolean isValidPageNo() { 90 | long totalPage = 0; 91 | if (totalCount % pageSize == 0) { 92 | totalPage = totalCount / pageSize; 93 | } else { 94 | totalPage = totalCount / pageSize + 1; 95 | } 96 | if (getCurrentPage() < 1 || getCurrentPage() > totalPage) { 97 | return false; 98 | } 99 | return true; 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/validator/BaseUpdateValidator.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.validator; 2 | 3 | 4 | import com.elastic.search.common.domain.ESErrorCode; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.domain.Status; 7 | import com.elastic.search.elasticsearch.dataobject.NestedESObject; 8 | import com.elastic.search.elasticsearch.dataobject.UpdateESObject; 9 | import com.elastic.search.elasticsearch.dataobject.enums.OperateTypeEnum; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | import java.util.Map; 13 | 14 | /** 15 | * @author niuzhiwei 16 | */ 17 | @Slf4j 18 | public class BaseUpdateValidator extends BaseValidator { 19 | 20 | public SearchBaseResult validate(UpdateESObject obj) { 21 | 22 | final SearchBaseResult baseValidateResult = super.baseValidate(obj); 23 | if (baseValidateResult.isFailed()) { 24 | log.warn("es base request param error ,systemName or indexName or typeName should not null!"); 25 | return baseValidateResult; 26 | } 27 | 28 | final Map dataMap = obj.getDataMap(); 29 | if (dataMap == null) { 30 | log.warn("update es object ,dataMap should not null!"); 31 | baseValidateResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "请求参数【dataMap】为空")); 32 | } 33 | 34 | final NestedESObject nestedESObject = obj.getNestedESObject(); 35 | final OperateTypeEnum nestedOperateType = obj.getNestedOperateType(); 36 | 37 | if (nestedESObject != null) { 38 | final String fieldName = nestedESObject.getFieldName(); 39 | if (fieldName == null) { 40 | log.warn("nested update es object ,fieldName should not null!"); 41 | baseValidateResult.setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "嵌套更新请求参数【fieldName】为空")); 42 | } 43 | 44 | if (nestedOperateType == null) { 45 | log.warn("nested update es object ,operate type should not null!"); 46 | baseValidateResult 47 | .setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, "嵌套更新请求参数【nestedOperateType】为空")); 48 | } 49 | 50 | if (!nestedESObject.isList()) { 51 | final NestedESObject nextNestedESObject = nestedESObject.getNextNestedESObject(); 52 | if (nextNestedESObject == null) { 53 | log.warn("nested update es ool object ,nextNestedESObject should not null!"); 54 | baseValidateResult 55 | .setStatus(new Status(ESErrorCode.REQUEST_PARAM_ERROR_CODE, 56 | "嵌套更新顶级非集合请求参数【nextNestedESObject】为空")); 57 | } 58 | } 59 | 60 | } 61 | return baseValidateResult; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/config/IndexHelper.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.config; 2 | 3 | import com.google.gson.JsonObject; 4 | import com.elastic.search.elasticsearch.search.index.DataType; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * @author niuzhiwei 10 | */ 11 | public class IndexHelper { 12 | 13 | private Map properties; 14 | 15 | public IndexHelper(Map properties) { 16 | this.properties = properties; 17 | } 18 | 19 | public boolean isTextField(String name) { 20 | if (properties.containsKey(name)) { 21 | return isTextField(properties.get(name)); 22 | } 23 | return false; 24 | } 25 | 26 | public boolean isKeywordField(String name) { 27 | if (properties.containsKey(name)) { 28 | return isKeywordField(properties.get(name)); 29 | } 30 | return false; 31 | } 32 | 33 | public boolean isSupportTextAndKeywordField(String name) { 34 | if (properties.containsKey(name)) { 35 | return isSupportTextAndKeyword(properties.get(name)); 36 | } 37 | return false; 38 | } 39 | 40 | private boolean isTextField(JsonObject jsonObject) { 41 | return matchType(jsonObject, DataType.TEXT); 42 | } 43 | 44 | private boolean isKeywordField(JsonObject jsonObject) { 45 | return matchType(jsonObject, DataType.KEYWORD); 46 | } 47 | 48 | private boolean isSupportTextAndKeyword(JsonObject jsonObject) { 49 | if (matchType(jsonObject, DataType.TEXT)) { 50 | if (jsonObject.has("fields")) { 51 | jsonObject = jsonObject.get("fields").getAsJsonObject(); 52 | if (jsonObject.has("keyword")) { 53 | { // {"type":"text","fields":{"keyword":{"type":"keyword","ignore_above":256}}} 54 | jsonObject = jsonObject.get("keyword").getAsJsonObject(); 55 | if ("keyword".equals(jsonObject.get("type").getAsString())) { 56 | return true; 57 | } 58 | } 59 | // } else if (jsonObject.has("raw")) { 60 | // {// {"type": "text","fields": {"raw": {"type": "keyword"}}} 61 | // jsonObject = jsonObject.get("raw").getAsJsonObject(); 62 | // if (jsonObject.get("type").getAsString().equals("keyword")) { 63 | // return true; 64 | // } 65 | // } 66 | } 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | private boolean matchType(JsonObject jsonObject, DataType type) { 73 | if (jsonObject.has("type")) { 74 | if (type.name().equalsIgnoreCase(jsonObject.get("type").getAsString())) { 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/condition/CollapseConditionBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.condition; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.CollapseQueryObject; 5 | import com.elastic.search.elasticsearch.dataobject.conditions.InnerHitsCondition; 6 | import com.elastic.search.elasticsearch.dataobject.conditions.OrderCondition; 7 | import org.elasticsearch.action.search.SearchRequestBuilder; 8 | import org.elasticsearch.common.Strings; 9 | import org.elasticsearch.index.query.InnerHitBuilder; 10 | import org.elasticsearch.search.collapse.CollapseBuilder; 11 | import org.elasticsearch.search.fetch.subphase.FetchSourceContext; 12 | import org.elasticsearch.search.sort.FieldSortBuilder; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | /** 19 | *

20 | * 瓦解查询条件构建器 21 | * 22 | * @author niuzhiwei 23 | */ 24 | public class CollapseConditionBuilder { 25 | 26 | @Resource 27 | private SearchSourceBuilder searchSourceBuilder; 28 | 29 | public CollapseBuilder build(final SearchRequestBuilder searchRequestBuilder, CollapseQueryObject esObject) { 30 | 31 | CollapseBuilder collapseBuilder = new CollapseBuilder(esObject.getFieldName()); 32 | 33 | final List innerHitsConditions = esObject.getInnerHitsConditions(); 34 | List innerHits = new ArrayList<>(innerHitsConditions.size()); 35 | for (InnerHitsCondition innerHitsCondition : innerHitsConditions) { 36 | InnerHitBuilder innerHitBuilder = new InnerHitBuilder(); 37 | innerHitBuilder.setName(innerHitsCondition.getHitName()); 38 | innerHitBuilder.setSize(innerHitsCondition.getHitSize()); 39 | final List orderConditions = innerHitsCondition.getOrderConditions(); 40 | if (orderConditions != null && orderConditions.size() > 0) { 41 | for (OrderCondition orderCondition : orderConditions) { 42 | final FieldSortBuilder sort = searchSourceBuilder.getSort(orderCondition); 43 | innerHitBuilder.addSort(sort); 44 | } 45 | } 46 | FetchSourceContext fetchSourceContext; 47 | final List fieldNames = innerHitsCondition.getFieldNames(); 48 | if (fieldNames == null || fieldNames.size() == 0) { 49 | fetchSourceContext = new FetchSourceContext(Boolean.TRUE, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY); 50 | } else { 51 | fetchSourceContext = new FetchSourceContext(Boolean.TRUE, fieldNames.toArray(new String[0]), 52 | Strings.EMPTY_ARRAY); 53 | } 54 | innerHitBuilder.setFetchSourceContext(fetchSourceContext); 55 | innerHits.add(innerHitBuilder); 56 | } 57 | collapseBuilder.setInnerHits(innerHits); 58 | return collapseBuilder; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/searchservice/ESSearchService.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.searchservice; 2 | 3 | 4 | import com.elastic.search.common.domain.SearchBaseResult; 5 | import com.elastic.search.elasticsearch.dataobject.*; 6 | 7 | 8 | /** 9 | *

10 | * 搜索引擎,feign 客户端调用API 11 | * 12 | * @author niuzhiwei 13 | */ 14 | public interface ESSearchService { 15 | 16 | /** 17 | * 新增操作 18 | * 19 | * @param obj 存储请求参数 20 | * @return true操作成功,false重复操作 21 | */ 22 | SearchBaseResult esSave(SaveESObject obj); 23 | 24 | /** 25 | * 查询操作 26 | * 27 | * @param obj 查询参数 28 | * @return 检索到的文档集 29 | */ 30 | SearchBaseResult esQuery(final QueryESObject obj); 31 | 32 | /** 33 | * 删除操作(根据 {@link SaveESObject#ukMap} 删除文档) 34 | * 35 | * @param obj 删除请求参数 36 | * @return true操作成功,false操作失败 37 | */ 38 | SearchBaseResult esDelete(final DeleteESObject obj); 39 | 40 | /** 41 | * 更新操作(根据 {@link SaveESObject#ukMap} 更新文档) 42 | *

43 | * 1:该操作会根据{@link UpdateESObject#dataMap} 的key-value键值对更新es文档 ,当前key不存在进行新增操作,当key存在进行更新操作。 44 | * 2:escommon 提供{@link ESSearchConvertor#object2MapExcludeNullValue(Object)}方法, 45 | * 可将map中value==null值过滤掉,注意基本类型默认值问题 46 | * 47 | * @param obj 参数,具体参见参数属性说明 48 | * @return true操作成功,false操作失败 49 | */ 50 | SearchBaseResult esUpdate(final UpdateESObject obj); 51 | 52 | 53 | /** 54 | * 批量新增操作 55 | * 56 | * @param obj 批量新增请求参数,参照{@link #esSave(SaveESObject)} 57 | * @return true全部操作成功,false部分操作失败 58 | */ 59 | SearchBaseResult esBatchSave(final BatchSaveESObject obj); 60 | 61 | /** 62 | * 批量更新操作(根据 {@link SaveESObject#ukMap} 更新文档) 63 | * 64 | * @param obj 批量更新请求参数,参照{@link #esUpdate(UpdateESObject)} 65 | * @return true全部操作成功,false部分操作失败 66 | */ 67 | SearchBaseResult esBatchUpdate(final BatchUpdateESObject obj); 68 | 69 | /** 70 | * 批量删除操作(根据 {@link DeleteESObject#ukMap} 删除文档) 71 | * 72 | * @param obj 批量删除请求参数,参照{@link #esDelete(DeleteESObject)} 73 | * @return true全部操作成功,false部分操作失败 74 | */ 75 | SearchBaseResult esBatchDelete(final BatchDeleteESObject obj); 76 | 77 | /** 78 | * 按条件进行更新(此 {@link SaveESObject#ukMap}条件废弃) 79 | * 80 | * @param obj 更新请求参数 81 | * @return true操作成功,false操作失败 82 | */ 83 | SearchBaseResult conditionUpdate(final ConditionUpdateESObject obj); 84 | 85 | /** 86 | * 按条件删除操作(此 {@link SaveESObject#ukMap}条件废弃) 87 | * 88 | * @param obj 删除请求参数 89 | * @return true操作成功,false操作失败 90 | */ 91 | SearchBaseResult conditionDelete(final ConditionDeleteESObject obj); 92 | } 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/serialize/api/xml/XStreamAlias.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.serialize.api.xml; 2 | 3 | 4 | import com.thoughtworks.xstream.XStream; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.lang.reflect.Field; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | /** 15 | * @author niuzhiwei 16 | */ 17 | public class XStreamAlias { 18 | 19 | private final Set> CACHE = new HashSet<>(); 20 | private static final Logger LOGGER = LoggerFactory.getLogger(XStreamAlias.class); 21 | 22 | public static XStreamAlias create() { 23 | return new XStreamAlias(); 24 | } 25 | 26 | private boolean initMap(XStream xStream, Map map) { 27 | for (Map.Entry entry : map.entrySet()) { 28 | initAlias(xStream, entry.getKey()); 29 | initAlias(xStream, entry.getValue()); 30 | } 31 | return false; 32 | } 33 | 34 | private boolean initList(XStream xStream, List list) { 35 | if (list.size() > 0) { 36 | return initAlias(xStream, list.get(0)); 37 | } 38 | return false; 39 | } 40 | 41 | public boolean initAlias(XStream xStream, Object obj) { 42 | if (obj == null) { 43 | return false; 44 | } 45 | if (Map.class.isAssignableFrom(obj.getClass())) { 46 | return initMap(xStream, (Map) obj); 47 | } else if (List.class.isAssignableFrom(obj.getClass())) { 48 | return initList(xStream, (List) obj); 49 | } else { 50 | if (obj.getClass().getPackage().getName().startsWith("com.hivescm")) { 51 | if (CACHE.contains(obj.getClass())) { 52 | return true; 53 | } 54 | xStream.alias(obj.getClass().getSimpleName(), obj.getClass()); 55 | if (LOGGER.isDebugEnabled()) { 56 | LOGGER.debug("alias:{}->{}", obj.getClass().getSimpleName(), obj.getClass()); 57 | } 58 | boolean res = true; 59 | Field[] fields = obj.getClass().getDeclaredFields(); 60 | for (int i = 0; i < fields.length; i++) { 61 | try { 62 | if (!fields[i].isAccessible()) { 63 | fields[i].setAccessible(true); 64 | } 65 | if (fields[i].getType().isPrimitive()) { 66 | continue; 67 | } 68 | Object object = fields[i].get(obj); 69 | if (!initAlias(xStream, object)) { 70 | res = false; 71 | } 72 | } catch (IllegalArgumentException | IllegalAccessException e) { 73 | throw new IllegalArgumentException("error", e); 74 | } 75 | } 76 | if (res) { 77 | CACHE.add(obj.getClass()); 78 | } 79 | return res; 80 | } 81 | } 82 | return true; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/condition/QueryConditionBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.condition; 2 | 3 | 4 | import com.elastic.search.elasticsearch.config.IndexAdmin; 5 | import com.elastic.search.elasticsearch.config.IndexHelper; 6 | import com.elastic.search.elasticsearch.dataobject.QueryESObject; 7 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 8 | import org.elasticsearch.action.search.SearchRequestBuilder; 9 | import org.elasticsearch.index.query.BoolQueryBuilder; 10 | import org.elasticsearch.index.query.QueryBuilder; 11 | import org.elasticsearch.index.query.QueryBuilders; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.util.CollectionUtils; 14 | 15 | import javax.annotation.Resource; 16 | import java.util.List; 17 | 18 | /** 19 | * @author niuzhiwei 20 | */ 21 | public class QueryConditionBuilder { 22 | 23 | @Resource(name = "searchConditionBuilder") 24 | private SearchConditionBuilder searchConditionBuilder; 25 | 26 | @Resource(name = "relationConditionBuilder") 27 | private RelationConditionBuilder relationConditionBuilder; 28 | 29 | @Autowired 30 | private IndexAdmin indexAdmin; 31 | 32 | public void build(final SearchRequestBuilder searchRequestBuilder, final QueryESObject esObject) { 33 | 34 | BoolQueryBuilder rootQuery = QueryBuilders.boolQuery(); 35 | 36 | QueryESObject termQuery = esObject; 37 | do { 38 | final BoolQueryBuilder currentQuery = innerBuilder(termQuery.getSearchConditions(), 1, esObject.getIndexName(), 39 | esObject.getTypeName()); 40 | 41 | relationConditionBuilder.builder(esObject.groupCondition(), currentQuery, rootQuery); 42 | 43 | termQuery = termQuery.getNextGroupQuery(); 44 | } while (termQuery != null); 45 | 46 | searchRequestBuilder.setQuery(rootQuery); 47 | } 48 | 49 | /** 50 | * 根据查询条件构建 QueryBuilder 51 | * 52 | * @param currentConditions 检索条件 53 | * @param version 查询版本 54 | * @return 查询条件 55 | */ 56 | public BoolQueryBuilder innerBuilder(final List currentConditions, Integer version, String indexName, 57 | String typeName) { 58 | final BoolQueryBuilder rootQuery = QueryBuilders.boolQuery(); 59 | IndexHelper helper = indexAdmin.getIndexHelper(indexName, typeName); 60 | if (CollectionUtils.isEmpty(currentConditions)) { 61 | return rootQuery; 62 | } 63 | 64 | if (version == 1) { 65 | for (SearchCondition currentCondition : currentConditions) { 66 | QueryBuilder currentQuery = searchConditionBuilder.builder(currentCondition, helper); 67 | // 同一条件集合内均为 68 | relationConditionBuilder.builder(Boolean.FALSE, currentQuery, rootQuery); 69 | // and 70 | // 链接 71 | } 72 | } 73 | 74 | if (version == 2) { 75 | for (SearchCondition currentCondition : currentConditions) { 76 | QueryBuilder query = searchConditionBuilder.builderVersion2(currentCondition, QueryBuilders.boolQuery(), helper); 77 | // 同一条件集合内均为 78 | relationConditionBuilder.builder(Boolean.TRUE, query, rootQuery); 79 | // and 80 | // 链接 81 | } 82 | } 83 | return rootQuery; 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/evo/ESSearchRequestBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.evo; 2 | 3 | import org.elasticsearch.action.search.SearchRequestBuilder; 4 | import org.elasticsearch.action.search.SearchResponse; 5 | import org.elasticsearch.index.query.QueryBuilder; 6 | import org.elasticsearch.index.query.QueryBuilders; 7 | 8 | public class ESSearchRequestBuilder { 9 | 10 | private SearchRequestBuilder searchRequestBuilder; 11 | private ESBoolQueryBuilder rootESQueryBuilder; 12 | 13 | public ESSearchRequestBuilder(SearchRequestBuilder searchRequestBuilder) { 14 | this.searchRequestBuilder = searchRequestBuilder; 15 | } 16 | 17 | public ESSearchRequestBuilder match(String name, Object value) { 18 | QueryBuilder builder = QueryBuilders.matchQuery(name, value); 19 | getRootESQueryBuilder().must(builder); 20 | return this; 21 | } 22 | 23 | public ESSearchRequestBuilder lt(String name, Object value) { 24 | QueryBuilder builder = QueryBuilders.rangeQuery(name).lt(value); 25 | getRootESQueryBuilder().must(builder); 26 | return this; 27 | } 28 | 29 | public ESSearchRequestBuilder and(ESQueryBuilder... builders) { 30 | ESBoolQueryBuilder rootESQueryBuilder = getRootESQueryBuilder(); 31 | for (ESQueryBuilder builder : builders) { 32 | rootESQueryBuilder.must(builder.getQueryBuilder()); 33 | } 34 | System.out.println(rootESQueryBuilder.getBoolQueryBuilder()); 35 | return this; 36 | } 37 | 38 | public ESSearchRequestBuilder or(ESQueryBuilder... builders) { 39 | ESBoolQueryBuilder rootESQueryBuilder = getRootESQueryBuilder(); 40 | for (ESQueryBuilder builder : builders) { 41 | rootESQueryBuilder.should(builder.getQueryBuilder()); 42 | } 43 | System.out.println(rootESQueryBuilder.getBoolQueryBuilder()); 44 | return this; 45 | } 46 | 47 | public ESSearchRequestBuilder not(ESQueryBuilder... builders) { 48 | ESBoolQueryBuilder rootESQueryBuilder = getRootESQueryBuilder(); 49 | for (ESQueryBuilder builder : builders) { 50 | rootESQueryBuilder.mustNot(builder.getQueryBuilder()); 51 | } 52 | System.out.println(rootESQueryBuilder.getBoolQueryBuilder()); 53 | return this; 54 | } 55 | 56 | // public ESSearchBuilder and(String name, ESQueryType type, Object text) { 57 | // QueryBuilder builder = type.getQueryBuilder(name, text); 58 | // getBoolQueryBuilder().must(builder); 59 | // return this; 60 | // } 61 | // 62 | // public ESSearchBuilder or(String name, ESQueryType type, Object text) { 63 | // QueryBuilder builder = type.getQueryBuilder(name, text); 64 | // System.out.println("\n\n\n"+getBoolQueryBuilder().should(builder)); 65 | // return this; 66 | // } 67 | 68 | public SearchResponse get() { 69 | return searchRequestBuilder.get(); 70 | } 71 | 72 | private ESBoolQueryBuilder getRootESQueryBuilder() { 73 | if (rootESQueryBuilder == null) { 74 | rootESQueryBuilder = new ESBoolQueryBuilder(QueryBuilders.boolQuery()); 75 | searchRequestBuilder.setQuery(rootESQueryBuilder.getBoolQueryBuilder()); 76 | } 77 | return rootESQueryBuilder; 78 | } 79 | 80 | // private ESSearchRequestBuilder must(QueryBuilder builder) { 81 | // getRootESQueryBuilder().must(builder); 82 | // return this; 83 | // } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/exception/StatusDefinition.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.exception; 2 | 3 | 4 | import com.elastic.search.common.domain.SearchBaseResult; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | /** 8 | * @author niuzhiwei 9 | */ 10 | public interface StatusDefinition { 11 | 12 | /** 13 | * 获取编码 14 | * 15 | * @return 16 | */ 17 | int getErrorCode(); 18 | 19 | /** 20 | * 获取描述 21 | * 22 | * @return 23 | */ 24 | String getErrorReason(); 25 | 26 | /** 27 | * 抛出异常 28 | * 29 | * @return 30 | */ 31 | default SystemException throwError() { 32 | throw new SystemException(this.getErrorCode(), this.getErrorReason()); 33 | } 34 | 35 | /** 36 | * 抛出异常 37 | * 38 | * @param throwable 39 | * @return 40 | */ 41 | default SystemException throwError(Throwable throwable) { 42 | throw new SystemException(this.getErrorCode(), this.getErrorReason()).setCause(throwable); 43 | } 44 | 45 | /** 46 | * 使用传入消息体作为返回给调用者的errorReason 47 | * 48 | * @param msg 49 | * @return 50 | */ 51 | default SystemException throwError(String msg) { 52 | throw new SystemException(this.getErrorCode(), msg); 53 | } 54 | 55 | /** 56 | * 使用传入消息体作为返回给调用者的errorReason 57 | * 58 | * @param msg 59 | * @return 60 | */ 61 | default SystemException throwError(String msg, Throwable throwable) { 62 | throw new SystemException(this.getErrorCode(), msg).setCause(throwable); 63 | } 64 | 65 | /** 66 | * 将传入的详细描述追加到默认errorReason后面 67 | *

68 | * 例如:参数错误(`x`必须为数字类型) 69 | * 70 | * @param detail 71 | * @return 72 | */ 73 | default SystemException throwErrorAndAppendDetail(String detail) { 74 | throw new SystemException(this.getErrorCode(), this.getErrorReason() + "(" + detail + ")"); 75 | } 76 | 77 | /** 78 | * 将传入的详细描述追加到默认errorReason后面 79 | *

80 | * 例如:参数错误(`x`必须为数字类型) 81 | * 82 | * @param detail 83 | * @return 84 | */ 85 | default SystemException throwErrorAndAppendDetail(String detail, Throwable throwable) { 86 | throw new SystemException(this.getErrorCode(), this.getErrorReason() + "(" + detail + ")").setCause(throwable); 87 | } 88 | 89 | /** 90 | * 使用状态定义创建DataResult 91 | * 92 | * @return 93 | */ 94 | default SearchBaseResult newDataResult() { 95 | return SearchBaseResult.faild(getErrorCode(), getErrorReason()); 96 | } 97 | 98 | /** 99 | * 使用状态定义创建DataResult 100 | * 101 | * @param msg 作为Status.statusReason使用 102 | * @return 103 | */ 104 | default SearchBaseResult newDataResult(String msg) { 105 | return SearchBaseResult.faild(getErrorCode(), msg); 106 | } 107 | 108 | /** 109 | * 追加错误明细并转化到DataResult 110 | * 111 | * @param errorDetail 错误明细 112 | * @return 113 | */ 114 | default SearchBaseResult asDataResult(String errorDetail) { 115 | return SearchBaseResult.faild(getErrorCode(), getErrorReason(errorDetail)); 116 | } 117 | 118 | default String getErrorReason(String errorDetails) { 119 | if (StringUtils.isNotBlank(errorDetails)) { 120 | return getErrorReason() + "(" + errorDetails + ")"; 121 | } else { 122 | return getErrorReason(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/config/IndexUtils.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.config; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; 5 | import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; 6 | import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; 7 | import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; 8 | import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; 9 | import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; 10 | import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse; 11 | import org.elasticsearch.client.Client; 12 | import org.elasticsearch.cluster.metadata.IndexMetaData; 13 | import org.elasticsearch.cluster.metadata.MappingMetaData; 14 | import org.elasticsearch.common.collect.ImmutableOpenMap; 15 | 16 | import java.util.Map; 17 | import java.util.concurrent.ExecutionException; 18 | 19 | /** 20 | * @author niuzhiwei 21 | */ 22 | @Slf4j 23 | public class IndexUtils { 24 | 25 | 26 | /** 27 | * 获取索引元数据信息 28 | * 29 | * @param index 30 | * @param type 31 | * @return 32 | */ 33 | public static MappingMetaData loadIndexMeta(Client client, String index, String type) { 34 | ClusterStateResponse response = client.admin().cluster().prepareState().execute().actionGet(); 35 | ImmutableOpenMap immutableOpenMap = response.getState().getMetaData().getIndices(); 36 | if (immutableOpenMap != null) { 37 | IndexMetaData metaData = immutableOpenMap.get(index); 38 | if (metaData != null) { 39 | ImmutableOpenMap mappings = metaData.getMappings(); 40 | if (mappings != null) { 41 | return mappings.get(type); 42 | } 43 | } 44 | } 45 | log.error("获取ES数据结构失败 index:" + index + "|type:" + type); 46 | return null; 47 | } 48 | 49 | public static boolean isExistsIndex(Client client, String index) throws InterruptedException, ExecutionException { 50 | IndicesExistsResponse response = client.admin().indices().exists(new IndicesExistsRequest(index)).get(); 51 | return response.isExists(); 52 | } 53 | 54 | public static boolean deleteIndex(Client client, String index) throws InterruptedException, ExecutionException { 55 | if (isExistsIndex(client, index)) { 56 | DeleteIndexResponse deleteResponse = client.admin().indices().delete(new DeleteIndexRequest(index)).get(); 57 | return deleteResponse.isAcknowledged(); 58 | } else { 59 | return false; 60 | } 61 | } 62 | 63 | public static boolean createIndex(Client client, String index) throws InterruptedException, ExecutionException { 64 | CreateIndexResponse response = client.admin().indices().create(new CreateIndexRequest(index)).get(); 65 | return response.isAcknowledged(); 66 | } 67 | 68 | /** 69 | * 创建索引 70 | * 71 | * @param client 72 | * @param index 73 | * @param type 74 | * @param data 75 | * @return 76 | */ 77 | public static boolean createIndex(Client client, String index, String type, Map data) { 78 | CreateIndexResponse createIndexResponse = client.admin().indices().prepareCreate(index).addMapping(type, data) 79 | .get(); 80 | return createIndexResponse.isAcknowledged(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/convert/ESSearchConvertor.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.convert; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | 5 | import java.io.IOException; 6 | import java.util.Iterator; 7 | import java.util.Map; 8 | 9 | /** 10 | * es通用对象转换工具 11 | * 12 | * @author niuzhiwei 13 | */ 14 | public final class ESSearchConvertor { 15 | 16 | /** 17 | * 以此判断当前实例对象是否为java的基本类型数据 18 | */ 19 | private static final String BASIC_DATA_TYPE = "java."; 20 | 21 | private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); 22 | 23 | /** 24 | * 将实例对象转换为Map 25 | * 26 | * @throws RuntimeException illegal json data 27 | */ 28 | @SuppressWarnings(value = {"unchecked"}) 29 | public static Map object2Map(Object obj) throws IOException { 30 | return illegal(obj) ? null : OBJECT_MAPPER.readValue(OBJECT_MAPPER.writeValueAsString(obj), Map.class); 31 | } 32 | 33 | /** 34 | * 将实例对象转换为Map,并排除空值 35 | * 36 | * @throws RuntimeException illegal json data 37 | */ 38 | @SuppressWarnings(value = {"unchecked"}) 39 | public static Map object2MapExcludeNullValue(Object obj) throws IOException { 40 | if (obj == null) { 41 | return null; 42 | } 43 | final Map map = OBJECT_MAPPER.readValue(OBJECT_MAPPER.writeValueAsString(obj), Map.class); 44 | removeNuLLValue(map); 45 | return map; 46 | } 47 | 48 | /** 49 | * 移除 map 中value为null的 entry 对 50 | * 51 | * @param map 52 | */ 53 | private static void removeNuLLValue(Map map) { 54 | if (map == null) { 55 | return; 56 | } 57 | for (final Iterator> iterator = map.entrySet().iterator(); iterator.hasNext(); ) { 58 | final Map.Entry next = iterator.next(); 59 | final Object value = next.getValue(); 60 | if (value == null) { 61 | iterator.remove(); 62 | } 63 | if (value instanceof Map) { 64 | removeNuLLValue((Map) value); 65 | } 66 | } 67 | } 68 | 69 | /** 70 | * 将Map转换为实例对象 71 | * 72 | * @throws IOException illegal data 73 | */ 74 | public static T map2Object(Map map, Class t) throws IOException { 75 | return map == null ? null : OBJECT_MAPPER.readValue(OBJECT_MAPPER.writeValueAsString(map), t); 76 | } 77 | 78 | /** 79 | * 将实例对象序列化为Json串 80 | * 81 | * @throws IOException illegal data 82 | */ 83 | public static String object2Json(Object obj) throws IOException { 84 | return obj == null ? null : OBJECT_MAPPER.writeValueAsString(obj); 85 | } 86 | 87 | /** 88 | * 将json串转反序列化实例对象 89 | * 90 | * @throws IOException illegal data 91 | */ 92 | public static T json2Object(String jsonStr, Class t) throws IOException { 93 | if (jsonStr == null || "".equalsIgnoreCase(jsonStr)) { 94 | return null; 95 | } 96 | return OBJECT_MAPPER.readValue(jsonStr, t); 97 | } 98 | 99 | /** 100 | * 验证请求参数是否合法 101 | * 102 | * @param obj 实例对象 103 | * @return trueobj 为空或为基本类型,false合法数据; 104 | */ 105 | private static boolean illegal(Object obj) { 106 | return null == obj || basicDataType(obj); 107 | } 108 | 109 | /** 110 | * 验证请求参数是否为基本类型 111 | * 112 | * @param obj 实例对象 113 | * @return trueobj 为基本类型,false非基本类型; 114 | */ 115 | private static boolean basicDataType(Object obj) { 116 | return obj.getClass().getName().startsWith(BASIC_DATA_TYPE); 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/handler/CollapseResponseHandler.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.handler; 2 | 3 | 4 | import com.elastic.search.elasticsearch.convert.ESSearchConvertor; 5 | import com.elastic.search.elasticsearch.dataobject.CollapseQueryObject; 6 | import com.elastic.search.elasticsearch.dataobject.ESDocument; 7 | import com.elastic.search.elasticsearch.dataobject.ESResponse; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.elasticsearch.action.search.SearchResponse; 10 | import org.elasticsearch.search.SearchHit; 11 | import org.elasticsearch.search.SearchHits; 12 | 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * @author niuzhiwei 21 | */ 22 | public class CollapseResponseHandler { 23 | 24 | public Map handler(final SearchResponse searchResponse, final CollapseQueryObject esObject) { 25 | final Map responseMap = new HashMap<>(); 26 | 27 | final SearchHits searchHits = searchResponse.getHits(); 28 | if (searchHits == null) { 29 | return responseMap; 30 | } 31 | 32 | final SearchHit[] outHits = searchHits.getHits(); 33 | if (outHits == null || outHits.length == 0) { 34 | return responseMap; 35 | } 36 | 37 | final List hitNames = esObject.getHitNames(); 38 | if (hitNames == null || hitNames.size() == 0) { 39 | return responseMap; 40 | } 41 | 42 | for (final SearchHit outHit : outHits) { 43 | final Map innerHits = outHit.getInnerHits(); 44 | for (final String hitName : hitNames) { 45 | final SearchHits innerSearchHits = innerHits.get(hitName); 46 | if (innerSearchHits == null) { 47 | continue; 48 | } 49 | 50 | final SearchHit[] hitResult = innerSearchHits.getHits(); 51 | if (hitResult == null || hitResult.length == 0) { 52 | continue; 53 | } 54 | 55 | for (final SearchHit searchHitFields : hitResult) { 56 | Map dataMap = null; 57 | try { 58 | dataMap = ESSearchConvertor.json2Object(searchHitFields.getSourceAsString(), Map.class); 59 | } catch (IOException e) { 60 | e.printStackTrace(); 61 | } 62 | 63 | if (dataMap != null && !dataMap.isEmpty()) { 64 | ESDocument esDocument = new ESDocument(); 65 | esDocument.setDataMap(dataMap); 66 | ESResponse esResponse = responseMap.get(hitName); 67 | if (esResponse == null) { 68 | esResponse = new ESResponse(); 69 | esResponse.setSystemName(esObject.getSystemName()); 70 | esResponse.setIndexName(esObject.getIndexName()); 71 | final String typeName = esObject.getTypeName(); 72 | if (StringUtils.isNotBlank(typeName)) { 73 | esResponse.setTypeName(typeName); 74 | } 75 | responseMap.put(hitName, esResponse); 76 | } 77 | List esDocuments = esResponse.getEsDocuments(); 78 | if (esDocuments == null) { 79 | esResponse.setEsDocuments(new ArrayList<>()); 80 | } 81 | esResponse.getEsDocuments().add(esDocument); 82 | } 83 | } 84 | } 85 | } 86 | return responseMap; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/conf/BaseTypeIndexConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.conf; 2 | 3 | 4 | import com.elastic.search.elasticsearch.infrastructure.constants.TypeIndexConstants; 5 | 6 | import java.util.Objects; 7 | 8 | /** 9 | * 索引配置类 10 | * 11 | * @author niuzhiwei 12 | */ 13 | public abstract class BaseTypeIndexConfiguration { 14 | 15 | private String systemName = TypeIndexConstants.SYSTEM_NAME; 16 | private String indexName; 17 | private String typeName; 18 | 19 | 20 | protected BaseTypeIndexConfiguration() { 21 | } 22 | 23 | protected BaseTypeIndexConfiguration(String indexName, String typeName) { 24 | this.indexName = indexName; 25 | this.typeName = typeName; 26 | } 27 | 28 | public String getSystemName() { 29 | return this.systemName; 30 | } 31 | 32 | public String getIndexName() { 33 | return this.indexName; 34 | } 35 | 36 | public String getTypeName() { 37 | return this.typeName; 38 | } 39 | 40 | public void setSystemName(String systemName) { 41 | this.systemName = systemName; 42 | } 43 | 44 | public void setIndexName(String indexName) { 45 | this.indexName = indexName; 46 | } 47 | 48 | public void setTypeName(String typeName) { 49 | this.typeName = typeName; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (o == this) { 55 | return true; 56 | } else if (!(o instanceof BaseTypeIndexConfiguration)) { 57 | return false; 58 | } else { 59 | BaseTypeIndexConfiguration other = (BaseTypeIndexConfiguration) o; 60 | if (!other.canEqual(this)) { 61 | return false; 62 | } else { 63 | label47: 64 | { 65 | Object thisSystemname = this.getSystemName(); 66 | Object otherSystemname = other.getSystemName(); 67 | if (thisSystemname == null) { 68 | if (otherSystemname == null) { 69 | break label47; 70 | } 71 | } else if (thisSystemname.equals(otherSystemname)) { 72 | break label47; 73 | } 74 | 75 | return false; 76 | } 77 | 78 | Object thisIndexname = this.getIndexName(); 79 | Object otherIndexname = other.getIndexName(); 80 | if (thisIndexname == null) { 81 | if (otherIndexname != null) { 82 | return false; 83 | } 84 | } else if (!thisIndexname.equals(otherIndexname)) { 85 | return false; 86 | } 87 | 88 | Object this$typeName = this.getTypeName(); 89 | Object other$typeName = other.getTypeName(); 90 | if (this$typeName == null) { 91 | if (other$typeName != null) { 92 | return false; 93 | } 94 | } else if (!this$typeName.equals(other$typeName)) { 95 | return false; 96 | } 97 | 98 | return true; 99 | } 100 | } 101 | } 102 | 103 | protected boolean canEqual(Object other) { 104 | return other instanceof BaseTypeIndexConfiguration; 105 | } 106 | 107 | @Override 108 | public int hashCode() { 109 | return Objects.hash(systemName, indexName, typeName); 110 | } 111 | 112 | @Override 113 | public String toString() { 114 | return "TypeIndexConfiguration(systemName=" + this.getSystemName() + ", indexName=" + this.getIndexName() + ", typeName=" + this.getTypeName() + ")"; 115 | } 116 | } 117 | 118 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/utils/Ognl.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.utils; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | import java.lang.reflect.Array; 6 | import java.util.Collection; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author niuzhiwei 11 | */ 12 | public class Ognl { 13 | 14 | public static boolean isNotNumber(Object o) throws IllegalArgumentException { 15 | if (o == null) { 16 | return false; 17 | } 18 | if (o instanceof Number) { 19 | if (o instanceof Double) { 20 | if (((Number) o).doubleValue() == 0.0) { 21 | return true; 22 | } 23 | } 24 | if (((Number) o).intValue() == 0) { 25 | return false; 26 | } 27 | } 28 | return true; 29 | } 30 | 31 | /** 32 | * test for Map,Collection,String,Array isEmpty 33 | * 34 | * @param o 35 | * @return 36 | */ 37 | @SuppressWarnings("rawtypes") 38 | public static boolean isEmpty(Object o, int flag) throws IllegalArgumentException { 39 | if (o == null) { 40 | return true; 41 | } 42 | if (o instanceof Number) { 43 | if (o instanceof Double) { 44 | if (((Number) o).doubleValue() == 0.0) { 45 | return true; 46 | } 47 | } 48 | //0也可以插入到数据表 49 | if (((Number) o).intValue() == 0 && flag == 0) { 50 | return false; 51 | } 52 | // 查询的时候用 53 | if (((Number) o).intValue() == 0 && flag == 1) { 54 | return true; 55 | } 56 | 57 | } 58 | if (o instanceof String) { 59 | if (((String) o).length() == 0) { 60 | return true; 61 | } 62 | } else if (o instanceof Collection) { 63 | if (((Collection) o).isEmpty()) { 64 | return true; 65 | } 66 | } else if (o.getClass().isArray()) { 67 | if (Array.getLength(o) == 0) { 68 | return true; 69 | } 70 | } else if (o instanceof Map) { 71 | if (((Map) o).isEmpty()) { 72 | return true; 73 | } 74 | } else { 75 | return false; 76 | } 77 | 78 | return false; 79 | } 80 | 81 | /** 82 | * test for Map,Collection,String,Array isNotEmpty 83 | * 84 | * @param o 85 | * @return 86 | */ 87 | public static boolean isNotEmpty(Object o) { 88 | return !isEmpty(o, 0); 89 | } 90 | 91 | public static boolean isNumber(Object o) { 92 | if (o == null) { 93 | return false; 94 | } 95 | if (o instanceof Number) { 96 | return true; 97 | } 98 | if (o instanceof String) { 99 | String str = (String) o; 100 | if (str.length() == 0) { 101 | return false; 102 | } 103 | if (str.trim().length() == 0) { 104 | return false; 105 | } 106 | return StringUtils.isNumeric(str); 107 | } 108 | return false; 109 | } 110 | 111 | public static boolean isBlank(Object o) { 112 | if (o == null) { 113 | return true; 114 | } 115 | if (o instanceof String) { 116 | String str = (String) o; 117 | return isBlank(str); 118 | } 119 | return false; 120 | } 121 | 122 | public static boolean isBlank(String str) { 123 | if (str == null || str.length() == 0) { 124 | return true; 125 | } 126 | 127 | for (int i = 0; i < str.length(); i++) { 128 | if (!Character.isWhitespace(str.charAt(i))) { 129 | return false; 130 | } 131 | } 132 | return true; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/common/domain/SystemManager.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.common.domain; 2 | 3 | 4 | import org.apache.commons.lang3.StringUtils; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.core.env.Environment; 8 | 9 | /** 10 | * @author niuzhiwei 11 | */ 12 | public class SystemManager { 13 | 14 | private static final Logger LOGGER = LoggerFactory.getLogger(SystemManager.class); 15 | 16 | public static volatile boolean isInit = false; 17 | /** 18 | * 使用前需要先初始化 19 | */ 20 | private static volatile Environment environment = null; 21 | 22 | /** 23 | * 初始化系统环境 24 | * 25 | * @param environment 26 | */ 27 | public static void initEnvironment(Environment environment) { 28 | if (SystemManager.environment == null) { 29 | if (environment == null) { 30 | throw new IllegalArgumentException("初始化环境参数不能为空"); 31 | } 32 | System.out.println("init.environment:" + environment); 33 | SystemManager.environment = environment; 34 | } 35 | } 36 | 37 | /** 38 | * 获取系统环境 39 | * 40 | * @return 41 | */ 42 | public static Environment getEnvironment() { 43 | return environment; 44 | } 45 | 46 | 47 | /** 48 | * 获取系统码 49 | * 50 | * @return 51 | */ 52 | public static int getSystemCode() { 53 | if (environment == null) { 54 | LOGGER.warn("[警告]请先调用初始化:SystemManager.initEnvironment()"); 55 | return 0; 56 | } 57 | String code = environment.getProperty(GlobalConstant.SYSTEM_CODE); 58 | if (code == null) { 59 | LOGGER.warn("[警告]没有设置系统码 application.properties ->'system.code'"); 60 | return 0; 61 | } 62 | return Integer.parseInt(code.trim()); 63 | } 64 | 65 | /** 66 | * 获取当前环境 dev|test|product 67 | * 68 | * @return 69 | */ 70 | public static String getEnv() { 71 | String env = null; 72 | if (environment != null) { 73 | String[] activeProfiles = environment.getActiveProfiles(); 74 | if (activeProfiles != null && activeProfiles.length > 0) { 75 | env = activeProfiles[0]; 76 | } else { 77 | env = environment.getProperty("spring.profiles.active"); 78 | } 79 | } 80 | if (StringUtils.isBlank(env)) { 81 | LOGGER.error("没有获取到有效的环境->spring.profiles.active=[local,dev,test,prepare,product]"); 82 | } 83 | return env; 84 | } 85 | 86 | 87 | /** 88 | * 将当前状态码追加系统码 89 | * 90 | * @param code 91 | * @return 92 | */ 93 | public static int appendSysCode(int code) { 94 | if (code < 0) { 95 | return -(getSystemCode() + Math.abs(code)); 96 | } 97 | return Integer.parseInt(getSystemCode() + "" + code); 98 | } 99 | 100 | /** 101 | * 获取当前系统secret 102 | * 103 | * @return 104 | */ 105 | public static String getOpenSecret() { 106 | String open_secret = environment.getProperty(GlobalConstant.OPEN_SECRET_CONFIG_KEY); 107 | if (open_secret == null) { 108 | LOGGER.info("没有获取到配置`{}`", GlobalConstant.OPEN_SECRET_CONFIG_KEY); 109 | } 110 | return open_secret; 111 | } 112 | 113 | public static Logger getLogger() { 114 | return LOGGER; 115 | } 116 | 117 | 118 | /** 119 | * 获取端口号 120 | * 121 | * @return 122 | */ 123 | public static Integer getPort() { 124 | Integer port = null; 125 | try { 126 | if (environment != null) { 127 | String val = environment.getProperty("server.port"); 128 | if (val != null) { 129 | port = Integer.parseInt(val.trim()); 130 | } 131 | } 132 | } catch (Exception e) { 133 | e.printStackTrace(); 134 | } 135 | if (port == null) { 136 | System.err.println("获取应用端口失败检查配置:`server.port`"); 137 | } 138 | return port; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/config/IndexAdmin.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.config; 2 | 3 | 4 | import com.elastic.search.elasticsearch.search.index.IndexParser; 5 | import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; 6 | import org.elasticsearch.client.Client; 7 | import org.elasticsearch.cluster.metadata.IndexMetaData; 8 | import org.elasticsearch.cluster.metadata.MappingMetaData; 9 | import org.elasticsearch.common.collect.ImmutableOpenMap; 10 | import org.elasticsearch.common.compress.CompressedXContent; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | import javax.annotation.PostConstruct; 16 | import java.util.Map; 17 | import java.util.Timer; 18 | import java.util.TimerTask; 19 | import java.util.concurrent.ConcurrentHashMap; 20 | 21 | /** 22 | * @author niuzhiwei 23 | */ 24 | public class IndexAdmin { 25 | 26 | @Autowired 27 | private Client client; 28 | private static final Map CACHE = new ConcurrentHashMap<>(); 29 | private static final Logger LOGGER = LoggerFactory.getLogger(IndexAdmin.class); 30 | 31 | @PostConstruct 32 | private void init() { 33 | new Timer().schedule(new TimerTask() { 34 | @Override 35 | public void run() { 36 | try {// 异步定时更新索引结构 37 | for (Map.Entry entry : CACHE.entrySet()) { 38 | String[] keyVal = entry.getKey().split(":"); 39 | String index = keyVal[0]; 40 | String type = keyVal[1]; 41 | String mapping = loadIndexStruct(index, type); 42 | register(index, type, mapping); 43 | } 44 | } catch (Exception e) { 45 | LOGGER.error("refresh.index.ERROR:" + e.getMessage()); 46 | } 47 | } 48 | }, 10000, 5000); 49 | } 50 | 51 | public IndexHelper getIndexHelper(String index, String type) { 52 | String key = generatedKey(index, type); 53 | if (!CACHE.containsKey(key)) { 54 | String mapping = loadIndexStruct(index, type); 55 | register(index, type, mapping); 56 | } 57 | return CACHE.get(key); 58 | } 59 | 60 | /** 61 | * 装载索引数据结构 62 | * 63 | * @param index 64 | * @param type 65 | * @return 66 | */ 67 | private String loadIndexStruct(String index, String type) { 68 | ClusterStateResponse response = client.admin().cluster().prepareState().execute().actionGet(); 69 | ImmutableOpenMap immutableOpenMap = response.getState().getMetaData().getIndices(); 70 | if (immutableOpenMap != null) { 71 | IndexMetaData metaData = immutableOpenMap.get(index); 72 | if (metaData != null) { 73 | ImmutableOpenMap mappings = metaData.getMappings(); 74 | if (mappings != null) { 75 | MappingMetaData mappingMetaData = mappings.get(type); 76 | if (mappingMetaData != null) { 77 | CompressedXContent content = mappingMetaData.source(); 78 | if (content != null) { 79 | return content.toString(); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | LOGGER.error("获取ES数据结构失败 index:" + index + "|type:" + type); 86 | return null; 87 | } 88 | 89 | private String generatedKey(String index, String type) { 90 | return index + ":" + type; 91 | } 92 | 93 | 94 | private void register(String index, String type, String mapping) { 95 | if (mapping != null) { 96 | String key = generatedKey(index, type); 97 | IndexParser parser = IndexParser.parseFromIndexType(mapping, type); 98 | IndexHelper helper = new IndexHelper(parser.getProperties()); 99 | CACHE.put(key, helper); 100 | LOGGER.info("register or update index:" + index + "|type:" + type); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.5.RELEASE 9 | 10 | 11 | com.elastic.search 12 | search-spring-boot-starter 13 | search-spring-boot-starter 14 | jar 15 | 1.0.0 16 | 17 | 18 | 19 | com.thoughtworks.xstream 20 | xstream 21 | 1.4.18 22 | 23 | 24 | com.google.code.gson 25 | gson 26 | 27 | 28 | javax.servlet 29 | javax.servlet-api 30 | 31 | 32 | org.apache.commons 33 | commons-lang3 34 | 35 | 36 | org.elasticsearch 37 | elasticsearch 38 | 6.8.17 39 | 40 | 41 | com.esotericsoftware 42 | kryo 43 | 4.0.1 44 | 45 | 46 | com.google.code.gson 47 | gson 48 | 49 | 50 | com.google.guava 51 | guava 52 | 29.0-jre 53 | 54 | 55 | com.fasterxml.jackson.core 56 | jackson-annotations 57 | 58 | 59 | com.fasterxml.jackson.core 60 | jackson-databind 61 | 62 | 63 | org.elasticsearch.client 64 | transport 65 | 6.4.2 66 | 67 | 68 | elasticsearch 69 | org.elasticsearch 70 | 71 | 72 | 73 | 74 | org.projectlombok 75 | lombok 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-configuration-processor 80 | true 81 | 82 | 83 | org.springframework.boot 84 | spring-boot-autoconfigure 85 | 86 | 87 | 88 | org.slf4j 89 | slf4j-api 90 | 91 | 92 | 93 | 94 | 95 | 96 | search-spring-boot-starter 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-compiler-plugin 101 | 102 | 1.8 103 | 1.8 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/dataobject/CollapseQueryObject.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.dataobject; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.conditions.InnerHitsCondition; 5 | import com.elastic.search.elasticsearch.dataobject.conditions.OrderCondition; 6 | import com.elastic.search.elasticsearch.dataobject.conditions.PageCondition; 7 | import com.elastic.search.elasticsearch.dataobject.conditions.SearchCondition; 8 | 9 | import java.io.Serializable; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | *

15 | * 瓦解查询,有点意思,来源es 16 | *

17 | * 依据单一字段值进行分组,对每组文档进行筛选若干条组成结果集返回 18 | * 19 | * @author niuzhiwei 20 | */ 21 | public class CollapseQueryObject extends BaseESObject implements Serializable { 22 | 23 | 24 | private static final long serialVersionUID = -5546475758546391769L; 25 | /** 26 | * 版本兼容标志(检索条件变更) 27 | * 历史版本: 28 | * 1 (2017年9月01日之前) 29 | * 2 (2017年11月14日之后) 30 | */ 31 | private Integer version = 1; 32 | 33 | /** 34 | * 数据去重 域 名 35 | *

36 | * 该字段映射类型为 keyword | numeric 37 | */ 38 | private String fieldName; 39 | 40 | /** 41 | * 过滤条件,内部均使用 AND 链接 42 | * 多条件使用 多层嵌套不便,使用 链表实现 {@link SearchCondition#nextAndCondition} 43 | */ 44 | private List searchConditions; 45 | 46 | /** 47 | * 分页条件,作用与组,对于最终返回文档数目取决于,每组返回的数目 48 | */ 49 | private PageCondition pageCondition; 50 | 51 | /** 52 | * 外部排序条件 53 | */ 54 | private List orderConditions; 55 | 56 | /** 57 | * 组内控制条件,内部击中条件控制,目前用于去重使用 58 | *

59 | * 默认值为取每组的第一个文档 60 | */ 61 | private List innerHitsConditions; 62 | 63 | public CollapseQueryObject() { 64 | } 65 | 66 | public CollapseQueryObject(String systemName, String indexName, String typeName) { 67 | super(systemName, indexName, typeName); 68 | } 69 | 70 | /** 71 | * 获取 内部查询所有名字 72 | * 73 | * @return hitNames 74 | */ 75 | public List getHitNames() { 76 | List hitNames = new ArrayList<>(); 77 | 78 | if (innerHitsConditions == null || innerHitsConditions.size() == 0) { 79 | return hitNames; 80 | } 81 | 82 | for (InnerHitsCondition innerHitsCondition : innerHitsConditions) { 83 | hitNames.add(innerHitsCondition.getHitName()); 84 | } 85 | return hitNames; 86 | } 87 | 88 | public Integer getVersion() { 89 | return version; 90 | } 91 | 92 | public void setVersion(Integer version) { 93 | this.version = version; 94 | } 95 | 96 | public boolean pageSearch() { 97 | return pageCondition != null; 98 | } 99 | 100 | public String getFieldName() { 101 | return fieldName; 102 | } 103 | 104 | public void setFieldName(String fieldName) { 105 | this.fieldName = fieldName; 106 | } 107 | 108 | public List getSearchConditions() { 109 | return searchConditions; 110 | } 111 | 112 | public void setSearchConditions(List searchConditions) { 113 | this.searchConditions = searchConditions; 114 | } 115 | 116 | public PageCondition getPageCondition() { 117 | return pageCondition; 118 | } 119 | 120 | public void setPageCondition(PageCondition pageCondition) { 121 | this.pageCondition = pageCondition; 122 | } 123 | 124 | public List getOrderConditions() { 125 | return orderConditions; 126 | } 127 | 128 | public void setOrderConditions(List orderConditions) { 129 | this.orderConditions = orderConditions; 130 | } 131 | 132 | public List getInnerHitsConditions() { 133 | return innerHitsConditions; 134 | } 135 | 136 | public void setInnerHitsConditions(List innerHitsConditions) { 137 | this.innerHitsConditions = innerHitsConditions; 138 | } 139 | 140 | /** 141 | * 格式未进行约束,调用方请勿尝试解析该字符串 142 | */ 143 | @Override 144 | public String toString() { 145 | final StringBuilder sb = new StringBuilder("CollapseQueryObject{"); 146 | sb.append("version=").append(version); 147 | sb.append(", fieldName='").append(fieldName).append('\''); 148 | sb.append(", searchConditions=").append(searchConditions); 149 | sb.append(", pageCondition=").append(pageCondition); 150 | sb.append(", orderConditions=").append(orderConditions); 151 | sb.append(", innerHitsConditions=").append(innerHitsConditions); 152 | sb.append('}'); 153 | return sb.toString(); 154 | } 155 | } 156 | 157 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/condition/SearchSourceBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.condition; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.QueryESObject; 5 | import com.elastic.search.elasticsearch.dataobject.conditions.OrderCondition; 6 | import com.elastic.search.elasticsearch.dataobject.conditions.PageCondition; 7 | import com.elastic.search.elasticsearch.dataobject.enums.SortEnum; 8 | import org.elasticsearch.action.search.SearchRequestBuilder; 9 | import org.elasticsearch.search.sort.FieldSortBuilder; 10 | import org.elasticsearch.search.sort.SortBuilders; 11 | import org.elasticsearch.search.sort.SortOrder; 12 | import org.springframework.beans.factory.annotation.Value; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | *

18 | * es 5.5.2 对资源的过滤进行了整合,统一构建资源过滤查询 19 | * 20 | * @author niuzhiwei 21 | */ 22 | public class SearchSourceBuilder { 23 | 24 | @Value(value = "${escenter.page.max.size:100}") 25 | private int pageMaxSize; 26 | 27 | public void build(final SearchRequestBuilder searchRequestBuilder, final QueryESObject esObject) { 28 | 29 | final org.elasticsearch.search.builder.SearchSourceBuilder searchSourceBuilder = org.elasticsearch.search.builder.SearchSourceBuilder.searchSource(); 30 | // 构建分页资源查询 31 | page(esObject.getPageCondition(), searchSourceBuilder); 32 | // 构建 域 过滤器 33 | field(esObject.getNeedFields(), searchSourceBuilder); 34 | // 构建 排序条件 35 | sort(esObject.getOrderConditions(), searchSourceBuilder); 36 | 37 | searchRequestBuilder.setSource(searchSourceBuilder); 38 | } 39 | 40 | /** 41 | * 页 查询 42 | * 43 | * @param pageCondition 44 | * @return 45 | */ 46 | public void page(PageCondition pageCondition, final org.elasticsearch.search.builder.SearchSourceBuilder searchSourceBuilder) { 47 | final PageCondition page = getPage(pageCondition); 48 | if (page != null) { 49 | searchSourceBuilder.from(page.getPageSize() * (page.getCurrentPage() - 1)); 50 | searchSourceBuilder.size(page.getPageSize()); 51 | } 52 | } 53 | 54 | public PageCondition getPage(PageCondition pageCondition) { 55 | if (null == pageCondition) { 56 | pageCondition = new PageCondition(); 57 | pageCondition.setPageSize(1000); 58 | pageCondition.setCurrentPage(1); 59 | return pageCondition; 60 | } 61 | 62 | Integer currentPage = pageCondition.getCurrentPage(); 63 | currentPage = currentPage == null ? 1 : currentPage < 1 ? 1 : currentPage; 64 | 65 | Integer pageSize = pageCondition.getPageSize(); 66 | pageSize = pageSize == null ? 1 : pageSize > pageMaxSize ? pageMaxSize : pageSize < 1 ? 1 : pageSize; 67 | 68 | pageCondition.setCurrentPage(currentPage); 69 | pageCondition.setPageSize(pageSize); 70 | 71 | return pageCondition; 72 | } 73 | 74 | /** 75 | * 域 过滤 76 | * 77 | * @param needFields 需要过滤的域 78 | * @param searchSourceBuilder 查询请求构建器 79 | */ 80 | public void field(final List needFields, org.elasticsearch.search.builder.SearchSourceBuilder searchSourceBuilder) { 81 | if (needFields == null || needFields.size() == 0) { 82 | searchSourceBuilder.fetchSource(Boolean.TRUE); 83 | return; 84 | } 85 | 86 | searchSourceBuilder.fetchSource(needFields.toArray(new String[0]), null); 87 | } 88 | 89 | /** 90 | * 排序条件 91 | * 92 | * @param orderConditions 排序条件 93 | * @param searchSourceBuilder 查询请求构建器 94 | */ 95 | public void sort(final List orderConditions, org.elasticsearch.search.builder.SearchSourceBuilder searchSourceBuilder) { 96 | if (null == orderConditions || orderConditions.isEmpty()) { 97 | return; 98 | } 99 | for (OrderCondition orderCondition : orderConditions) { 100 | searchSourceBuilder.sort(getSort(orderCondition)); 101 | } 102 | } 103 | 104 | public FieldSortBuilder getSort(OrderCondition orderCondition) { 105 | final String fieldName = orderCondition.getFieldName(); 106 | final SortEnum sort = orderCondition.getOrderCondition(); 107 | 108 | FieldSortBuilder order; 109 | switch (sort) { 110 | case ASC: 111 | order = SortBuilders.fieldSort(fieldName).order(SortOrder.ASC); 112 | break; 113 | case DESC: 114 | order = SortBuilders.fieldSort(fieldName).order(SortOrder.DESC); 115 | break; 116 | default: 117 | order = null; 118 | } 119 | return order; 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/infrastructure/executor/impl/BaseSearchSaveExecutor.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.infrastructure.executor.impl; 2 | 3 | 4 | import com.elastic.search.common.boot.SearchBeanContext; 5 | import com.elastic.search.common.domain.SearchBaseResult; 6 | import com.elastic.search.common.exception.SystemException; 7 | import com.elastic.search.common.utils.ListUtils; 8 | import com.elastic.search.elasticsearch.convert.ESSearchConvertor; 9 | import com.elastic.search.elasticsearch.infrastructure.common.SearchAdapter; 10 | import com.elastic.search.elasticsearch.infrastructure.conf.BaseTypeIndexConfiguration; 11 | import com.elastic.search.elasticsearch.infrastructure.consts.FrameworkExceptionConstants; 12 | import com.elastic.search.elasticsearch.dataobject.BatchSaveESObject; 13 | import com.elastic.search.elasticsearch.dataobject.SaveESObject; 14 | import com.elastic.search.elasticsearch.infrastructure.executor.SearchExecutor; 15 | import com.elastic.search.elasticsearch.searchservice.ESSearchService; 16 | import lombok.extern.slf4j.Slf4j; 17 | 18 | import java.lang.reflect.Field; 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | /** 24 | * @param 25 | * @author niuzhiwei 26 | */ 27 | @Slf4j 28 | public abstract class BaseSearchSaveExecutor extends SearchAdapter implements SearchExecutor { 29 | 30 | /** 31 | * 插入一条数据,支持嵌套插入 32 | * 33 | * @param t 34 | * @return 35 | * @throws SystemException 36 | */ 37 | public synchronized Boolean execute(T t) throws SystemException { 38 | try { 39 | BaseTypeIndexConfiguration config = this.getConfig(); 40 | SaveESObject obj = this.setConfig(config, new SaveESObject()); 41 | Field f = t.getClass().getDeclaredField(primaryKeyName); 42 | f.setAccessible(true); 43 | obj.setId(f.get(t)); 44 | Map data = ESSearchConvertor.object2Map(t); 45 | List nodes = this.getCascade(t); 46 | if (ListUtils.isNotBlank(nodes)) { 47 | nodes.forEach(node -> { 48 | data.put(String.format("_%s", node.getNodeName()), node.getNodeValue()); 49 | }); 50 | } 51 | obj.setDataMap(data); 52 | SearchBaseResult result = SearchBeanContext.getBean(ESSearchService.class).esSave(obj); 53 | if (result.isSuccess()) { 54 | return result.getResult(); 55 | } else { 56 | throw new SystemException(FrameworkExceptionConstants.ERROR_SEARCH_ENGINES, result.toJSON()); 57 | } 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | throw new SystemException(FrameworkExceptionConstants.ERROR_SEARCH_ENGINES, "搜索引擎异常(插入一条数据): t={" + t + "}, error={" + e.getLocalizedMessage() + "}"); 61 | } 62 | } 63 | 64 | /** 65 | * 批量插入 66 | * 67 | * @param list 68 | * @return 69 | * @throws SystemException 70 | */ 71 | public synchronized boolean execute(List list) throws SystemException { 72 | try { 73 | BatchSaveESObject bso = new BatchSaveESObject(); 74 | List so = new ArrayList(); 75 | Field f = null; 76 | for (T t : list) { 77 | SaveESObject obj = this.setConfig(this.getConfig(), SaveESObject.class.newInstance()); 78 | f = t.getClass().getDeclaredField(primaryKeyName); 79 | f.setAccessible(true); 80 | obj.setId(f.get(t)); 81 | Map data = ESSearchConvertor.object2Map(t); 82 | List nodes = this.getCascade(t); 83 | if (ListUtils.isNotBlank(nodes)) { 84 | nodes.forEach(node -> { 85 | data.put(String.format("_%s", node.getNodeName()), node.getNodeValue()); 86 | }); 87 | } 88 | obj.setDataMap(data); 89 | so.add(obj); 90 | } 91 | bso.setSaveDatas(so); 92 | SearchBaseResult result = esSearchService.esBatchSave(bso); 93 | if (result.isSuccess()) { 94 | return result.getResult(); 95 | } else { 96 | throw new SystemException(FrameworkExceptionConstants.ERROR_SEARCH_ENGINES, result.toJSON()); 97 | } 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | throw new SystemException(FrameworkExceptionConstants.ERROR_SEARCH_ENGINES, "搜索引擎异常(批量插入): list={" + list + "}, error={" + e.getLocalizedMessage() + "}"); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/condition/GroupConditionBuilder.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.condition; 2 | 3 | 4 | import com.elastic.search.elasticsearch.dataobject.QueryESObject; 5 | import com.elastic.search.elasticsearch.dataobject.conditions.FunctionCondition; 6 | import com.elastic.search.elasticsearch.dataobject.conditions.GroupByCondition; 7 | import com.elastic.search.elasticsearch.dataobject.enums.SqlFunctionEnum; 8 | import org.elasticsearch.action.search.SearchRequestBuilder; 9 | import org.elasticsearch.search.aggregations.AbstractAggregationBuilder; 10 | import org.elasticsearch.search.aggregations.AggregationBuilder; 11 | import org.elasticsearch.search.aggregations.AggregationBuilders; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | *

17 | * 分组条件 构建器 18 | * 19 | * @author niuzhiwei 20 | */ 21 | public class GroupConditionBuilder { 22 | 23 | public SearchRequestBuilder build(final SearchRequestBuilder searchRequestBuilder, final QueryESObject esObject) { 24 | 25 | final GroupByCondition groupByCondition = esObject.getGroupByCondition(); 26 | if (groupByCondition == null) { 27 | return searchRequestBuilder; 28 | } 29 | final List groupFields = groupByCondition.getGroupFields(); 30 | if (groupFields == null) { 31 | return searchRequestBuilder; 32 | } 33 | // 根聚合嵌套使用 34 | AggregationBuilder rootTermsBuilder = null; 35 | // 最底层嵌套聚合 36 | AggregationBuilder termTermsBuilder = null; 37 | for (int i = 0; i < groupFields.size(); i++) { 38 | if (rootTermsBuilder == null) { 39 | rootTermsBuilder = AggregationBuilders.terms(groupFields.get(i)) 40 | .field(groupFields.get(i)); 41 | } else { 42 | if (null == termTermsBuilder || termTermsBuilder == rootTermsBuilder) { 43 | termTermsBuilder = AggregationBuilders.terms(groupFields.get(i)).field(groupFields.get(i)); 44 | rootTermsBuilder.subAggregation(termTermsBuilder); 45 | } else { 46 | final AggregationBuilder currentTermsBuilder = AggregationBuilders.terms(groupFields.get(i)) 47 | .field(groupFields.get(i)) 48 | .minDocCount(0); 49 | termTermsBuilder.subAggregation(currentTermsBuilder); 50 | termTermsBuilder = currentTermsBuilder; 51 | } 52 | } 53 | } 54 | 55 | aggregationFunction(rootTermsBuilder, termTermsBuilder, groupByCondition.getFunctionConditions(), 56 | searchRequestBuilder); 57 | 58 | return searchRequestBuilder; 59 | } 60 | 61 | /** 62 | * 封装查询请求的聚合条件 63 | * 64 | * @param rootTermsBuilder 聚合根 65 | * @param termsBuilder 当前聚合 66 | * @param functions 聚合函数集 67 | * @param searchRequestBuilder 聚合功能查询请求 68 | */ 69 | private void aggregationFunction(AggregationBuilder rootTermsBuilder, AggregationBuilder termsBuilder, 70 | final List functions, 71 | final SearchRequestBuilder searchRequestBuilder) { 72 | 73 | for (FunctionCondition functionCondition : functions) { 74 | 75 | AbstractAggregationBuilder aggregation = getAggregationFunction(functionCondition); 76 | 77 | if (termsBuilder != null) { 78 | termsBuilder.subAggregation(aggregation); 79 | } else { 80 | searchRequestBuilder.addAggregation(aggregation); 81 | } 82 | } 83 | if (termsBuilder != null) { 84 | searchRequestBuilder.addAggregation(rootTermsBuilder); 85 | } 86 | } 87 | 88 | public AbstractAggregationBuilder getAggregationFunction(FunctionCondition functionCondition) { 89 | final String field = functionCondition.getField(); 90 | final SqlFunctionEnum sqlFunction = functionCondition.getFunction(); 91 | final String functionName = functionCondition.getFunctionName(); 92 | AbstractAggregationBuilder aggregation; 93 | switch (sqlFunction) { 94 | case AVG: 95 | aggregation = AggregationBuilders.avg(functionName).field(field); 96 | break; 97 | case MAX: 98 | aggregation = AggregationBuilders.max(functionName).field(field); 99 | break; 100 | case MIN: 101 | aggregation = AggregationBuilders.min(functionName).field(field); 102 | break; 103 | case SUM: 104 | aggregation = AggregationBuilders.sum(functionName).field(field); 105 | break; 106 | case COUNT: 107 | aggregation = AggregationBuilders.count(functionName).field(field); 108 | break; 109 | default: 110 | throw new RuntimeException("不支持的聚合类型"); 111 | } 112 | return aggregation; 113 | } 114 | } -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/config/CanalBean.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.config; 2 | 3 | import java.io.Serializable; 4 | import java.util.Map; 5 | 6 | /** 7 | * Canal接到binlog的封装类 8 | * 9 | * @author niuzhiwei 10 | */ 11 | public class CanalBean implements Serializable { 12 | 13 | //数据库 14 | private String database; 15 | //表 16 | private String table; 17 | //操作时间 18 | private Long executeTime; 19 | //操作类型 20 | //INSERT = 1;UPDATE = 2;DELETE = 3;CREATE = 4;ALTER = 5;ERASE = 6;QUERY = 7; 21 | //TRUNCATE = 8;RENAME = 9;CINDEX = 10;DINDEX = 11; 22 | private int eventType; 23 | //ddl的sql 24 | private String ddlSql; 25 | //行数据 26 | private RowData rowData; 27 | 28 | public static class RowData { 29 | //操作前字段信息 30 | private Map beforeColumns; 31 | //操作后字段信息 32 | private Map afterColumns; 33 | 34 | public RowData() { 35 | } 36 | 37 | public RowData(Map beforeColumns, Map afterColumns) { 38 | this.beforeColumns = beforeColumns; 39 | this.afterColumns = afterColumns; 40 | } 41 | 42 | public Map getBeforeColumns() { 43 | return beforeColumns; 44 | } 45 | 46 | public void setBeforeColumns(Map beforeColumns) { 47 | this.beforeColumns = beforeColumns; 48 | } 49 | 50 | public Map getAfterColumns() { 51 | return afterColumns; 52 | } 53 | 54 | public void setAfterColumns(Map afterColumns) { 55 | this.afterColumns = afterColumns; 56 | } 57 | 58 | public static class ColumnEntry { 59 | //字段名称 60 | private String name; 61 | //是否是主键 62 | private Boolean isKey; 63 | //是否修改 64 | private Boolean updated; 65 | //是否为空 66 | private Boolean isNull; 67 | //字段的值 68 | private String value; 69 | 70 | public ColumnEntry() { 71 | } 72 | 73 | public ColumnEntry(String name, Boolean isKey, Boolean updated, Boolean isNull, String value) { 74 | this.name = name; 75 | this.isKey = isKey; 76 | this.updated = updated; 77 | this.isNull = isNull; 78 | this.value = value; 79 | } 80 | 81 | public String getName() { 82 | return name; 83 | } 84 | 85 | public void setName(String name) { 86 | this.name = name; 87 | } 88 | 89 | public Boolean getIsKey() { 90 | return isKey; 91 | } 92 | 93 | public void setIsKey(Boolean isKey) { 94 | this.isKey = isKey; 95 | } 96 | 97 | public Boolean getUpdated() { 98 | return updated; 99 | } 100 | 101 | public void setUpdated(Boolean updated) { 102 | this.updated = updated; 103 | } 104 | 105 | public Boolean getIsNull() { 106 | return isNull; 107 | } 108 | 109 | public void setIsNull(Boolean isNull) { 110 | this.isNull = isNull; 111 | } 112 | 113 | public String getValue() { 114 | return value; 115 | } 116 | 117 | public void setValue(String value) { 118 | this.value = value; 119 | } 120 | } 121 | } 122 | 123 | public CanalBean() { 124 | } 125 | 126 | public CanalBean(String database, String table, Long executeTime, int eventType, String ddlSql) { 127 | this.database = database; 128 | this.table = table; 129 | this.executeTime = executeTime; 130 | this.eventType = eventType; 131 | this.ddlSql = ddlSql; 132 | } 133 | 134 | public String getDatabase() { 135 | return database; 136 | } 137 | 138 | public void setDatabase(String database) { 139 | this.database = database; 140 | } 141 | 142 | public String getTable() { 143 | return table; 144 | } 145 | 146 | public void setTable(String table) { 147 | this.table = table; 148 | } 149 | 150 | public Long getExecuteTime() { 151 | return executeTime; 152 | } 153 | 154 | public void setExecuteTime(Long executeTime) { 155 | this.executeTime = executeTime; 156 | } 157 | 158 | public int getEventType() { 159 | return eventType; 160 | } 161 | 162 | public void setEventType(int eventType) { 163 | this.eventType = eventType; 164 | } 165 | 166 | public String getDdlSql() { 167 | return ddlSql; 168 | } 169 | 170 | public void setDdlSql(String ddlSql) { 171 | this.ddlSql = ddlSql; 172 | } 173 | 174 | public RowData getRowData() { 175 | return rowData; 176 | } 177 | 178 | public void setRowData(RowData rowData) { 179 | this.rowData = rowData; 180 | } 181 | 182 | 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/com/elastic/search/elasticsearch/search/utils/ModifyIndexFactory.java: -------------------------------------------------------------------------------- 1 | package com.elastic.search.elasticsearch.search.utils; 2 | 3 | 4 | import com.elastic.search.elasticsearch.search.index.ScanDocuments; 5 | import com.elastic.search.elasticsearch.config.IndexUtils; 6 | import com.elastic.search.elasticsearch.search.api.SearchService; 7 | import org.elasticsearch.action.index.IndexRequestBuilder; 8 | import org.elasticsearch.client.Client; 9 | import org.elasticsearch.cluster.metadata.MappingMetaData; 10 | import org.elasticsearch.search.SearchHit; 11 | import org.elasticsearch.search.sort.SortOrder; 12 | 13 | import javax.annotation.Resource; 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.concurrent.ExecutionException; 19 | 20 | /** 21 | * @author niuzhiwei 22 | */ 23 | public class ModifyIndexFactory { 24 | 25 | @Resource 26 | private SearchService searchService; 27 | 28 | @Resource 29 | private Client client; 30 | 31 | /** 32 | * 重建索引处理 33 | *

40 | * 41 | * @param index 索引名称 42 | * @param type 类型 43 | * @param updateProperties 更新属性处理 44 | * @param sortName 排序字段 45 | * @param order 排序方式 46 | * @return 47 | * @throws IOException 48 | * @throws ExecutionException 49 | * @throws InterruptedException 50 | */ 51 | public boolean reindex(String index, String type, UpdateProperties updateProperties, String sortName, SortOrder order) 52 | throws IOException, InterruptedException, ExecutionException { 53 | String tmp_index = index + "_tmp"; 54 | MappingMetaData metaData = IndexUtils.loadIndexMeta(client, index, type); 55 | Map data = updateProperties.execute(metaData.getSourceAsMap()); 56 | if (!IndexUtils.createIndex(client, tmp_index, type, data)) { 57 | throw new IllegalArgumentException("创建临时索引失败"); 58 | } 59 | //将数据拷贝到临时索引 60 | copy_data(index, tmp_index, type, sortName, order); 61 | //删除主索引 62 | IndexUtils.deleteIndex(client, index); 63 | //重建主索引 64 | if (!IndexUtils.createIndex(client, index, type, data)) { 65 | throw new IllegalArgumentException("重建主索引失败"); 66 | } 67 | // 从临时索引中拷贝到主索引中 68 | copy_data(tmp_index, index, type, sortName, order); 69 | // 删除临时索引 70 | IndexUtils.deleteIndex(client, tmp_index); 71 | return true; 72 | } 73 | 74 | /** 75 | * 同一个ES服务中拷贝数据 76 | * 77 | * @param srcIndex 原索引 78 | * @param dectIndex 目标索引 79 | * @param type 索引类型 80 | * @param sortName 81 | */ 82 | private void copy_data(String srcIndex, String dectIndex, String type, String sortName, SortOrder order) { 83 | int batch = 100; 84 | ScanDocuments scanDocuments = new ScanDocuments(srcIndex, type, batch); 85 | scanDocuments.start(client, sortName, order); 86 | int count = 0; 87 | List batchList = new ArrayList<>(batch); 88 | while (scanDocuments.hasNext()) { 89 | SearchHit hit = scanDocuments.next(); 90 | IndexRequestBuilder indexRequestBuilder = client.prepareIndex(dectIndex, type).setId(hit.getId()) 91 | .setSource(hit.getSourceAsMap()); 92 | batchList.add(indexRequestBuilder); 93 | if (batchList.size() == batch) { 94 | boolean success = searchService.batchSave(batchList); 95 | System.out.println("批量提交" + batch + "->endIndex:" + count + " 状态:" + success); 96 | } 97 | count++; 98 | } 99 | if (batchList.size() > 0) { 100 | boolean success = searchService.batchSave(batchList); 101 | System.out.println("批量提交" + batch + "->endIndex:" + count + " 状态:" + success); 102 | } 103 | System.out.println("迁移数据:" + count); 104 | } 105 | 106 | public static interface UpdateProperties { 107 | /** 108 | * 修改索引数据结构(属性结构为索引中的原始格式) 109 | * 110 | *
111 |          * public default Map process(Map properties) {
112 |          * 	Map weight = (Map) properties.get("weight");
113 |          * 	weight.put("type", "integer");
114 |          * 	weight.remove("field");
115 |          * 	return properties;
116 |          * }
117 |          * 
118 | * 119 | * @param properties 120 | */ 121 | public Map adjustField(Map properties); 122 | 123 | @SuppressWarnings("unchecked") 124 | default Map execute(Map data) { 125 | Map properties = (Map) data.get("properties"); 126 | properties = this.adjustField(properties); 127 | data.put("properties", properties); 128 | return data; 129 | } 130 | } 131 | } --------------------------------------------------------------------------------