Elasticsearch-Rest-Client
1. 通过 9300: TCP
spring-data-elasticsearch:transport-api.jar;
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. 新建模块
2. 检索服务模块 pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.zsy</groupId><artifactId>guli-mall</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>mall-search</artifactId><version>0.0.1-SNAPSHOT</version><name>mall-search</name><description>Elasticsearch 检索服务</description><dependencies><dependency><groupId>com.zsy</groupId><artifactId>mall-common</artifactId><exclusions><exclusion><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
3. 父 pom 更新依赖检索服务
部分不完整
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zsy</groupId><artifactId>guli-mall</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><modules>...<module>mall-search</module></modules><name>guli-mall</name><description>parent</description><!-- 这里的属性会被子模块继承 --><properties>...<elasticsearch.version>7.4.2</elasticsearch.version></properties><!-- 子模块继承父模块之后,提供作用:锁定版本 + 子模块不用再写 version --><dependencyManagement><dependencies>...<!-- 重写覆盖 spring-boot-dependencies 中的依赖版本 --><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>${elasticsearch.version}</version></dependency><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>${elasticsearch.version}</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>${elasticsearch.version}</version></dependency></dependencies></dependencyManagement></project>
4. 配置application.yaml
spring:application:name: mall-searchcloud:nacos:discovery:server-addr: 192.168.163.131:8848
5. 主启动类增加注册服务注解
@EnableDiscoveryClient@SpringBootApplicationpublic class MallSearchApplication {public static void main(String[] args) {SpringApplication.run(MallSearchApplication.class, args);}}
SpringBoot对应Elasticsearch版本过低问题
参考:多模块开发SpringBoot项目自定义第三方依赖版本
问题说明
当前Maven Pom文件中没有将spring-boot-starter-parent作为父项目依赖。所以会出现下面的问题。
- 我们用的Springboot版本依赖管理为 2.2.5,对应 es版本为 6.8.6(需要7.4.2)

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

- 引入 elasticsearch-rest-high-level-client 发现子依赖的 elasticsearch 版本仍然用 springboot-dependencies中的版本
问题解决:
如果你使用Maven进行一个直接或间接继承spring-boot-dependencies(比如spring-boot-starter-parent)的构建,并想覆盖一个特定的第三方依赖,那你可以添加合适的
<properties><elasticsearch.version>7.4.2</elasticsearch.version></properties>
但是这只在你的Maven项目继承(直接或间接)自spring-boot-dependencies才有用。
如果你使用<scope>import</scope>,将spring-boot-dependencies添加到自己的dependencyManagement片段,那你必须自己重新定义artifact而不是覆盖属性。

需要在 <dependencyManagement> 下重新定义 artifact
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>${elasticsearch.version}</version></dependency><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>${elasticsearch.version}</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>${elasticsearch.version}</version></dependency>
编码测试
具体操作参考:es 操作API
1. 编写配置类
package com.zsy.search.config;/*** @author: zhangshuaiyin* @date: 2021/3/11 15:22*/@Configurationpublic class MallElasticSearchConfig {/*** 配置请求选项* 参考:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-low-usage-requests.html#java-rest-low-usage-request-options*/public static final RequestOptions COMMON_OPTIONS;static {RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();// builder.addHeader("Authorization", "Bearer " + TOKEN);// builder.setHttpAsyncResponseConsumerFactory(// new HttpAsyncResponseConsumerFactory// .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));COMMON_OPTIONS = builder.build();}@Beanpublic RestHighLevelClient esRestClient() {return new RestHighLevelClient(RestClient.builder(new HttpHost("192.168.163.131", 9200, "http")));}}
2. 测试配置类依赖注入
package com.zsy;/*** 下面的测试都在本测试类下完成,只标注方法*/@SpringBootTestclass MallSearchApplicationTests {@AutowiredRestHighLevelClient client;@Testvoid contextLoads() {System.out.println(client);}}
3. 测试存储数据(更新)
参考:Index API
/*** 测试存储数据到 es* source 方法用于保存数据,数据的格式为键值对形式的类型* - json 字符串* - Map* - XContentBuilder* - KV 键值对* - 实体类对象转json*/@Testvoid indexData() throws IOException {IndexRequest indexRequest = new IndexRequest("users");indexRequest.id("1");// json 字符串indexRequest.source("{" +"\"user\":\"kimchy\"," +"\"postDate\":\"2013-01-30\"," +"\"message\":\"trying out Elasticsearch\"" +"}", XContentType.JSON);// KV 键值对// indexRequest.source("username", "zhangsan", "age", 12, "address", "sz");// 同步执行client.index(indexRequest, MallElasticSearchConfig.COMMON_OPTIONS);}
Kibana 检索查看
GET users/_search
4. 测试复杂检索
参考: Search API
检索地址中带有 mill 的人员年龄分布和平均薪资
/*** 检索地址中带有 mill 的人员年龄分布和平均薪资*/@Testvoid searchData() throws IOException {// 1. 创建检索请求SearchRequest searchRequest = new SearchRequest();// 指定索引searchRequest.indices("bank");// 指定 DSL 检索条件SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();// 1.1 构建检索条件 address 包含 millsearchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));// 1.2 按照年龄值分布进行聚合TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);searchSourceBuilder.aggregation(ageAgg);// 1.3 计算平均薪资AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");searchSourceBuilder.aggregation(balanceAvg);System.out.println("检索条件:" + searchSourceBuilder.toString());searchRequest.source(searchSourceBuilder);// 2. 执行检索, 获得响应SearchResponse searchResponse = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS);// 3. 分析结果// 3.1 获取所有查到的记录SearchHits hits = searchResponse.getHits();SearchHit[] searchHits = hits.getHits();for (SearchHit hit : searchHits) {// 数据字符串String jsonString = hit.getSourceAsString();System.out.println(jsonString);// 可以通过 json 转换成实体类对象// Account account = JSON.parseObject(jsonString, Account.class);}// 3.2 获取检索的分析信息(聚合数据等)Aggregations aggregations = searchResponse.getAggregations();// for (Aggregation aggregation : aggregations.asList()) {// System.out.println("当前聚合名:" + aggregation.getName());// }Terms ageAgg1 = aggregations.get("ageAgg");for (Terms.Bucket bucket : ageAgg1.getBuckets()) {String keyAsString = bucket.getKeyAsString();System.out.println("年龄:" + keyAsString + " 岁的有 " + bucket.getDocCount() + " 人");}Avg balanceAvg1 = aggregations.get("balanceAvg");System.out.println("平均薪资: " + balanceAvg1.getValue());}
