Elasticsearch-Rest-Client

通过 9300: TCP

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

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

      通过 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 检索服务模块

新建模块

image.png
image.png

pom.xml

  1. <properties>
  2. <java.version>1.8</java.version>
  3. <!-- SpringBoot管理了elasticsearch的版本, 所有我们需要重写这个版本 -->
  4. <elasticsearch.version>7.4.2</elasticsearch.version>
  5. </properties>
  6. <dependencies>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-web</artifactId>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.elasticsearch.client</groupId>
  13. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-test</artifactId>
  18. <scope>test</scope>
  19. </dependency>
  20. <!-- 用来转换JSON数据 -->
  21. <dependency>
  22. <groupId>com.alibaba</groupId>
  23. <artifactId>fastjson</artifactId>
  24. <version>1.2.76</version>
  25. </dependency>
  26. </dependencies>

编码测试

具体操作参考:es 操作API

编写配置类

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

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

测试配置类依赖注入

  1. package org.hong.gulimall.search;
  2. import org.elasticsearch.client.RestHighLevelClient;
  3. import org.junit.jupiter.api.Test;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.boot.test.context.SpringBootTest;
  6. @SpringBootTest
  7. class GulimallSearchApplicationTests {
  8. @Autowired
  9. RestHighLevelClient client;
  10. @Test
  11. void contextLoads() {
  12. System.out.println(client);
  13. }
  14. }

测试存储数据 ( 更新 )

参考:Index API

  1. package org.hong.gulimall.search;
  2. import com.alibaba.fastjson.JSON;
  3. import lombok.Data;
  4. import org.elasticsearch.action.index.IndexRequest;
  5. import org.elasticsearch.action.index.IndexResponse;
  6. import org.elasticsearch.client.RestHighLevelClient;
  7. import org.elasticsearch.common.xcontent.XContentType;
  8. import org.hong.gulimall.search.config.ElasticsearchConfig;
  9. import org.junit.jupiter.api.Test;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.boot.test.context.SpringBootTest;
  12. import java.io.IOException;
  13. @SpringBootTest
  14. class GulimallSearchApplicationTests {
  15. @Autowired
  16. RestHighLevelClient client;
  17. @Data
  18. class User{
  19. private String userName;
  20. private String gender;
  21. private Integer age;
  22. }
  23. @Test
  24. void indexData() throws IOException {
  25. // 创建IndexRequest对象
  26. IndexRequest indexRequest = new IndexRequest();
  27. // 设置index
  28. indexRequest.index("users");
  29. // 设置id
  30. indexRequest.id("1");
  31. // 准备需要保存的数据
  32. User user = new User();
  33. user.setUserName("hong");
  34. user.setAge(18);
  35. user.setGender("男");
  36. // 将对象转换成JSON格式的数据
  37. String jsonString = JSON.toJSONString(user);
  38. // 设置资源
  39. indexRequest.source(jsonString, XContentType.JSON);
  40. // 执行操作
  41. IndexResponse index = client.index(indexRequest, ElasticsearchConfig.COMMON_OPTIONS);
  42. // 提取有用的响应数据
  43. System.out.println(index);
  44. }
  45. }

控制台打印

  1. IndexResponse[index=users,type=_doc,id=1,version=1,result=created,seqNo=0,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]

Kibana 检索查看

  1. GET /users/_search
  1. {
  2. "took" : 4,
  3. "timed_out" : false,
  4. "_shards" : {
  5. "total" : 1,
  6. "successful" : 1,
  7. "skipped" : 0,
  8. "failed" : 0
  9. },
  10. "hits" : {
  11. "total" : {
  12. "value" : 1,
  13. "relation" : "eq"
  14. },
  15. "max_score" : 1.0,
  16. "hits" : [
  17. {
  18. "_index" : "users",
  19. "_type" : "_doc",
  20. "_id" : "1",
  21. "_score" : 1.0,
  22. "_source" : {
  23. "age" : 18,
  24. "gender" : "男",
  25. "userName" : "hong"
  26. }
  27. }
  28. ]
  29. }
  30. }

测试复杂检索

参考: Search API

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

  1. package org.hong.gulimall.search;
  2. import com.alibaba.fastjson.JSON;
  3. import lombok.Data;
  4. import org.elasticsearch.action.search.SearchRequest;
  5. import org.elasticsearch.action.search.SearchResponse;
  6. import org.elasticsearch.client.RestHighLevelClient;
  7. import org.elasticsearch.index.query.QueryBuilders;
  8. import org.elasticsearch.search.SearchHit;
  9. import org.elasticsearch.search.SearchHits;
  10. import org.elasticsearch.search.aggregations.AggregationBuilders;
  11. import org.elasticsearch.search.aggregations.Aggregations;
  12. import org.elasticsearch.search.aggregations.bucket.terms.Terms;
  13. import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
  14. import org.elasticsearch.search.aggregations.metrics.Avg;
  15. import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
  16. import org.elasticsearch.search.builder.SearchSourceBuilder;
  17. import org.hong.gulimall.search.config.ElasticsearchConfig;
  18. import org.junit.jupiter.api.Test;
  19. import org.springframework.beans.factory.annotation.Autowired;
  20. import org.springframework.boot.test.context.SpringBootTest;
  21. import java.io.IOException;
  22. @SpringBootTest
  23. class GulimallSearchApplicationTests {
  24. @Autowired
  25. RestHighLevelClient client;
  26. @Data
  27. static class Account {
  28. private int account_number;
  29. private int balance;
  30. private String firstname;
  31. private String lastname;
  32. private int age;
  33. private String gender;
  34. private String address;
  35. private String employer;
  36. private String email;
  37. private String city;
  38. private String state;
  39. }
  40. @Test
  41. void searchData() throws IOException {
  42. // 1、创建检索请求
  43. SearchRequest searchRequest = new SearchRequest();
  44. // 指定索引
  45. searchRequest.indices("bank");
  46. // 指定DSL, 检索条件
  47. SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  48. // 1.1、构造检索条件 address 包含 mill
  49. searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
  50. // 1.2 按照年龄值分布进行聚合
  51. TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(100);
  52. // 嵌套聚合subAggregation()方法
  53. //ageAgg.subAggregation(AggregationBuilders.avg("balanceAvg").field("balance"));
  54. searchSourceBuilder.aggregation(ageAgg);
  55. // 1.3 计算平均薪资
  56. AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
  57. searchSourceBuilder.aggregation(balanceAvg);
  58. searchRequest.source(searchSourceBuilder);
  59. System.out.println(searchSourceBuilder);
  60. // 2、执行检索
  61. SearchResponse searchResponse = client.search(searchRequest, ElasticsearchConfig.COMMON_OPTIONS);
  62. // 3、分析结果
  63. System.out.println(searchResponse);
  64. // 3.1、获取所有查询到的数据
  65. SearchHits hits = searchResponse.getHits();
  66. SearchHit[] searchHits = hits.getHits();
  67. for (SearchHit searchHit : searchHits) {
  68. // 获取JSON格式的数据
  69. String sourceAsString = searchHit.getSourceAsString();
  70. Account account = JSON.parseObject(sourceAsString, Account.class);
  71. System.out.println(account);
  72. }
  73. // 3.2、获取检索到的分析信息
  74. Aggregations aggregations = searchResponse.getAggregations();
  75. Terms ageAgg1 = aggregations.get("ageAgg");
  76. for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
  77. System.out.println("年龄:" + bucket.getKey() + "\t" + "数量:" + bucket.getDocCount());
  78. }
  79. Avg avgBalance = aggregations.get("balanceAvg");
  80. System.out.println("平均薪资:" + avgBalance.getValue());
  81. }
  82. }