Elasticsearch-Rest-Client

1. 通过 9300: TCP

  • spring-data-elasticsearch:transport-api.jar;

    • springboot版本不同,ransport-api.jar不同,不能适配es版本
    • 7.x已经不建议使用,8以后就要废弃

      2. 通过 9200: HTTP

  • jestClient: 非官方,更新慢;

  • RestTemplate:模拟HTTP请求,ES很多操作需要自己封装,麻烦;
  • HttpClient:同上;
  • Elasticsearch-Rest-Client:官方RestClient,封装了ES操作,API层次分明,上手简单;

最终选择Elasticsearch-Rest-Client(elasticsearch-rest-high-level-client); https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html

创建 Elasticsearch 检索服务模块

1. 新建模块

image.png

2. 检索服务模块 pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>com.zsy</groupId>
  7. <artifactId>guli-mall</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. </parent>
  10. <artifactId>mall-search</artifactId>
  11. <version>0.0.1-SNAPSHOT</version>
  12. <name>mall-search</name>
  13. <description>Elasticsearch 检索服务</description>
  14. <dependencies>
  15. <dependency>
  16. <groupId>com.zsy</groupId>
  17. <artifactId>mall-common</artifactId>
  18. <exclusions>
  19. <exclusion>
  20. <groupId>com.baomidou</groupId>
  21. <artifactId>mybatis-plus-boot-starter</artifactId>
  22. </exclusion>
  23. </exclusions>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.elasticsearch.client</groupId>
  27. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  28. </dependency>
  29. </dependencies>
  30. <build>
  31. <plugins>
  32. <plugin>
  33. <groupId>org.springframework.boot</groupId>
  34. <artifactId>spring-boot-maven-plugin</artifactId>
  35. </plugin>
  36. </plugins>
  37. </build>
  38. </project>

3. 父 pom 更新依赖检索服务

部分不完整

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.zsy</groupId>
  6. <artifactId>guli-mall</artifactId>
  7. <version>0.0.1-SNAPSHOT</version>
  8. <packaging>pom</packaging>
  9. <modules>
  10. ...
  11. <module>mall-search</module>
  12. </modules>
  13. <name>guli-mall</name>
  14. <description>parent</description>
  15. <!-- 这里的属性会被子模块继承 -->
  16. <properties>
  17. ...
  18. <elasticsearch.version>7.4.2</elasticsearch.version>
  19. </properties>
  20. <!-- 子模块继承父模块之后,提供作用:锁定版本 + 子模块不用再写 version -->
  21. <dependencyManagement>
  22. <dependencies>
  23. ...
  24. <!-- 重写覆盖 spring-boot-dependencies 中的依赖版本 -->
  25. <dependency>
  26. <groupId>org.elasticsearch.client</groupId>
  27. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  28. <version>${elasticsearch.version}</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.elasticsearch</groupId>
  32. <artifactId>elasticsearch</artifactId>
  33. <version>${elasticsearch.version}</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.elasticsearch.client</groupId>
  37. <artifactId>elasticsearch-rest-client</artifactId>
  38. <version>${elasticsearch.version}</version>
  39. </dependency>
  40. </dependencies>
  41. </dependencyManagement>
  42. </project>

4. 配置application.yaml

  1. spring:
  2. application:
  3. name: mall-search
  4. cloud:
  5. nacos:
  6. discovery:
  7. server-addr: 192.168.163.131:8848

5. 主启动类增加注册服务注解

  1. @EnableDiscoveryClient
  2. @SpringBootApplication
  3. public class MallSearchApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(MallSearchApplication.class, args);
  6. }
  7. }

SpringBoot对应Elasticsearch版本过低问题

参考:多模块开发SpringBoot项目自定义第三方依赖版本

问题说明

当前Maven Pom文件中没有将spring-boot-starter-parent作为父项目依赖。所以会出现下面的问题。

  1. 我们用的Springboot版本依赖管理为 2.2.5,对应 es版本为 6.8.6(需要7.4.2)

image.png

  1. 我们在父模块中定义7.4.2的版本号

image.png

  1. 引入 elasticsearch-rest-high-level-client 发现子依赖的 elasticsearch 版本仍然用 springboot-dependencies中的版本

image.png

问题解决:

如果你使用Maven进行一个直接或间接继承spring-boot-dependencies(比如spring-boot-starter-parent)的构建,并想覆盖一个特定的第三方依赖,那你可以添加合适的元素。浏览spring-boot-dependencies POM可以获取一个全面的属性列表。例如,想要选择一个不同的elasticsearch版本,你可以添加以下内容:

  1. <properties>
  2. <elasticsearch.version>7.4.2</elasticsearch.version>
  3. </properties>

但是这只在你的Maven项目继承(直接或间接)自spring-boot-dependencies才有用。
如果你使用<scope>import</scope>,将spring-boot-dependencies添加到自己的dependencyManagement片段,那你必须自己重新定义artifact而不是覆盖属性。
image.png
image.png
需要在 <dependencyManagement> 下重新定义 artifact

  1. <dependency>
  2. <groupId>org.elasticsearch.client</groupId>
  3. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  4. <version>${elasticsearch.version}</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.elasticsearch</groupId>
  8. <artifactId>elasticsearch</artifactId>
  9. <version>${elasticsearch.version}</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.elasticsearch.client</groupId>
  13. <artifactId>elasticsearch-rest-client</artifactId>
  14. <version>${elasticsearch.version}</version>
  15. </dependency>

编码测试

具体操作参考:es 操作API

1. 编写配置类

配置客户端Bean 配置请求选项

  1. package com.zsy.search.config;
  2. /**
  3. * @author: zhangshuaiyin
  4. * @date: 2021/3/11 15:22
  5. */
  6. @Configuration
  7. public class MallElasticSearchConfig {
  8. /**
  9. * 配置请求选项
  10. * 参考:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-low-usage-requests.html#java-rest-low-usage-request-options
  11. */
  12. public static final RequestOptions COMMON_OPTIONS;
  13. static {
  14. RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
  15. // builder.addHeader("Authorization", "Bearer " + TOKEN);
  16. // builder.setHttpAsyncResponseConsumerFactory(
  17. // new HttpAsyncResponseConsumerFactory
  18. // .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
  19. COMMON_OPTIONS = builder.build();
  20. }
  21. @Bean
  22. public RestHighLevelClient esRestClient() {
  23. return new RestHighLevelClient(
  24. RestClient.builder(
  25. new HttpHost("192.168.163.131", 9200, "http")));
  26. }
  27. }

2. 测试配置类依赖注入

  1. package com.zsy;
  2. /**
  3. * 下面的测试都在本测试类下完成,只标注方法
  4. */
  5. @SpringBootTest
  6. class MallSearchApplicationTests {
  7. @Autowired
  8. RestHighLevelClient client;
  9. @Test
  10. void contextLoads() {
  11. System.out.println(client);
  12. }
  13. }

3. 测试存储数据(更新)

参考:Index API

  1. /**
  2. * 测试存储数据到 es
  3. * source 方法用于保存数据,数据的格式为键值对形式的类型
  4. * - json 字符串
  5. * - Map
  6. * - XContentBuilder
  7. * - KV 键值对
  8. * - 实体类对象转json
  9. */
  10. @Test
  11. void indexData() throws IOException {
  12. IndexRequest indexRequest = new IndexRequest("users");
  13. indexRequest.id("1");
  14. // json 字符串
  15. indexRequest.source("{" +
  16. "\"user\":\"kimchy\"," +
  17. "\"postDate\":\"2013-01-30\"," +
  18. "\"message\":\"trying out Elasticsearch\"" +
  19. "}", XContentType.JSON);
  20. // KV 键值对
  21. // indexRequest.source("username", "zhangsan", "age", 12, "address", "sz");
  22. // 同步执行
  23. client.index(indexRequest, MallElasticSearchConfig.COMMON_OPTIONS);
  24. }

Kibana 检索查看

  1. GET users/_search

4. 测试复杂检索

参考: Search API

检索地址中带有 mill 的人员年龄分布和平均薪资

  1. /**
  2. * 检索地址中带有 mill 的人员年龄分布和平均薪资
  3. */
  4. @Test
  5. void searchData() throws IOException {
  6. // 1. 创建检索请求
  7. SearchRequest searchRequest = new SearchRequest();
  8. // 指定索引
  9. searchRequest.indices("bank");
  10. // 指定 DSL 检索条件
  11. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  12. // 1.1 构建检索条件 address 包含 mill
  13. searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
  14. // 1.2 按照年龄值分布进行聚合
  15. TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
  16. searchSourceBuilder.aggregation(ageAgg);
  17. // 1.3 计算平均薪资
  18. AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
  19. searchSourceBuilder.aggregation(balanceAvg);
  20. System.out.println("检索条件:" + searchSourceBuilder.toString());
  21. searchRequest.source(searchSourceBuilder);
  22. // 2. 执行检索, 获得响应
  23. SearchResponse searchResponse = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS);
  24. // 3. 分析结果
  25. // 3.1 获取所有查到的记录
  26. SearchHits hits = searchResponse.getHits();
  27. SearchHit[] searchHits = hits.getHits();
  28. for (SearchHit hit : searchHits) {
  29. // 数据字符串
  30. String jsonString = hit.getSourceAsString();
  31. System.out.println(jsonString);
  32. // 可以通过 json 转换成实体类对象
  33. // Account account = JSON.parseObject(jsonString, Account.class);
  34. }
  35. // 3.2 获取检索的分析信息(聚合数据等)
  36. Aggregations aggregations = searchResponse.getAggregations();
  37. // for (Aggregation aggregation : aggregations.asList()) {
  38. // System.out.println("当前聚合名:" + aggregation.getName());
  39. // }
  40. Terms ageAgg1 = aggregations.get("ageAgg");
  41. for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
  42. String keyAsString = bucket.getKeyAsString();
  43. System.out.println("年龄:" + keyAsString + " 岁的有 " + bucket.getDocCount() + " 人");
  44. }
  45. Avg balanceAvg1 = aggregations.get("balanceAvg");
  46. System.out.println("平均薪资: " + balanceAvg1.getValue());
  47. }