# elasticsearch学习实战项目
**Repository Path**: satan1996/elasticsearch-learn
## Basic Information
- **Project Name**: elasticsearch学习实战项目
- **Description**: 个人基于elasticsearch8.x版本的学习记录包含最新的api操作文档和项目实战代码
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 1
- **Created**: 2024-02-19
- **Last Updated**: 2025-05-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Elasticsearch8学习笔记
## 一、安装elasticsearch和kibana
### 1.1.编写elasticsearch.yaml文件
```yaml
# 版本信息:2.2
services:
# Elasticsearch 服务配置
Elasticsearch:
# 镜像名称:elasticsearch:8.12.0
image: elasticsearch:8.12.0
# 容器名称:elasticsearch
container_name: elasticsearch
# 数据卷挂载
volumes:
- /home/docker/container/elasticsearch/data:/usr/share/elasticsearch/data
- /home/docker/container/elasticsearch/logs:/usr/share/elasticsearch/logs
- /home/docker/container/elasticsearch/config:/usr/share/elasticsearch/config
- /home/docker/container/elasticsearch/plugins:/usr/share/elasticsearch/plugins
# 端口映射:将本地的 9200 端口映射到容器的 9200 端口
ports:
- 9200:9200
# 环境变量设置
environment:
- node.name=single-node
- cluster.name=docker-cluster
- discovery.type=single-node
- bootstrap.memory_lock=true
- xpack.security.enabled=false
# 内存限制:1GB
mem_limit: 1g
# ulimits 设置:解锁内存锁定
ulimits:
memlock:
soft: -1
hard: -1
# 健康检查:使用 CMD-SHELL 执行 curl 命令检查 Elasticsearch 是否运行正常
healthcheck:
test:
[
"CMD-SHELL",
"curl -s http://localhost:9200 | grep -q 'elasticsearch'",
]
interval: 10s
timeout: 10s
retries: 120
# Kibana 服务配置
kibana:
# 依赖 Elasticsearch 服务
depends_on:
- elasticsearch
# 镜像名称:kibana:8.12.0
image: kibana:8.12.0
# 容器名称:kibana
container_name: kibana
# 数据卷挂载
volumes:
- /home/docker/container/kibana/data:/usr/share/kibana/data
- /home/docker/container/kibana/logs:/usr/share/kibana/logs
- /home/docker/container/kibana/config:/usr/share/kibana/config
- /home/docker/container/kibana/plugins:/usr/share/kibana/plugins
# 端口映射:将本地的 5601 端口映射到容器的 5601 端口
ports:
- 5601:5601
# 环境变量设置
environment:
- SERVERNAME=kibana
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
# 内存限制:1GB
mem_limit: 1g
# 健康检查:使用 CMD-SHELL 执行 curl 命令检查 Kibana 是否运行正常
healthcheck:
test:
[
"CMD-SHELL",
"curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'",
]
interval: 10s
timeout: 10s
retries: 120
```
### 1.2.安装ik分词器
[下载地址](https://github.com/medcl/elasticsearch-analysis-ik/releases)
解压后重命名放入以下位置
### 1.3.启动容器命令
```shell
docker compose -f elasticsearch.yaml up -d
```
### 1.4.启动效果(portainer控制台)

## 二、springboot整合elasticsearch8.x
### 2.1.springboot项目引入依赖
```xml
co.elastic.clients
elasticsearch-java
```
### 2.2.配置客户端
#### 2.2.1.application.yaml定义参数
```yaml
elasticsearch:
host: 192.168.120.130
port: 9200
```
#### 2.2.2.java代码中配置
```java
@Configuration
public class EsConfig {
@Value("${elasticsearch.host}")
private String hostname;
@Value("${elasticsearch.port}")
private int port;
/**
* 创建一个ElasticsearchClient实例,并将其注册为Bean。
* @return ElasticsearchClient实例
*/
@Bean
public ElasticsearchClient elasticsearchClient() {
// 创建一个HttpHost实例,用于指定Elasticsearch的主机和端口
HttpHost httpHost = HttpHost.create(hostname + ":" + port);
// 创建一个RestClient实例,用于与Elasticsearch进行通信
RestClient restClient = RestClient.builder(httpHost).build();
// 创建一个RestClientTransport实例,用于将RestClient与Elasticsearch连接起来
RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
// 创建一个ElasticsearchClient实例,并传入RestClientTransport对象
return new ElasticsearchClient(transport);
}
/**
* 创建一个ElasticsearchAsyncClient实例,并将其注册为Bean。
* @return ElasticsearchAsyncClient实例
*/
@Bean
public ElasticsearchAsyncClient elasticsearchAsyncClient() {
// 创建一个HttpHost实例,用于指定Elasticsearch的主机和端口
HttpHost httpHost = HttpHost.create(hostname + ":" + port);
// 创建一个RestClient实例,用于与Elasticsearch进行通信
RestClient restClient = RestClient.builder(httpHost).build();
// 创建一个RestClientTransport实例,用于将RestClient与Elasticsearch连接起来
RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
// 创建一个ElasticsearchAsyncClient实例,并传入RestClientTransport对象
return new ElasticsearchAsyncClient(transport);
}
}
```
### 2.3.代码中引入客户端
```java
@Autowired
private ElasticsearchClient client;
```
## 三、RestAPI
### 3.1.创建索引库
#### 3.1.1.方式一
- 编写some-index.json文件放到src/main/resources目录下
```json
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"name": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"address": {
"type": "keyword",
"index": false
},
"price": {
"type": "integer"
},
"score": {
"type": "integer"
},
"brand": {
"type": "keyword",
"copy_to": "all"
},
"city": {
"type": "keyword",
"copy_to": "all"
},
"starName": {
"type": "keyword"
},
"business": {
"type": "keyword"
},
"location": {
"type": "geo_point"
},
"pic": {
"type": "keyword",
"index": false
},
"all": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
```
- 创建文档类型实体类HotelDoc.java
```java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HotelDoc {
@Schema(description = "酒店id")
private Long id;
@Schema(description = "酒店名称")
private String name;
@Schema(description = "酒店地址")
private String address;
@Schema(description = "酒店价格")
private Integer price;
@Schema(description = "酒店评分")
private Integer score;
@Schema(description = "酒店品牌")
private String brand;
@Schema(description = "酒店城市")
private String city;
@Schema(description = "酒店星级")
private String starName;
@Schema(description = "酒店商圈")
private String business;
@Schema(description = "酒店经纬度")
private String location;
@Schema(description = "酒店图片")
private String pic;
// 排序时的 距离值
@Schema(description = "距离值")
private Object distance;
@Schema(description = "是否广告位")
private Boolean isAD;
@Schema(description = "建议词")
private List suggestion;
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
final String regex = "[\\u4e00-\\u9fa5]+";
final Pattern pattern = Pattern.compile(regex);
if (hotel.getBusiness().isEmpty()) {
this.suggestion = Arrays.asList(this.brand);
} else {
this.suggestion = new ArrayList<>();
this.suggestion.add(this.brand);
Matcher matcher = pattern.matcher(hotel.getBusiness());
while (matcher.find()) {
this.suggestion.add(matcher.group());
}
}
}
}
```
- 编写java代码
```java
/**
* 测试创建索引
* @throws IOException
*/
@Test
public void createIndex1() throws IOException {
// 创建一个InputStream对象,用于读取索引配置文件
InputStream input = new FileInputStream(new File("src/main/resources/some-index.json"));
// 创建一个CreateIndexRequest对象,用于指定索引名称和索引配置文件
CreateIndexRequest req = CreateIndexRequest.of(b -> b
.index("some-index")
.withJson(input)
);
// 调用Elasticsearch客户端的create方法创建索引,并获取返回结果
boolean created = client.indices().create(req).acknowledged();
// 根据创建结果输出相应的信息
if (created) {
System.out.println("创建成功");
} else {
System.out.println("创建失败");
}
}
```
#### 3.1.2.方式二
- 编写java类HotelIndexConsts.java
```java
public class HotelIndexConsts {
public static final String MAPPING_TEMPLATE = """
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"name": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"address": {
"type": "keyword",
"index": false
},
"price": {
"type": "integer"
},
"score": {
"type": "integer"
},
"brand": {
"type": "keyword",
"copy_to": "all"
},
"city": {
"type": "keyword",
"copy_to": "all"
},
"starName": {
"type": "keyword"
},
"business": {
"type": "keyword"
},
"location": {
"type": "geo_point"
},
"pic": {
"type": "keyword",
"index": false
},
"all": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
""";
}
```
- 编写java代码
```java
@Test
public void createIndex2() throws IOException {
//创建Reader
Reader reader = new StringReader(HotelIndexConsts.MAPPING_TEMPLATE);
CreateIndexRequest req = CreateIndexRequest.of(b -> b
.index("some-index")
.withJson(reader)
);
boolean created = client.indices().create(req).acknowledged();
if (created) {
System.out.println("创建成功");
} else {
System.out.println("创建失败");
}
}
```
### 3.2.删除索引库
```java
@Test
public void deleteIndex() throws IOException {
// 创建删除索引请求
DeleteIndexRequest request = DeleteIndexRequest.of(b -> b.index("some-index"));
// 发送删除索引请求并获取响应
DeleteIndexResponse response = client.indices().delete(request);
// 判断删除是否成功
if (response.acknowledged()) {
System.out.println("删除成功");
} else {
System.out.println("删除失败");
}
}
```
### 3.3.判断索引是否存在
```java
@Test
public void testExistsIndex() throws IOException {
// 创建ExistsRequest对象,指定要查询的索引库名称
ExistsRequest request = ExistsRequest.of(b -> b.index("hotel"));
// 发送查询请求,获取索引库是否存在
BooleanResponse response = client.indices().exists(request);
// 输出查询结果
System.out.println(response.value()?"索引存在":"索引不存在");
}
```
## 四、操作文档
### 4.1.新增文档
```java
@Test
public void testAddDocument() throws IOException {
// 1. 根据id查询酒店数据
Hotel hotel = hotelService.getById(61083L);
// 2. 将酒店数据转换为文档类型(HotelDoc)
HotelDoc hotelDoc = new HotelDoc(hotel);
// 3. 将HotelDoc对象转换为JSON格式字符串
String json = JSON.toJSONString(hotelDoc);
// 4. 准备索引请求对象
IndexResponse response = client.index(i -> i
.index("hotel") // 设置索引名称为"hotel"
.id(hotelDoc.getId().toString()) // 设置文档id
.document(hotelDoc) // 设置待索引的文档对象
);
log.info("已成功索引,版本号为:" + response.version());
}
```
### 4.2.查询文档
```java
@Test
public void getIndex() throws IOException {
// 1. 准备GetIndexRequest对象
GetIndexRequest request = GetIndexRequest.of(b -> b.index("hotel"));
// 2. 准备并发送获取请求,获取响应对象(GetResponse)
GetResponse getResponse = client.get(i -> i.index("hotel").id("61083"), HotelDoc.class);
// 3. 从响应对象中获取原始文档数据(HotelDoc类型)
HotelDoc hotelDoc = getResponse.source();
// 4. 打印获取到的HotelDoc对象内容
System.out.println(hotelDoc);
}
```
### 4.3.删除文档
```java
/**
* 测试方法,用于从酒店索引中删除指定文档。
*
* @throws IOException 如果发生输入输出错误,则抛出此异常
*/
@Test
void testDeleteDocument() throws IOException {
// 1. 准备 DeleteRequest 对象,设置要删除的文档所在索引为 "hotel",以及文档ID为 "36934"
DeleteResponse response = client.delete(i -> i.index("hotel").id("36934"));
// 2. 输出 DeleteResponse 对象中的结果状态
System.out.println(response.result());
}
```
### 4.4.修改文档
```java
@Test
public void testUpdateDocument() throws IOException {
// 1.根据id查询酒店数据
Hotel hotel = hotelService.getById(61083L);
// 2.转换为文档类型
HotelDoc hotelDoc = new HotelDoc(hotel);
hotelDoc.setPrice(1000);
// 1.准备Request对象
IndexResponse response = client.index(i -> i
.index("hotel")
.id("61083")
.document(hotelDoc)
);
System.out.println("response.result() = " + response.result());
}
```
### 4.5.批量导入文档
```java
@Test
void testBulkRequest() throws IOException {
// 从服务中查询并获取所有酒店数据
List hotels = hotelService.list();
// 初始化一个批量操作列表,用于存储待执行的Elasticsearch批量操作
List bulkOperations = new ArrayList<>();
// 对查询到的所有酒店进行遍历,并为每个酒店创建一个新的HotelDoc实例
hotels.stream().forEach(hotel -> {
HotelDoc hotelDoc = new HotelDoc(hotel);
// 创建一个批量操作,设置索引、文档内容(HotelDoc对象)以及文档ID
BulkOperation operation = BulkOperation.of(b -> b.index(c -> c.document(hotelDoc).id(hotelDoc.getId().toString())));
// 将创建好的批量操作添加到批量操作列表中
bulkOperations.add(operation);
});
// 使用Elasticsearch客户端执行批量请求,索引名称为"hotel",并将之前构建的所有批量操作应用于该请求
BulkResponse response = client.bulk(b -> b.index("hotel").operations(bulkOperations));
// 打印出批量请求响应中的每个项目结果
response.items().forEach(System.out::println);
}
```
## 五、查询文档
### 5.1.match_all查询
```java
@Test
void testMatchAll() throws IOException {
// 使用客户端执行对"hotel"索引的搜索,其中查询语句为匹配所有文档(Match All Query)
SearchResponse searchResponse = client.search(s -> s.index("hotel")
.query(a->a.matchAll(MatchAllQuery.of(b->b.queryName("")))), HotelDoc.class);
// 处理并解析搜索响应结果
handleResponse(searchResponse);
}
```
### 5.2.match查询
```java
@Test
void testMatch() throws IOException {
// 创建一个针对“hotel”索引的搜索请求,其中包含一个match查询条件
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.query(q -> q.match(m -> m.field("all").query("如家"))) // 设置查询字段为"all",查询关键词为"如家"
);
// 执行搜索并获取响应结果,类型为HotelDoc的SearchResponse对象
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索响应结果
handleResponse(searchResponse);
}
```
### 5.3.multiMatch多字段查询
```java
@Test
void testMultiMatch() throws IOException {
// 创建一个多字段匹配查询的搜索请求,索引为"hotel",查询字段包括"name"和"business",查询关键词为"如家"
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.query(q -> q.multiMatch(a->a.fields("name","business").query("如家"))));
// 执行搜索并获取包含HotelDoc类型结果的响应
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索响应内容
handleResponse(searchResponse);
}
```
### 5.4.精确查询
```java
@Test
void testTermMatchTest() throws IOException {
// 创建一个带有term匹配查询的搜索请求
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.query(q -> q.term(t -> t.field("city").value("上海")))
);
// 执行搜索并获取响应
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理响应
handleResponse(searchResponse);
}
```
### 5.5.范围查询
```java
/**
* 范围查询
*/
@Test
void testRange() throws IOException {
// 构造搜索请求
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.query(q -> q.range(r -> r.field("price").gte(JsonData.of(1000)).lte(JsonData.of(2000)))));
// 执行搜索
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索结果
handleResponse(searchResponse);
}
```
### 5.6.布尔查询
```java
/**
* 布尔查询
*/
@Test
void testBool() throws IOException {
// 构造搜索请求
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.query(q -> q.bool(bq -> bq.must(m -> m.term(t -> t.field("city").value("上海"))).filter(f -> f.range(r -> r.field("price").lte(JsonData.of(250))))))
);
// 执行搜索
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索结果
handleResponse(searchResponse);
}
```
### 5.7.排序、分页
```java
/**
* 进行分页查询的测试方法
*/
@Test
void testPageAndSort() throws IOException {
// 定义当前页码和每页显示的记录数
int page = 1, size = 50;
// 构建搜索请求,指定索引为"hotel",从((当前页码-1) * 每页大小)的位置开始获取数据
// 并设置每页获取size条记录,同时按照price字段降序排序
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.from((page - 1) * size)
.size(size).sort(s -> s.field(f -> f.field("price").order(SortOrder.Desc)))
);
// 使用Elasticsearch客户端执行搜索请求,返回HotelDoc类型的SearchResponse对象
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理并解析搜索响应结果
handleResponse(searchResponse);
}
```
### 5.8.高亮
```java
/**
* 高亮显示
*/
@Test
void testHighlight() throws IOException {
// 构建搜索请求
SearchRequest request = SearchRequest.of(b -> b
.index("hotel")
.query(q -> q.match(m -> m.field("all").query("如家")))
.highlight(Highlight.of(o -> o.requireFieldMatch(false).fields("name", t -> t.preTags("").postTags("")))));
// 执行搜索请求
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索结果
handleResponse(searchResponse);
}
```
### 5.9.地理位置(geo_distance)
- 查询半径范围内数据
```java
@Test
void testGeoDistance() throws IOException {
// 创建SearchRequest对象
SearchRequest request = SearchRequest.of(b -> b
.index("hotel") // 设置索引名称为"hotel"
.query(q -> q.geoDistance(g -> g.distance("100km").field("location").location(GeoLocation.of(a -> a.latlon(c -> c.lat(31.21).lon(121.5)))))) // 设置查询条件为距离"location"字段的值为100km的地理位置查询
);
// 执行查询
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理查询结果
handleResponse(searchResponse);
}
```
- 查询半径数据后排序
```java
/**
* 查询全部数据并根据地理位置排序
*/
@Test
void testGeoDistanceSort() throws IOException {
// 创建SearchRequest对象
SearchRequest request = SearchRequest.of(b -> b
.index("hotel") // 设置索引名称为"hotel"
.sort(s -> s.geoDistance(d -> d.field("location").location(l -> l.latlon(c -> c.lat(31.21).lon(121.5))).order(SortOrder.Asc).unit(DistanceUnit.Kilometers))) // 设置排序方式为根据地理位置排序,按照距离升序排列,单位为千米
);
// 执行搜索请求
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索结果
handleResponse(searchResponse);
}
```
### 5.10.算分函数查询
```java
@Test
public void testfunctionScore() throws IOException {
// 创建SearchRequest对象
SearchRequest request = SearchRequest.of(b -> b
// 设置索引名称为"hotel"
.index("hotel")
// 设置查询方式为算分函数查询,使用match查询匹配字段"all"中包含"外滩"的文档,设置一个过滤器,过滤出id为"434082"的文档,并设置权重为10.0,使用乘法方式计算得分
.query(q -> q.functionScore(f -> f.query(w -> w.match(m -> m.field("all").query("外滩"))).functions(m -> m.filter(s -> s.term(t -> t.field("id").value("434082"))).weight(10.0)).boostMode(FunctionBoostMode.Multiply)))// 设置查询方式为算分函数查询,使用match查询匹配字段"all"中包含"外滩"的文档,设置一个过滤器,过滤出id为"434082"的文档,并设置权重为10.0,使用乘法方式计算得分
);
// 执行搜索请求
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理搜索结果
handleResponse(searchResponse);
}
```
### 5.11.公共返回值处理方法
```java
/**
* 处理搜索响应
* @param response 搜索响应
*/
private void handleResponse(SearchResponse response) {
System.out.println("response = " + response);
// 4.解析响应
HitsMetadata hitsMetadata = response.hits();
// 4.1.获取总条数
long total = hitsMetadata.total().value();
System.out.println("共搜索到" + total + "条数据");
// 4.2.获取结果集
List> hits = hitsMetadata.hits();
hits.forEach(hit -> {
HotelDoc hotelDoc = hit.source();
Map> highlight = hit.highlight();
// 4.2.1.处理高亮显示
if (highlight != null && highlight.containsKey("name")) {
List highlightedNames = highlight.get("name");
System.out.println(highlightedNames.get(0));
// 合并原name和高亮片段(这里假设只取第一个高亮片段)
hotelDoc.setName(highlightedNames.get(0));
}
// 4.2.2.处理排序结果
List sort = hit.sort();
if (sort != null && sort.size() > 0) {
// 4.2.1.获取排序字段
FieldValue fieldValue = sort.get(1);
// 4.2.2.获取排序值
Object value = fieldValue.doubleValue();
hotelDoc.setDistance(value);
}
System.out.println(hotelDoc);
});
}
```
## 六、聚合搜索
### 6.1.bucket聚合
```java
/**
* bucket聚合结果排序
*/
@Test
public void testBucketAggregation() throws IOException {
SearchRequest request = SearchRequest.of(a -> a
.index("hotel").query(b -> b.range(c -> c.field("price").lte(JsonData.of(200)))).aggregations("brand_agg", d -> d.terms(t -> t.field("brand").size(20).order(NamedValue.of("_count", SortOrder.Asc)))).size(0)
);
SearchResponse searchResponse = client.search(request, HotelDoc.class);
handleAggResponse(searchResponse);
}
```
### 6.2.Metric聚合
```java
/**
* Metric聚合语法测试
*/
@Test
public void testMetricAggregation() throws IOException {
// 构建SearchRequest对象
SearchRequest request = SearchRequest.of(a -> a
.index("hotel").aggregations("brand_agg", d -> d.terms(e -> e.field("brand").size(20).order(NamedValue.of("score_agg.avg", SortOrder.Asc))).aggregations("score_agg", s -> s.stats(f -> f.field("score")))).size(0)
);
// 执行搜索请求
SearchResponse searchResponse = client.search(request, HotelDoc.class);
// 处理聚合响应
handleAggResponse(searchResponse);
}
```
### 6.3.处理聚合响应结果
```java
/**
* 处理聚合响应
*
* @param searchResponse 搜索响应
*/
private void handleAggResponse(SearchResponse searchResponse) {
// 打印搜索响应
// System.out.println(searchResponse);
// 获取聚合结果
Map aggregations = searchResponse.aggregations();
// 打印聚合结果
// System.out.println(aggregations);
// 获取品牌聚合结果
Aggregate brandAgg = aggregations.get("brand_agg");
// 获取品牌聚合结果的字符串聚合结果
StringTermsAggregate stermsAggregate = brandAgg.sterms();
// 获取品牌聚合结果的桶
Buckets buckets = stermsAggregate.buckets();
// 将桶转换为列表
List bucketList = buckets.array();
// 遍历桶列表
bucketList.forEach(bucket -> {
// 获取桶的key
String key = bucket.key().stringValue();
// 获取桶的docCount
long docCount = bucket.docCount();
// 获取桶的聚合结果
Map scoreAgg = bucket.aggregations();
if (scoreAgg.size()>0) {
// 获取桶的score聚合结果
Aggregate aggregate = scoreAgg.get("score_agg");
// 获取score聚合结果的统计聚合结果
StatsAggregate statsAggregate = aggregate.stats();
System.out.println("key:" + key + ", docCount:" + docCount + ", score_agg:" + statsAggregate);
}
// 打印全部参数
System.out.println("key:" + key + ", docCount:" + docCount);
});
}
```
## 七、自动补全
### 7.1.拼音分词器
[下载地址](https://github.com/medcl/elasticsearch-analysis-pinyin)
解压后重命名放入以下目录
### 7.2.创建索引
- 在HotelConsts.java中添加以下代码
```java
public static final String INDEX_TEMPLATE = """
{
"settings": {
"analysis": {
"analyzer": {
"text_anlyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
},
"completion_analyzer": {
"tokenizer": "keyword",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"id":{
"type": "keyword"
},
"name":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart",
"copy_to": "all"
},
"address":{
"type": "keyword",
"index": false
},
"price":{
"type": "integer"
},
"score":{
"type": "integer"
},
"brand":{
"type": "keyword",
"copy_to": "all"
},
"city":{
"type": "keyword"
},
"starName":{
"type": "keyword"
},
"business":{
"type": "keyword",
"copy_to": "all"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart"
},
"suggestion":{
"type": "completion",
"analyzer": "completion_analyzer"
}
}
}
}
""";
```
- 编写创建索引代码
```java
/**
* 创建索引测试方法,该方法读取HotelIndexConsts.INDEX_TEMPLATE中的模板内容,
* 并使用其创建一个名为"hotel2"的索引请求。
*
* @throws Exception 如果在创建索引过程中出现异常,则抛出异常
*/
@Test
public void createIndex() throws Exception {
// 创建一个从字符串读取器,读取预定义的索引模板内容
Reader reader = new StringReader(HotelIndexConsts.INDEX_TEMPLATE);
// 使用读取到的模板内容构建一个CreateIndexRequest对象,指定索引名称为"hotel2"
CreateIndexRequest request = CreateIndexRequest.of(a -> a.index("hotel2").withJson(reader));
// 调用Elasticsearch客户端的indices().create()方法发送创建索引请求
CreateIndexResponse response = client.indices().create(request);
// 输出响应结果,检查索引是否成功创建(acknowledged字段表示操作是否被集群中所有相关节点确认执行)
System.out.println(response.acknowledged());
}
```
- 执行批量导入数据到es
```java
//批量导入数据到es
@Test
void testBulkRequest() throws IOException {
// 批量查询酒店数据
List hotels = hotelService.list();
List bulkOperations = new ArrayList<>();
hotels.stream().forEach(hotel -> {
HotelDoc hotelDoc = new HotelDoc(hotel);
bulkOperations.add(BulkOperation.of(b -> b.index(c -> c.document(hotelDoc).id(hotelDoc.getId().toString()))));
});
BulkResponse response = client.bulk(b -> b.index("hotel2").operations(bulkOperations));
response.items().forEach(System.out::println);
}
```
### 7.3.自动补全
```java
/**
* 自动补全测试
*/
@Test
void testSuggest() throws IOException {
// 创建搜索请求
SearchRequest searchRequest = SearchRequest.of(a ->
a.index("hotel2").suggest(b -> b.suggesters("my_suggest", c -> c.text("h").completion(d -> d.field("suggestion").skipDuplicates(true).size(10))))
);
// 执行搜索请求
SearchResponse searchResponse = client.search(searchRequest, HotelDoc.class);
// 处理搜索响应
handleResponse(searchResponse);
}
```
### 7.4.处理响应结果
```java
/**
* 处理响应结果
*
* @param searchResponse 搜索响应结果
*/
private void handleResponse(SearchResponse searchResponse) {
// 获取建议结果
Map>> suggestions = searchResponse.suggest();
// 获取指定建议结果
Suggestion suggestion = suggestions.get("my_suggest").getFirst();
// 获取建议结果的选项列表
List> options = suggestion.completion().options();
// 遍历选项列表并打印选项文本
options.forEach(option -> {
System.out.println(option.text());
});
}
```
## 八、实践项目地址
[码云](https://gitee.com/satan1996/elasticsearch-learn.git)
[本地knife4j文档地址](http://localhost:8080/doc.html)
