【ElasticSearch(十三)进阶】SpringBoot整合ElasticSearch7.14.0 基本教程
一、接入方式
1.端口9300:TCP
1)spring-data-elasticsearch:transport-api.jar:
springboot版本不同,transport-api.jar 不同,不能适配es版本
7.x 已经不建议使用,8以后就要废弃
2.端口9200:HTTP
1)JestClient
非官方,更新慢
2)RestTemplate
模拟发HTTP请求,ES很多操作需要自己封装,麻烦
3)HttpClient
同上
4)Elasticsearch-Rest-Client(我们选择的)
官方RestClient,封装了ES操作,API层次分明,上手简单
(使用指南)
https://www.elastic.co/guide/en/elasticsearch/client/index.html
二、搭建项目
我使用的版本是ElasticSearch 7.14,配合SpringBoot搭建项目。
三、导入Maven
由于父依赖spring-boot-dependencies
导入的elasticsearch
依赖版本是7.12.1
的,所以这里我们另外在<properties>
标签下定义下elasticsearch
版本是7.14
的。
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.14.0</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 导入es的rest-high-level-client和elasticsearch server-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.14.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.14.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
四、建立Config
建立config文件夹,创建类ElasticSearchConfig ,作为我们的配置文件。
给容器中注入一个RestHighLevelClient
package com.musecho.gulimallsearch.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticSearchConfig {
/**
* 创建单例模式的RequestOptions,使得所有请求共用
*/
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();
}
@Bean
public RestHighLevelClient client() {
RestClientBuilder builder=RestClient.builder(new HttpHost("localhost", 9200, "http"));
RestHighLevelClient client = new RestHighLevelClient(builder);
return client;
}
}
五、测试:保存数据
保存一个user信息,使用index()
package com.musecho.gulimallsearch;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.musecho.gulimallsearch.config.ElasticSearchConfig;
import com.musecho.gulimallsearch.pojo.User;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
@SpringBootTest
public class GulimallSearchApplicationTests {
@Autowired
private RestHighLevelClient client;
/**
* jackson的objectMapper
*/
ObjectMapper objectMapper=new ObjectMapper();
/**
* 测试RestHighLevelClient注入是否成功
*/
@Test
public void contextLoads() {
System.out.println(client);
}
/**
* 保存用户数据
*/
@Test
public void indexData() throws IOException {
//指定索引和id
IndexRequest request=new IndexRequest("users");
request.id("1");
//数据转为json格式
User user=new User("zhengkeke","女",9);
String userString=objectMapper.writeValueAsString(user);
request.source(userString, XContentType.JSON);
//执行保存操作
IndexResponse indexResponse=client.index(request, ElasticSearchConfig.COMMON_OPTIONS);
System.out.println(indexResponse);
}
}
通过Kinaba查询是否添加成功:
GET /users/_search
返回结果如下, 保存数据成功
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "users",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "zhengkeke",
"sex" : "女",
"age" : 9
}
}
]
}
}
六、测试:复杂检索数据
现在用java结合ES实现这个查询
#搜索 address中包含mill的所有人的年龄分布以及平均年龄
GET /bank/_search
{
"query":{
"match":{
"address":"mill"
}
},
"aggs":{
"ageAgg":{
"terms":{
"field": "age",
"size": 10
}
},
"ageAvg":{
"avg":{
"field":"age"
}
}
}
}
类GulimallSearchApplicationTests中添加方法searchData()
/**
* 复杂检索数据
*/
@Test
public void searchData() throws IOException {
//1.创建检索请求
SearchRequest searchRequest = new SearchRequest();
//指定索引
searchRequest.indices("bank");
//指定DSL,检索条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//1.1 构造检索条件
//address中包含mill
searchSourceBuilder.query(QueryBuilders.matchQuery("address", "mill"));
//按照前10种年龄分布进行聚合
TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
searchSourceBuilder.aggregation(ageAgg);
//求所有人年龄的平均值
AvgAggregationBuilder ageAvg = AggregationBuilders.avg("ageAvg").field("age");
searchSourceBuilder.aggregation(ageAvg);
System.out.println(searchSourceBuilder);
searchRequest.source(searchSourceBuilder);
//2.执行检索
SearchResponse searchResponse = client.search(searchRequest, ElasticSearchConfig.COMMON_OPTIONS);
//3.分析结果
//3.1 查看查询结果
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : searchHits) {
System.out.println(hit);
}
//3.2 查看聚合结果
Aggregations aggs = searchResponse.getAggregations();
Terms ageAgg2 = aggs.get("ageAgg");
for (Terms.Bucket bucket : ageAgg2.getBuckets()) {
System.out.println("年龄:" + bucket.getKeyAsString()+"==> 人数:"+bucket.getDocCount());
}
System.out.println();
Avg ageAvg2 = aggs.get("ageAvg");
System.out.println("平均年龄:" + ageAvg2.getValue());
}
控制台打印结果:
//请求条件
{
"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
}
}
},
"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"
}
]
}
},
"ageAvg": {
"avg": {
"field": "age"
}
}
}
}
//查询结果
{
"_index" : "bank",
"_type" : "account",
"_id" : "970",
"_score" : 5.4032025,
"_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.4032025,
"_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.4032025,
"_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.4032025,
"_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"
}
}
//聚合结果
年龄:38==> 人数:2
年龄:28==> 人数:1
年龄:32==> 人数:1
平均年龄:34.0