赞
踩
前面记录了 Elasticsearch 全文检索的入门篇和进阶检索。这次我们来讲下 Spring Boot 中如何整合 ES,以及如何在 Spring Cloud 微服务项目中使用 ES 来实现全文检索,来达到商品检索的功能。
检索服务单独作为一个服务,就称作 gulimall-search 模块。
点击 Next 勾选 Spring Web 依赖,点击 finish 即可
1.添加 es 高阶客户端
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.4.2</version>
</dependency>
2.选择 java 和 elasticsearch 版本
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.4.2</elasticsearch.version>
</properties>
3.将之前的 common 包导入
<dependency>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
添加完依赖后,我们就可以将搜索服务注册到 nacos 注册中心了。 nacos 注册中心的用法在前面几篇文章中也详细讲解过,这里需要注意的是要先启动 nacos 注册中心,才能正常注册 gulimall-search 服务。
spring.application.name=gulimall-search
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
给启动类添加服务发现注解:@EnableDiscoveryClient,这样 gulimall-search 服务就可以被注册中心发现了。
因 common 模块依赖数据源,但 search 模块不依赖数据源,所以该模块需要移除数据源依赖,检索服务启动类如下
@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class GulimallSearchApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallSearchApplication.class, args);
}
}
@Configuration
public class ElasticsearchConfig {
@Bean
// 给容器注册一个 RestHighLevelClient,用来操作 ES
// 参考官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.9/java-rest-high-getting-started-initialization.html
public RestHighLevelClient restHighLevelClient() {
return new RestHighLevelClient(
RestClient.builder(
new HttpHost("192.168.57.129", 9200, "http")));
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallSearchApplicationTests {
@Resource
private RestHighLevelClient restHighLevelClient;
@Test
public void contextLoads() {
System.out.println(restHighLevelClient);
}
}
运行结果如下所示,打印出了 RestHighLevelClient。说明自定义的 ES Client 自动装载成功。
ElasticsearchConfig 安全配置
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();
}
测试类
/** * 测试存储数据到es * 更新也可以 * @throws IOException */ @Test public void indexData() throws IOException { IndexRequest index = new IndexRequest("users"); index.id("1"); //第一种:index.source("userName","zhangsan","age","18","gender","男"); //第二种: User user = new User(); user.setUserName("zhangsan"); user.setAge(18); user.setGender("男"); String jsonString = JSON.toJSONString(user); //要保存的数据 index.source(jsonString, XContentType.JSON); //执行操作 IndexResponse response = restHighLevelClient.index(index, ElasticsearchConfig.COMMON_OPTIONS); //提取有用的响应数据 System.out.println(response); } @Data class User{ private String userName; private String gender; private Integer age; }
控制台打印数据
测试数据存储到 es 成功
1.查看检索条件
@Test public void searchData() throws IOException { // 1.创建检索请求 SearchRequest request = new SearchRequest(); // 指定索引 request.indices("bank"); // 指定DSL,检索条件 // SearchSourceBuilder sourceBuilder 封装的条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 1.1构造检索条件 // sourceBuilder.query(); // sourceBuilder.from(); // sourceBuilder.size(); // sourceBuilder.aggregations(); sourceBuilder.query(QueryBuilders.matchQuery("address", "mill")); System.out.println(sourceBuilder.toString()); request.source(sourceBuilder); // 2.执行检索 SearchResponse response = restHighLevelClient.search(request, ElasticsearchConfig.COMMON_OPTIONS); // 3.分析结果 response System.out.println(response.toString()); }
查看检索结果
2.按照年龄值的分布和平均薪资进行聚合
@Test public void searchData() throws IOException { // 1.创建检索请求 SearchRequest request = new SearchRequest(); // 指定索引 request.indices("bank"); // 指定DSL,检索条件 // SearchSourceBuilder sourceBuilder 封装的条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 1.1构造检索条件 // sourceBuilder.query(); // sourceBuilder.from(); // sourceBuilder.size(); // sourceBuilder.aggregations(); sourceBuilder.query(QueryBuilders.matchQuery("address","mill")); // 1.2按照年龄值的分布进行聚合 TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10); sourceBuilder.aggregation(ageAgg); // 1.3计算平均薪资 AvgAggregationBuilder balance = AggregationBuilders.avg("balanceAvg").field("balance"); sourceBuilder.aggregation(balance); System.out.println("检索条件:" + sourceBuilder.toString()); request.source(sourceBuilder); // 2.执行检索 SearchResponse response = restHighLevelClient.search(request, ElasticsearchConfig.COMMON_OPTIONS); // 3.分析结果 response System.out.println(response.toString()); }
删除默认信息后,检索条件如下
{ "query": { "match": { "address": { "query": "mill" } } }, "aggregations": { "ageAgg": { "terms": { "field": "age", "size": 10 } }, "balanceAvg": { "avg": { "field": "balance" } } } }
复制检索条件到 Kibana 进行检索
整体测试
@RunWith(SpringRunner.class) @SpringBootTest public class GulimallSearchApplicationTests { @Resource private RestHighLevelClient restHighLevelClient; @Test public void searchData() throws IOException { // 1.创建检索请求 SearchRequest request = new SearchRequest(); // 指定索引 request.indices("bank"); // 指定DSL,检索条件 // SearchSourceBuilder sourceBuilder 封装的条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 1.1构造检索条件 // sourceBuilder.query(); // sourceBuilder.from(); // sourceBuilder.size(); // sourceBuilder.aggregations(); sourceBuilder.query(QueryBuilders.matchQuery("address","mill")); // 1.2按照年龄值的分布进行聚合 TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10); sourceBuilder.aggregation(ageAgg); // 1.3计算平均薪资 AvgAggregationBuilder balance = AggregationBuilders.avg("balanceAvg").field("balance"); sourceBuilder.aggregation(balance); System.out.println("检索条件:" + sourceBuilder.toString()); request.source(sourceBuilder); // 2.执行检索 SearchResponse response = restHighLevelClient.search(request, ElasticsearchConfig.COMMON_OPTIONS); // 3.分析结果 response System.out.println(response.toString()); // Map map = JSON.parseObject(searchResponse.toString(), Map.class); //3.1)、获取所有查到的数据 SearchHits hits = response.getHits(); SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { /** * "_index" : "bank", * "_type" : "account", * "_id" : "970", * "_score" : 5.4598455, * "_source" : { */ // hit.getIndex();hit.getType();hit.getId(); String string = hit.getSourceAsString(); Account account = JSON.parseObject(string, Account.class); System.out.println("account: " + account); } //3.2)、获取这次检索到的分析信息; Aggregations aggregations = response.getAggregations(); // for (Aggregation aggregation : aggregations.asList()) { // System.out.println("当前聚合:"+aggregation.getName()); // 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()); } /** * 测试存储数据到es * 更新也可以 * @throws IOException */ @Test public void indexData() throws IOException { IndexRequest index = new IndexRequest("users"); index.id("1"); //第一种:index.source("userName","zhangsan","age","18","gender","男"); //第二种: User user = new User(); user.setUserName("zhangsan"); user.setAge(18); user.setGender("男"); String jsonString = JSON.toJSONString(user); //要保存的数据 index.source(jsonString, XContentType.JSON); //执行操作 IndexResponse response = restHighLevelClient.index(index, ElasticsearchConfig.COMMON_OPTIONS); //提取有用的响应数据 System.out.println(response); } @Test public void contextLoads() { System.out.println(restHighLevelClient); } @Data class User{ private String userName; private String gender; private Integer age; } @Data @ToString static class Account { private int account_number; private int balance; private String firstname; private String lastname; private int age; private String gender; private String address; private String employer; private String email; private String city; private String state; } }
控制台输出
检索条件:{"query":{"match":{"address":{"query":"mill","operator":"OR","prefix_length":0,"max_expansions":50,"fuzzy_transpositions":true,"lenient":false,"zero_terms_query":"NONE","auto_generate_synonyms_phrase_query":true,"boost":1.0}}},"aggregations":{"ageAgg":{"terms":{"field":"age","size":10,"min_doc_count":1,"shard_min_doc_count":0,"show_term_doc_count_error":false,"order":[{"_count":"desc"},{"_key":"asc"}]}},"balanceAvg":{"avg":{"field":"balance"}}}}
{"took":1,"timed_out":false,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0},"hits":{"total":{"value":4,"relation":"eq"},"max_score":5.4598455,"hits":[{"_index":"bank","_type":"account","_id":"970","_score":5.4598455,"_source":{"account_number":970,"balance":19648,"firstname":"Forbes","lastname":"Wallace","age":28,"gender":"M","address":"990 Mill Road","employer":"Pheast","email":"forbeswallace@pheast.com","city":"Lopezo","state":"AK"}},{"_index":"bank","_type":"account","_id":"136","_score":5.4598455,"_source":{"account_number":136,"balance":45801,"firstname":"Winnie","lastname":"Holland","age":38,"gender":"M","address":"198 Mill Lane","employer":"Neteria","email":"winnieholland@neteria.com","city":"Urie","state":"IL"}},{"_index":"bank","_type":"account","_id":"345","_score":5.4598455,"_source":{"account_number":345,"balance":9812,"firstname":"Parker","lastname":"Hines","age":38,"gender":"M","address":"715 Mill Avenue","employer":"Baluba","email":"parkerhines@baluba.com","city":"Blackgum","state":"KY"}},{"_index":"bank","_type":"account","_id":"472","_score":5.4598455,"_source":{"account_number":472,"balance":25571,"firstname":"Lee","lastname":"Long","age":32,"gender":"F","address":"288 Mill Street","employer":"Comverges","email":"leelong@comverges.com","city":"Movico","state":"MT"}}]},"aggregations":{"lterms#ageAgg":{"doc_count_error_upper_bound":0,"sum_other_doc_count":0,"buckets":[{"key":38,"doc_count":2},{"key":28,"doc_count":1},{"key":32,"doc_count":1}]},"avg#balanceAvg":{"value":25208.0}}}
account: GulimallSearchApplicationTests.Account(account_number=970, balance=19648, firstname=Forbes, lastname=Wallace, age=28, gender=M, address=990 Mill Road, employer=Pheast, email=forbeswallace@pheast.com, city=Lopezo, state=AK)
account: GulimallSearchApplicationTests.Account(account_number=136, balance=45801, firstname=Winnie, lastname=Holland, age=38, gender=M, address=198 Mill Lane, employer=Neteria, email=winnieholland@neteria.com, city=Urie, state=IL)
account: GulimallSearchApplicationTests.Account(account_number=345, balance=9812, firstname=Parker, lastname=Hines, age=38, gender=M, address=715 Mill Avenue, employer=Baluba, email=parkerhines@baluba.com, city=Blackgum, state=KY)
account: GulimallSearchApplicationTests.Account(account_number=472, balance=25571, firstname=Lee, lastname=Long, age=32, gender=F, address=288 Mill Street, employer=Comverges, email=leelong@comverges.com, city=Movico, state=MT)
年龄:38==>2
年龄:28==>1
年龄:32==>1
平均薪资:25208.0
2023-05-12 22:43:00.325 INFO 17832 --- [ Thread-9] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
Process finished with exit code 0
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。