【Spring Boot】Spring Boot之使用 Java High Level REST Client 整合elasticsearch
一、相关介绍
1)版本信息:
Java High Level REST Client 的版本为:7.4.2
elasticsearch: 7.4.2
注意:Java High Level REST Client的版本必须小于等于你的elasticsearch版本,建议版本一致
2)整合思路
1.通过注解在实体类上定义对应的index和mapping信息
2.通过spring事件监听器实现项目启动后,自动建立index和mapping
3.通过抽取base dao类,实现通用的es增删改查逻辑
4.提供部分常用的查询demo
3)GitHub地址
https://github.com/zhangboqing/spring-boot-demo-elasticsearch-rest-high-level-client
二、整合步骤
1)maven坐标
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.4.2</version> <exclusions> <exclusion> <artifactId>elasticsearch</artifactId> <groupId>org.elasticsearch</groupId> </exclusion> <exclusion> <artifactId>elasticsearch-rest-client</artifactId> <groupId>org.elasticsearch.client</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.4.2</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>7.4.2</version> <scope>compile</scope> </dependency>
2)自定义注解
1.@ESDocument
import java.lang.annotation.*; /** * @author zhangboqing * @date 2019/12/12 */ @Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) public @interface ESDocument { /** * Name of the Elasticsearch index. * <ul> * <li>Lowercase only</li> * <li><Cannot include \, /, *, ?, ", <, >, |, ` ` (space character), ,, #/li> * <li>Cannot start with -, _, +</li> * <li>Cannot be . or ..</li> * <li>Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit * faster)</li> * </ul> */ String indexName(); /** * Number of shards for the index {@link #indexName()}. Used for index creation. */ int shards() default 0; /** * Number of replicas for the index {@link #indexName()}. Used for index creation. */ int replicas() default 0; }
2.@ESField
/** * @author zhangboqing * @date 2019/12/12 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Documented @Inherited public @interface ESField { @AliasFor("name") String value() default ""; @AliasFor("value") String name() default ""; ESFieldType type(); String analyzer() default ""; }
3.@ESId
/** * @author zhangboqing * @date 2019/12/12 */ @Retention(RetentionPolicy.RUNTIME) @Target(value = { FIELD, METHOD, ANNOTATION_TYPE }) public @interface ESId { }
3)定义的base类
1.BaseElasticsearchDao
/** * @author zhangboqing * @date 2019/12/10 */ @Slf4j public abstract class BaseElasticsearchDao<T> { @Autowired protected ElasticsearchUtils elasticsearchUtils; @Autowired protected RestHighLevelClient client; /** * 索引名称 */ protected String indexName; /** * ID字段 */ protected Field idField; /** * T对应的类型Class */ protected Class<T> genericClass; public BaseElasticsearchDao() { Class<T> beanClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(this.getClass(), BaseElasticsearchDao.class); this.genericClass = beanClass; ESDocument esDocument = AnnotationUtils.findAnnotation(beanClass, ESDocument.class); this.indexName = esDocument.indexName(); Field[] declaredFields = beanClass.getDeclaredFields(); for (Field declaredField : declaredFields) { ESId esId = declaredField.getAnnotation(ESId.class); if (esId != null) { this.idField = declaredField; idField.setAccessible(true); break; } } } /** * 保存或更新文档数据 * * @param list 文档数据集合 */ public void saveOrUpdate(List<T> list) { list.forEach(genericInstance -> { IndexRequest request = ElasticsearchUtils.buildIndexRequest(indexName, getIdValue(genericInstance), genericInstance); try { client.index(request, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); log.error("elasticsearch insert error", e); } }); } /** * 删除操作 * 当genericInstance在es中不存在时,调用该方法也不会报错 * * @param genericInstance 被删除的实例对象 */ public void delete(T genericInstance) { if (ObjectUtils.isEmpty(genericInstance)) { // 如果对象为空,则删除全量 searchList().forEach(result -> { elasticsearchUtils.deleteRequest(indexName, getIdValue(genericInstance)); }); } elasticsearchUtils.deleteRequest(indexName, getIdValue(genericInstance)); } /** * 搜索文档,根据指定的搜索条件 * * @param searchSourceBuilder * @return */ public List<T> search(SearchSourceBuilder searchSourceBuilder) { ESSort esSort = new ESSort(SortOrder.ASC,"goodsName"); ESPageResult search = search(searchSourceBuilder, null, null); return search != null ? search.getResults() : null; } /** * 分页排序搜索文档,根据指定的搜索条件 * * @param searchSourceBuilder * @param esPageRequest 分页 * @param esSort 排序 * @return */ public ESPageResult<T> search(SearchSourceBuilder searchSourceBuilder, ESPageRequest esPageRequest, ESSort esSort) { // 搜索 Assert.notNull(searchSourceBuilder, "searchSourceBuilder is null"); SearchRequest searchRequest = new SearchRequest(indexName); searchRequest.source(searchSourceBuilder); // 分页 if (esPageRequest != null) { searchSourceBuilder.from(esPageRequest.getPageNo()); searchSourceBuilder.size(esPageRequest.getSize()); } // 排序 if (esSort != null) { List<ESSort.ESOrder> orders = esSort.orders; if (!CollectionUtils.isEmpty(orders)) { orders.forEach(esOrder -> searchSourceBuilder.sort(esOrder.getProperty(), esOrder.getDirection())); } } SearchResponse searchResponse = null; try { searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } if (searchResponse == null) { return null; } SearchHits searchHits = searchResponse.getHits(); SearchHit[] hits = searchHits.getHits(); List<T> genericInstanceList = new ArrayList<>(); Arrays.stream(hits).forEach(hit -> { String sourceAsString = hit.getSourceAsString(); genericInstanceList.add(JSON.parseObject(sourceAsString, genericClass)); }); TotalHits totalHits = searchHits.getTotalHits(); long total = totalHits.value; ESPageResult<T> pageResult = new ESPageResult<>( total, esPageRequest != null ? esPageRequest.getPageNo() : -1, esPageRequest != null ? esPageRequest.getSize() : -1, genericInstanceList); return pageResult; } /** * ============================================================================================================ * 私有方法 * ============================================================================================================ * */ private List<T> searchList() { SearchResponse searchResponse = elasticsearchUtils.search(indexName); SearchHit[] hits = searchResponse.getHits().getHits(); List<T> genericInstanceList = new ArrayList<>(); Arrays.stream(hits).forEach(hit -> { String sourceAsString = hit.getSourceAsString(); genericInstanceList.add(JSON.parseObject(sourceAsString, genericClass)); }); return genericInstanceList; } /** * 获取当前操作的genericInstance的主键ID * * @param genericInstance 实例对象 * @return 返回主键ID值 */ private String getIdValue(T genericInstance) { try { Object idValue = idField.get(genericInstance); return idValue.toString(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } }
2.ElasticsearchUtils
/** * @author zhangboqing * @date 2019/12/10 */ @Slf4j @Component public class ElasticsearchUtils { @Autowired public RestHighLevelClient client; @Autowired private ElasticsearchProperties elasticsearchProperties; public static final RequestOptions COMMON_OPTIONS; static { RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder(); // 默认缓冲限制为100MB,此处修改为30MB。 builder.setHttpAsyncResponseConsumerFactory(new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(30 * 1024 * 1024)); COMMON_OPTIONS = builder.build(); } public boolean existIndex(String indexName) { boolean exists = false; try { GetIndexRequest request = new GetIndexRequest(indexName); exists = client.indices().exists(request, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); throw new ElasticsearchException("判断索引 {" + indexName + "} 是否存在失败"); } return exists; } public void createIndexRequest(String indexName) { createIndexRequest(indexName, elasticsearchProperties.getIndex().getNumberOfShards(), elasticsearchProperties.getIndex().getNumberOfReplicas()); } public void createIndexRequest(String indexName, int shards, int replicas) { if (existIndex(indexName)) { return; } try { CreateIndexRequest request = new CreateIndexRequest(indexName); // Settings for this index request.settings(Settings.builder() .put("index.number_of_shards", shards) .put("index.number_of_replicas", replicas) ); CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); log.info(" acknowledged : {}", createIndexResponse.isAcknowledged()); log.info(" shardsAcknowledged :{}", createIndexResponse.isShardsAcknowledged()); } catch (IOException e) { throw new ElasticsearchException("创建索引 {" + indexName + "} 失败"); } } public void putMappingRequest(String indexName, Class clazz) { Field[] fields = clazz.getDeclaredFields(); if (fields == null || fields.length == 0) { return; } try { PutMappingRequest request = new PutMappingRequest(indexName); XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject(); { builder.startObject("properties"); { for (int i = 0; i < fields.length; i++) { Field field = fields[i]; ESId esId = field.getAnnotation(ESId.class); if (esId != null) { continue; } else { AnnotationAttributes esField = AnnotatedElementUtils.getMergedAnnotationAttributes(field, ESField.class); if (esField == null) { continue; } String name = esField.getString("name"); if (StringUtils.isEmpty(name)) { throw new ElasticsearchException("注解ESField的name属性未指定"); } ESFieldType esFieldType = (ESFieldType) esField.get("type"); if (esFieldType == null) { throw new ElasticsearchException("注解ESField的type属性未指定"); } builder.startObject(name); { builder.field("type", esFieldType.typeName); // 分词器 String analyzer = esField.getString("analyzer"); if (StringUtils.hasText(analyzer)) { builder.field("analyzer", analyzer); } } builder.endObject(); } } } builder.endObject(); } builder.endObject(); request.source(builder); AcknowledgedResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT); log.info("acknowledged : :{}", putMappingResponse.isAcknowledged()); } catch (IOException e) { e.printStackTrace(); } } public void deleteIndexRequest(String index) { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index); try { client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); } catch (IOException e) { throw new ElasticsearchException("删除索引 {" + index + "} 失败"); } } public static IndexRequest buildIndexRequest(String index, String id, Object object) { return new IndexRequest(index).id(id).source(JSON.toJSONString(object), XContentType.JSON); } public void updateRequest(String index, String id, Object object) { try { UpdateRequest updateRequest = new UpdateRequest(index, id).doc(JSON.toJSONString(object), XContentType.JSON); client.update(updateRequest, COMMON_OPTIONS); } catch (IOException e) { throw new ElasticsearchException("更新索引 {" + index + "} 数据 {" + object + "} 失败"); } } public void deleteRequest(String index, String id) { try { DeleteRequest deleteRequest = new DeleteRequest(index, id); client.delete(deleteRequest, COMMON_OPTIONS); } catch (IOException e) { throw new ElasticsearchException("删除索引 {" + index + "} 数据id {" + id + "} 失败"); } } public SearchResponse search(String index) { SearchRequest searchRequest = new SearchRequest(index); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = null; try { searchResponse = client.search(searchRequest, COMMON_OPTIONS); } catch (IOException e) { e.printStackTrace(); } return searchResponse; } }
3.ESPageRequest
/** * 分页 * @author zhangboqing * @date 2019/12/29 */ @Data public class ESPageRequest { private final int pageNo; private final int size; public ESPageRequest(int pageNo, int size) { if (pageNo < 0) { throw new IllegalArgumentException("Page index must not be less than zero!"); } if (size < 1) { throw new IllegalArgumentException("Page size must not be less than one!"); } this.pageNo = pageNo; this.size = size; } }
4.ESPageResult
/** * @Author zhangboqing * @Date 2019-12-30 * 分页结果 */ @Data public class ESPageResult<T> { private final long total; private final int pageNo; private final int pageSize; private List<T> results; public ESPageResult(long total, int pageNo, int pageSize, List<T> results) { this.total = total; this.pageNo = pageNo; this.pageSize = pageSize; this.results = results; } }
5.ESSort
/** * @Author zhangboqing * @Date 2019/12/29 * 封装排序参数 */ public class ESSort { public final List<ESOrder> orders; public ESSort() { orders = new ArrayList<>(); } public ESSort(SortOrder direction, String property) { orders = new ArrayList<>(); add(direction,property); } /** * 追加排序字段 * @param direction 排序方向 * @param property 排序字段 * @return */ public ESSort add(SortOrder direction, String property) { Assert.notNull(direction, "direction must not be null!"); Assert.hasText(property, "fieldName must not be empty!"); orders.add(ESOrder.builder().direction(direction).property(property).build()); return this; } @Builder @Data public static class ESOrder implements Serializable { private final SortOrder direction; private final String property; } }
4)定义的enum枚举类
1.ESFieldType
/** * @author zhangboqing * @date 2019/12/12 */ public enum ESFieldType { Text("text"), Byte("byte"), Short("short"), Integer("integer"), Long("long"), Date("date"), Float("float"), Double("double"), Boolean("boolean"), Object("object"), Keyword("keyword"); ESFieldType(String typeName) { this.typeName = typeName; } public String typeName; }
5)自定义异常类
1.ApiException
public class ApiException extends RuntimeException { private ApiResponseCode responseCode; private IApiResponseCode iApiResponseCode; private ApiException.ErrorPrintLogLevelEnum errorPrintLogLevelEnum; private Integer code; public ApiException() { } public ApiException(String message) { super(message); } public ApiException(String message, Throwable cause) { super(message, cause); } public ApiException(Throwable cause) { super(cause); } public ApiException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public ApiException(Integer code, String message) { super(message); this.code = code; } public ApiException(ApiResponseCode responseCode) { super(responseCode.message); this.responseCode = responseCode; this.code = responseCode.getCode(); } public ApiException(ApiResponseCode responseCode, String message) { super(message); this.responseCode = responseCode; this.code = responseCode.getCode(); } public ApiException(ApiResponseCode responseCode, Throwable cause) { super(responseCode.message, cause); this.responseCode = responseCode; this.code = responseCode.getCode(); } public ApiException(ApiResponseCode responseCode, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(responseCode.message, cause, enableSuppression, writableStackTrace); this.responseCode = responseCode; this.code = responseCode.getCode(); } public ApiException(IApiResponseCode iApiResponseCode) { super(iApiResponseCode.getMessage()); this.iApiResponseCode = iApiResponseCode; this.code = iApiResponseCode.getCode(); } public ApiException(IApiResponseCode iApiResponseCode, String message) { super(message); this.iApiResponseCode = iApiResponseCode; this.code = iApiResponseCode.getCode(); } public ApiException(IApiResponseCode iApiResponseCode, String message, ApiException.ErrorPrintLogLevelEnum errorPrintLogLevel) { super(message); this.iApiResponseCode = iApiResponseCode; this.code = iApiResponseCode.getCode(); this.errorPrintLogLevelEnum = errorPrintLogLevel; } public ApiException(IApiResponseCode iApiResponseCode, Throwable cause) { super(iApiResponseCode.getMessage(), cause); this.iApiResponseCode = iApiResponseCode; this.code = iApiResponseCode.getCode(); } public ApiException(IApiResponseCode iApiResponseCode, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(iApiResponseCode.getMessage(), cause, enableSuppression, writableStackTrace); this.iApiResponseCode = iApiResponseCode; this.code = iApiResponseCode.getCode(); } public ApiResponseCode getResponseCode() { return this.responseCode; } public IApiResponseCode getIApiResponseCode() { return this.iApiResponseCode; } public ApiException.ErrorPrintLogLevelEnum getErrorPrintLogLevelEnum() { return this.errorPrintLogLevelEnum; } public Integer getCode() { return this.code; } public void setResponseCode(ApiResponseCode responseCode) { this.responseCode = responseCode; } public void setIApiResponseCode(IApiResponseCode iApiResponseCode) { this.iApiResponseCode = iApiResponseCode; } public void setErrorPrintLogLevelEnum(ApiException.ErrorPrintLogLevelEnum errorPrintLogLevelEnum) { this.errorPrintLogLevelEnum = errorPrintLogLevelEnum; } public void setCode(Integer code) { this.code = code; } public static enum ErrorPrintLogLevelEnum { NONE, TRACE, DEBUG, INFO, WARN, ERROR; private ErrorPrintLogLevelEnum() { } } }
2.ApiResponseCode
public enum ApiResponseCode implements IApiResponseCode { SUCCESS(0, "成功"), FAILED(1, "失败"); public Integer code; public String message; @Override public Integer getCode() { return this.code; } @Override public String getMessage() { return this.message; } private ApiResponseCode(Integer code, String message) { this.code = code; this.message = message; } public String toString() { return "ApiResponseCode(code=" + this.getCode() + ", message=" + this.getMessage() + ")"; } }
3.IApiResponseCode
/** * @author zhangboqing * @date 2019/12/10 */ public interface IApiResponseCode { Integer getCode(); String getMessage(); }
4.ElasticsearchException
/** * @author zhangboqing * @date 2019/12/10 */ public class ElasticsearchException extends ApiException { public ElasticsearchException(String message) { super(ApiResponseCode.FAILED,message); } }
6)elasticsearch核心config类
1.ElasticsearchProperties
/** * @author zhangboqing * @date 2019/12/10 */ @Data @Builder @Component @NoArgsConstructor @AllArgsConstructor @ConfigurationProperties(prefix = "demo.data.elasticsearch") public class ElasticsearchProperties { /** * 请求协议 */ private String schema = "http"; /** * 集群名称 */ private String clusterName = "elasticsearch"; /** * 集群节点 */ @NotNull(message = "集群节点不允许为空") private List<String> clusterNodes = new ArrayList<>(); /** * 连接超时时间(毫秒) */ private Integer connectTimeout = 1000; /** * socket 超时时间 */ private Integer socketTimeout = 30000; /** * 连接请求超时时间 */ private Integer connectionRequestTimeout = 500; /** * 每个路由的最大连接数量 */ private Integer maxConnectPerRoute = 10; /** * 最大连接总数量 */ private Integer maxConnectTotal = 30; /** * 索引配置信息 */ private Index index = new Index(); /** * 认证账户 */ private Account account = new Account(); /** * 索引配置信息 */ @Data public static class Index { /** * 分片数量 */ private Integer numberOfShards = 3; /** * 副本数量 */ private Integer numberOfReplicas = 2; } /** * 认证账户 */ @Data public static class Account { /** * 认证用户 */ private String username; /** * 认证密码 */ private String password; } }
2.ElasticsearchConfig
/** * @author zhangboqing * @date 2019/12/10 */ @Configuration @RequiredArgsConstructor(onConstructor_ = @Autowired) @EnableAutoConfiguration(exclude = {RestClientAutoConfiguration.class}) public class ElasticsearchConfig { private final ElasticsearchProperties elasticsearchProperties; @Bean public RestHighLevelClient initailizationRestHighLevelClient() { // 设置es节点 List<HttpHost> httpHosts = new ArrayList<>(); List<String> clusterNodes = elasticsearchProperties.getClusterNodes(); clusterNodes.forEach(node -> { try { String[] parts = StringUtils.split(node, ":"); Assert.notNull(parts, "Must defined"); Assert.state(parts.length == 2, "Must be defined as 'host:port'"); httpHosts.add(new HttpHost(parts[0], Integer.parseInt(parts[1]), elasticsearchProperties.getSchema())); } catch (Exception e) { throw new IllegalStateException("Invalid ES nodes " + "property '" + node + "'", e); } }); RestClientBuilder builder = RestClient.builder(httpHosts.toArray(new HttpHost[0])); final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "123456")); builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { return httpClientBuilder // 线程数量 // .setDefaultIOReactorConfig( // IOReactorConfig.custom() // .setIoThreadCount(1) // .build()) // 认证设置 .setDefaultCredentialsProvider(credentialsProvider); } }) // 超时时间 .setRequestConfigCallback( new RestClientBuilder.RequestConfigCallback() { @Override public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) { return requestConfigBuilder.setConnectTimeout(5000).setSocketTimeout(60000); } }); RestHighLevelClient client = new RestHighLevelClient(builder); return client; } }
3.ElasticsearchApplicationListener
/** * @author zhangboqing * @date 2019/12/10 */ @Component @Slf4j public class ElasticsearchApplicationListener implements ApplicationListener<ContextRefreshedEvent>, ApplicationContextAware { @Autowired protected ElasticsearchUtils elasticsearchUtils; private ApplicationContext applicationContext; @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { String[] beanNames = applicationContext.getBeanNamesForType(BaseElasticsearchDao.class); if (beanNames != null && beanNames.length > 0) { for (int i = 0; i < beanNames.length; i++) { String beanName = beanNames[i]; if (beanName.contains("com.zbq.springbootelasticsearch.common.elasticsearch.base.BaseElasticsearchDao")) { continue; } Object bean = applicationContext.getBean(beanName); Class<?> targetBeanClass = bean.getClass(); Class<?> beanClass = GenericTypeResolver.resolveTypeArgument(targetBeanClass, BaseElasticsearchDao.class); ESDocument esDocument = AnnotationUtils.findAnnotation(beanClass, ESDocument.class); if (esDocument == null) { throw new ElasticsearchException("ESDocument注解未指定"); } String indexName = esDocument.indexName(); if (StringUtils.isEmpty(indexName)) { throw new ElasticsearchException("indexName未指定"); } int shards = esDocument.shards(); int replicas = esDocument.replicas(); if (shards == 0 || replicas == 0) { elasticsearchUtils.createIndexRequest(indexName); } else { elasticsearchUtils.createIndexRequest(indexName, shards, replicas); } elasticsearchUtils.putMappingRequest(indexName, beanClass); } } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
三、使用步骤
1)定义GoodsESEntity
/** * @author zhangboqing * @date 2019/12/10 */ @Data @NoArgsConstructor @AllArgsConstructor @Builder @ESDocument(indexName = "goods") public class GoodsESEntity { // 筛选条件包括:商品名称,品牌,规格,适用车型,商品编号,原厂编号 /** * 主键,商品ID */ @ESId @ESField(value = "goodsId",type = ESFieldType.Long) private Long goodsId; /** * 商品名称 */ @ESField(value = "goodsName",type = ESFieldType.Keyword) private String goodsName; /** * 品牌 */ @ESField(value = "goodBrand",type = ESFieldType.Keyword) private String goodBrand; /** * 规格 */ @ESField(value = "goodsSpec",type = ESFieldType.Keyword) private String goodsSpec; /** * 商品编号 */ @ESField(value = "goodsAccessoriesCode",type = ESFieldType.Keyword) private String goodsAccessoriesCode; /** * 原厂编号 */ @ESField(value = "goodsOriginalFactoryCode",type = ESFieldType.Keyword) private String goodsOriginalFactoryCode; /** * 复合字段,会被分词后存储 */ @ESField(value = "groupData",type = ESFieldType.Text,analyzer = "ik_smart") private String groupData; }
2)定义GoodsESDao
/** * @author zhangboqing * @date 2019/12/10 */ @Component public class GoodsESDao<T extends GoodsESEntity> extends BaseElasticsearchDao<GoodsESEntity> { /** * 全文搜索查询 * @param queryName * @return */ public List<GoodsESEntity> findListByAnalysisForGroupData(String queryName) { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchQuery("groupData",queryName)); List<GoodsESEntity> search = search(searchSourceBuilder); return search; } /** * 多条件等值查询查询 * @return */ public List<GoodsESEntity> findListByEq() { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.filter(QueryBuilders.matchQuery("goodsName","保时捷跑车V10")); boolQueryBuilder.filter(QueryBuilders.matchQuery("goodBrand","国际1")); searchSourceBuilder.query(boolQueryBuilder); List<GoodsESEntity> search = search(searchSourceBuilder); return search; } /** * 多条件like查询查询 * @return */ public List<GoodsESEntity> findListByLike() { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.filter(QueryBuilders.wildcardQuery("goodsName","?V10")); boolQueryBuilder.filter(QueryBuilders.wildcardQuery("goodBrand","国际1")); searchSourceBuilder.query(boolQueryBuilder); List<GoodsESEntity> search = search(searchSourceBuilder); return search; } /** * 全文搜索查询分页排序 * @param queryName * @return * QueryBuilders.boolQuery() */ public ESPageResult findList(String queryName) { // 搜索条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchQuery("groupData",queryName)); // 分页 ESPageRequest esPageRequest = new ESPageRequest(1, 2); // 排序 ESSort esSort = new ESSort(SortOrder.ASC,"goodsName"); ESPageResult<GoodsESEntity> search = search(searchSourceBuilder, esPageRequest, esSort); return search; } }
3)配置属性
demo: data: elasticsearch: # es集群名称 cluster-name: elasticsearch # es集群节点,多个逗号分隔 localhost:9200,localhost:9400 cluster-nodes: localhost:9200 # 设置创建index时,默认的分片规则 index: number-of-shards: 3 number-of-replicas: 2 # 设置连接es的用户名和密码 account: username: elastic password: 123456
你投入得越多,就能得到越多得价值