搜索引擎ElasticSearch7.x
# 搜索引擎ElasticSearch概述
全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当用户查询时根据建立的索引查找,类似于通过字典的检索字表查字的过程。
# 1、什么是ElasticSearch
ElasticSearch简称ES,是基于Apache Lucene构建的开源搜索引擎,是当前最流行的企业级搜索引擎。Lucene本身就可以被认为迄今为止性能最好的一款开源搜索引擎工具包,但是lucene的API相对复杂,需要深厚的搜索理论。很难集成到实际的应用中去。ES是采用java语言编写,提供了简单易用的RestFul API,开发者可以使用其简单的RestFul API,开发相关的搜索功能,从而避免lucene的复杂性。
# 2、ElasticSearch诞生
多年前,一个叫做Shay Banon的刚结婚不久的失业开发者,由于妻子要去伦敦学习厨师,他便跟着也去了。在他找工作的过程中,为了给妻子构建一个食谱的搜索引擎,他开始构建一个早期版本的Lucene。
直接基于Lucene工作会比较困难,所以Shay开始抽象Lucene代码以便Java程序员可以在应用中添加搜索功能。他发布了他的第一个开源项目,叫做“Compass”。
后来Shay找到一份工作,这份工作处在高性能和内存数据网格的分布式环境中,因此高性能的、实时的、分布式的搜索引擎也是理所当然需要的。然后他决定重写Compass库使其成为一个独立的服务叫做Elasticsearch。
第一个公开版本出现在2010年2月,在那之后Elasticsearch已经成为Github上最受欢迎的项目之一,代码贡献者超过300人。一家主营Elasticsearch的公司就此成立,他们一边提供商业支持一边开发新功能,不过Elasticsearch将永远开源且对所有人可用。
目前国内大厂几乎无一不用Elasticsearch,阿里,腾讯,京东,美团等等.....
# 安装ElasticSearch和Kibana
传统方式安装ES是一件比较费劲的事情,使用Docker能够非常轻松的安装ElasticSearch。而Kibana是一个针对Elasticsearch的开源分析及可视化平台,使用Kibana可以查询、查看并与存储在ES索引的数据进行交互操作,使用Kibana能执行高级的数据分析,并能以图表、表格和地图的形式查看数据。
# 1、使用Docker方式安装ElasticSearch
# 1.获取镜像
docker pull elasticsearch:7.14.0
# 2.运行es
docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.14.0
2
3
4
5
安装成功后用过端口9200进行访问,http://ip:9200/,如果出现如下JSON数据代表安装成功。

# 2、使用Docker方式安装Kibana
# 1.获取镜像
docker pull kibana:7.14.0
# 2.运行kibana
docker run -d --name kibana -p 5601:5601 kibana:7.14.0
# 3.进入容器
docker exec -it kibana bash
# 4.修改ElasticSearch地址
vi /usr/share/kibana/config/kibana.yml
# 5.测试:重启kibana容器,访问 http://ip地址:5601
docker restart kibana
2
3
4
5
6
7
8
9
10
11
12
13
14
# a、基于数据卷加载配置文件方式运行
- a.从容器复制kibana配置文件出来
- b.修改配置文件为对应ES服务器地址
- c.通过数据卷加载配置文件方式启动
docker run -d -v /root/kibana.yml:/usr/share/kibana/config/kibana.yml --name kibana -p 5601:5601 kibana:7.14.0
# b、测试kibana安装是否成功
访问 http://ip地址:5601,出现如下界面代表安装成功

# ES的核心概念与基本操作
和学习MySQL一样,学习MySQL我们需要理解库、表、字段等概念。那么学习ElasticSearch,我们也需要先学习其核心概念才能理解如何使用,主要有三个概念,如下所示:
- 索引 Index
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个商品数据的索引,一个订单数据的索引,还有一个用户数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字.
- 映射 Mapping
映射是定义一个文档和它所包含的字段如何被存储和索引的过程。在默认配置下,ES可以根据插入的数据自动地创建mapping,也可以手动创建mapping。 mapping中主要包括字段名、字段类型等
- 文档 Document
文档是索引中存储的一条条数据。一条文档是一个可被索引的最小单元。ES中的文档采用了轻量级的JSON格式数据来表示。
# 1、索引的基本操作
索引只能被删除不能被修改,所以索引的操作包含增删查,不包含修改索引操作。首先我们需要打开输入命令的控制台。

# 创建索引
PUT /products
PUT /orders
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
}
}
# 查看ES中的索引
GET /_cat/indices?v
# 删除索引
DELETE /products
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# a、添加索引
顶部会有警告信息,我们不用管

# b、查询索引

health:代表健康状态,图中有详细说明,red才是不能使用的,yellow和green都是可以正常使用的。
index开头是"."代表系统索引,剩下的才是我们创建的
pri代表主数据块,rep代表备用数据块,当主数据和备用数据都在同一台机器上,不能满足高可用,所以才提示yellow
接下来我们指定主数据块为1,备用数据块为0,发现已经health变成green了

# c、删除索引

# 2、映射的基本操作
我们再创建索引的时候,一般会将映射一同创建,索引与映射一般是不分家的。
# a、创建索引并指定映射
- 字符串类型: keyword关键字、关键词,而text一般是一段文本
- 数字类型:integer long
- 小数类型:float double
- 布尔类型:boolean
- 日期类型:date
PUT /products
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"title":{
"type": "keyword"
},
"price":{
"type": "double"
},
"created_at":{
"type": "date"
},
"description":{
"type": "text"
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# b、查看某个索引的映射信息
GET /products/_mapping
映射无法修改或删除,查看products索引的映射信息,返回数据如下:
{
"products" : {
"mappings" : {
"properties" : {
"created_at" : {
"type" : "date"
},
"description" : {
"type" : "text"
},
"price" : {
"type" : "double"
},
"title" : {
"type" : "keyword"
}
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ElasticSearch文档的基本操作
创建文档如果不指定id会默认创建,默认创建的id是UUID格式的
- 添加文档——手动指定_id
注意路径,路径最后跟上的要和json数据中的id保持一致。
POST /products/_doc/1
{
"id": 1,
"title": "松鼠",
"price": 0.5,
"created_at": "2022-10-10",
"description": "可爱的松鼠"
}
2
3
4
5
6
7
8
- 添加文档——自动生成文档id
POST /products/_doc/
{
"title":"iphone14",
"price":8999.99,
"created_at":"2021-09-15",
"description":"iPhone 13屏幕采用6.8英寸OLED屏幕"
}
2
3
4
5
6
7
# 1、查询文档
GET /products/_doc/1
返回的数据如下:
{
"_index" : "products",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"id" : 1,
"title" : "松鼠",
"price" : 0.5,
"created_at" : "2022-10-10",
"description" : "可爱的松鼠"
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2、更新文档
PUT /products/_doc/1
{
"title": "仓鼠"
}
2
3
4
更新后查询发现,映射只剩下title,之前的id、price等映射全都没有了
{
"_index" : "products",
"_type" : "_doc",
"_id" : "1",
"_version" : 5,
"_seq_no" : 5,
"_primary_term" : 1,
"found" : true,
"_source" : {
"title" : "仓鼠"
}
}
2
3
4
5
6
7
8
9
10
11
12
# 3、删除文档
DELETE /products/_doc/1
# 4、批量操作
批量索引两条文档
POST /products/_doc/_bulk
{"index":{"_id":"1"}}
{"title":"iphone14","price":8999.99,"created_at":"2021-09-15","description":"iPhone 13屏幕采用6.8英寸OLED屏幕"}
{"index":{"_id":"2"}}
{"title":"iphone15","price":8999.99,"created_at":"2021-09-15","description":"iPhone 15屏幕采用10.8英寸OLED屏幕"}
2
3
4
5
更新文档同时删除文档
POST /products/_doc/_bulk
{"update":{"_id":"1"}}
{"doc":{"title":"iphone17"}}
{"delete":{"_id":2}}
{"index":{}}
{"title":"iphone19","price":8999.99,"created_at":"2021-09-15","description":"iPhone 19屏幕采用61.8英寸OLED屏幕"}
2
3
4
5
6
批量时不会因为一个失败而全部失败,而是继续执行后续操作,在返回时按照执行的状态返回!
# ElasticSearch高级查询QueryDSL
搜索引擎ElasticSearch中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL,Query DSL是利用Rest API传递JSON格式的请求体(Request Body)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。
GET /索引名/_doc/_search {json格式请求体数据}
测试数据
# 1.创建索引 映射
PUT /products/
{
"mappings": {
"properties": {
"title":{
"type": "keyword"
},
"price":{
"type": "double"
},
"created_at":{
"type":"date"
},
"description":{
"type":"text"
}
}
}
}
# 2.测试数据
PUT /products/_doc/_bulk
{"index":{}}
{"title":"iphone12 pro","price":8999,"created_at":"2020-10-23","description":"iPhone 12 Pro采用超瓷晶面板和亚光质感玻璃背板,搭配不锈钢边框,有银色、石墨色、金色、海蓝色四种颜色。宽度:71.5毫米,高度:146.7毫米,厚度:7.4毫米,重量:187克"}
{"index":{}}
{"title":"iphone12","price":4999,"created_at":"2020-10-23","description":"iPhone 12 高度:146.7毫米;宽度:71.5毫米;厚度:7.4毫米;重量:162克(5.73盎司) [5] 。iPhone 12设计采用了离子玻璃,以及7000系列铝金属外壳。"}
{"index":{}}
{"title":"iphone13","price":6000,"created_at":"2021-09-15","description":"iPhone 13屏幕采用6.1英寸OLED屏幕;高度约146.7毫米,宽度约71.5毫米,厚度约7.65毫米,重量约173克。"}
{"index":{}}
{"title":"iphone13 pro","price":8999,"created_at":"2021-09-15","description":"iPhone 13Pro搭载A15 Bionic芯片,拥有四种配色,支持5G。有128G、256G、512G、1T可选,售价为999美元起。"}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 1、查询所有[match_all]
返回索引中的全部文档,第一行都是GET /products/_search,后面的案例将只展示json格式的数据,查询时第一行记得写。
GET /products/_search
{
"query": {
"match_all": {}
}
}
2
3
4
5
6
# 2、关键词查询[term]
- 通过使用term查询得知ES中默认使用分词器为`标准分词器(StandardAnalyzer),标准分词器对于英文单词分词,对于中文单字分词,所以说对中文的分词并不友好。
- 过使用term查询得知,在ES的MappingType中keyword, date, integer, long, double, boolean OR ip 这些类型不分词,只有text类型分词。
{
"query": {
"term": {
"price": {
"value": 4999
}
}
}
}
2
3
4
5
6
7
8
9
# 3、范围查询[range]
用来指定查询指定范围内的文档,gte代表大于,lte代表小于
{
"query": {
"range": {
"price": {
"gte": 1400,
"lte": 9999
}
}
}
}
2
3
4
5
6
7
8
9
10
# 4、前缀查询[prefix]
用来检索含有指定前缀的关键词的相关文档
{
"query": {
"prefix": {
"title": {
"value": "ipho"
}
}
}
}
2
3
4
5
6
7
8
9
# 5、通配符查询[wildcard]
通配符查询:?用来匹配一个任意字符,*用来匹配多个任意字符
{
"query": {
"wildcard": {
"description": {
"value": "iphon*"
}
}
}
}
2
3
4
5
6
7
8
9
# 6、多id查询[ids]
ids 关键字 : 值为数组类型,用来根据一组id获取多个对应的文档
{
"query": {
"ids": {
"values": ["verUq3wBOTjuBizqAegi","vurUq3wBOTjuBizqAegk"]
}
}
}
2
3
4
5
6
7
# 7、模糊查询[fuzzy]
用来模糊查询含有指定关键字的文档
{
"query": {
"fuzzy": {
"description": "iphooone"
}
}
}
2
3
4
5
6
7
- 搜索关键词长度为 2 不允许存在模糊
- 搜索关键词长度为3-5 允许一次模糊
- 搜索关键词长度大于5 允许最大2模糊
# 8、布尔查询[bool]
用来组合多个条件实现复杂查询.
must: 相当于&& 同时成立
should: 相当于|| 成立一个就行
must_not: 相当于! 不能满足任何一个
{
"query": {
"bool": {
"must": [
{"term": {
"price": {
"value": 4999
}
}}
]
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 9、多字段查询[multi_match]
GET /products/_search
{
"query": {
"multi_match": {
"query": "iphone13 毫",
"fields": ["title","description"]
}
}
}
注意: 字段类型分词,将查询条件分词之后进行查询改字段 如果该字段不分词就会将查询条件作为整体进行查询
2
3
4
5
6
7
8
9
10
# SpringBoot整合ElasticSearch
SpringBoot整合ElasticSearch核心是使用SpringDataES进行整合,整合方式非常简单,操作ES的客户端有两种。
# 1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2
3
4
# 2、配置客户端
配置客户端有两种方式,下面这种是官方文档所写的方式。
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("172.16.91.10:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
2
3
4
5
6
7
8
9
10
11
第二种的更为简便的配置文件配置方式:
spring:
elasticsearch:
uris: http://192.168.31.76:9200
2
3
# 客户端对象
- ElasticsearchOperations:始终使用面向对象方式操作 ES
- RestHighLevelClient:ElasticSearch官方提供的API,用Rest风格的JSON交互模式操作。
# ElasticsearchOperations方式
ElasticsearchOperations方式操作,就是常规的面向对象思想进行操作,使用起来非常简单。
# 1、核心概念回顾
索引:用来存放相似文档集合,类似MySQL中的数据库
映射:用来决定放入文档的每个字段以什么样方式录入到 ES 中 字段类型分词器,类似MySQL的表
文档:可以被索引最小单元 json 数据格式
# 2、类与文档映射
@Document(indexName = "products", createIndex = true)
public class Product {
@Id
private Integer id;
@Field(type = FieldType.Keyword)
private String title;
@Field(type = FieldType.Float)
private Double price;
@Field(type = FieldType.Text)
private String description;
//get set ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
解释说明
| 代码 | 含义 |
|---|---|
| @Document | 标注当前类是一个文档,indexName是索引名称,createIndex设置当索引不存在时自动创建 |
| @Id | 设置该字段为文档Id |
| @Field | 用来描述属性在ES中存储类型以及分词情况,type用来指定字段类型,analyzer指定该字段的分词器 |
| Keyword | 此类型不会进行分词 |
| Text | Text会进行分词,且可以通过analyzer指定该字段的分词器 |
# 3、保存/更新文档
class ApplicationTests {
@Autowired
private ElasticsearchOperations elasticsearchOperations;
/**
* 索引一条文档,也就是保存,同时save方法也可用于更新
* id存在则为更新,id不存在则为保存,不设置id统一都是保存
*/
@Test
public void testIndex() {
Product product = new Product();
product.setId(1);
product.setTitle("小米13");
product.setPrice(4899.6);
product.setDescription("Xiaomi 联合徕卡深度研发,带来更具质感的专业影像,让你忘情地创作,记录美好一刻");
elasticsearchOperations.save(product);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 4、删除文档
@Test
public void delete() {
Product product = new Product();
product.setId(1);
elasticsearchOperations.delete(product);
}
2
3
4
5
6
# 5、查询文档
@Test
public void testGet() {
Product product = elasticsearchOperations.get("1", Product.class);
System.out.println(product);
}
2
3
4
5
# 6、删除所有
@Test
public void testDeleteAll() {
elasticsearchOperations.delete(Query.findAll(), Product.class);
}
2
3
4
# 7、查询所有
@Test
public void testFindAll() {
SearchHits<Product> productSearchHits = elasticsearchOperations.search(Query.findAll(), Product.class);
productSearchHits.forEach(productSearchHit -> {
System.out.println("id: " + productSearchHit.getId());
System.out.println("score: " + productSearchHit.getScore());
Product product = productSearchHit.getContent();
System.out.println("product: " + product);
});
}
2
3
4
5
6
7
8
9
10
# RestHighLevelClient方式操作
Rest操作通常是在Kibana编写语句,然后将json格式的参数放入到java代码中。
# 1、创建索引映射
@Test
public void testCreateIndex() throws IOException {
CreateIndexRequest createIndexRequest = new CreateIndexRequest("fruit");
createIndexRequest.mapping("{\n" +
" \"properties\": {\n" +
" \"title\":{\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"price\":{\n" +
" \"type\": \"double\"\n" +
" },\n" +
" \"created_at\":{\n" +
" \"type\": \"date\"\n" +
" },\n" +
" \"description\":{\n" +
" \"type\": \"text\"\n" +
" }\n" +
" }\n" +
" }\n" , XContentType.JSON);
// restHighLevelClient.indices()代表操作索引,create代表创建
// 参数1是指定映射json结构,参数2是指定数据类型
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println("创建状态:"+createIndexResponse.isAcknowledged());
restHighLevelClient.close();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 2、索引文档
@Test
public void testIndex() throws IOException {
IndexRequest indexRequest = new IndexRequest("fruit");
indexRequest.source("{\n" +
" \"id\" : 1,\n" +
" \"title\" : \"蓝月亮\",\n" +
" \"price\" : 123.23,\n" +
" \"description\" : \"这个洗衣液非常不错哦!\"\n" +
" }",XContentType.JSON);
IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(index.status());
}
2
3
4
5
6
7
8
9
10
11
12
# a、更新文档
@Test
public void testUpdate() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("fruit","qJ0R9XwBD3J1IW494-Om");
updateRequest.doc("{\"title\":\"好月亮\"}",XContentType.JSON);
UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(update.status());
}
2
3
4
5
6
7
# b、删除文档
@Test
public void testDelete() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest("fruit","1");
DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(delete.status());
}
2
3
4
5
6
# c、基于 id 查询文档
@Test
public void testGet() throws IOException {
GetRequest getRequest = new GetRequest("fruit","1");
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
System.out.println(getResponse.getSourceAsString());
}
2
3
4
5
6
# d、查询所有
@Test
public void testSearch() throws IOException {
SearchRequest searchRequest = new SearchRequest("fruit");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchAllQuery());
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//System.out.println(searchResponse.getHits().getTotalHits().value);
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# e、综合查询
@Test
public void testSearch() throws IOException {
SearchRequest searchRequest = new SearchRequest("fruit");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder
.from(0)
.size(2)
.sort("price", SortOrder.DESC)
.fetchSource(new String[]{"title"},new String[]{})
.highlighter(new HighlightBuilder().field("description").requireFieldMatch(false).preTags("<span style='color:red;'>").postTags("</span>"))
.query(QueryBuilders.termQuery("description","错"));
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
System.out.println("总条数: "+searchResponse.getHits().getTotalHits().value);
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
highlightFields.forEach((k,v)-> System.out.println("key: "+k + " value: "+v.fragments()[0]));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# RestHighLevelClient之聚合查询
聚合查询是es除搜索功能外提供的针对es数据做统计分析的功能。聚合有助于根据搜索查询提供聚合数据。聚合查询是数据库中重要的功能特性,ES作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。它基于查询条件来对数据进行分桶、计算的方法。有点类似于 SQL 中的 group by 再加一些函数方法的操作。
注意:text类型是不支持聚合的。
# 1、测试数据
# 创建索引 index 和映射 mapping
PUT /fruit
{
"mappings": {
"properties": {
"title":{
"type": "keyword"
},
"price":{
"type":"double"
},
"description":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
# 放入测试数据
PUT /fruit/_bulk
{"index":{}}
{"title" : "面包","price" : 19.9,"description" : "小面包非常好吃"}
{"index":{}}
{"title" : "旺仔牛奶","price" : 29.9,"description" : "非常好喝"}
{"index":{}}
{"title" : "日本豆","price" : 19.9,"description" : "日本豆非常好吃"}
{"index":{}}
{"title" : "小馒头","price" : 19.9,"description" : "小馒头非常好吃"}
{"index":{}}
{"title" : "大辣片","price" : 39.9,"description" : "大辣片非常好吃"}
{"index":{}}
{"title" : "透心凉","price" : 9.9,"description" : "透心凉非常好喝"}
{"index":{}}
{"title" : "小浣熊","price" : 19.9,"description" : "童年的味道"}
{"index":{}}
{"title" : "海苔","price" : 19.9,"description" : "海的味道"}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 2、使用
# a、根据某个字段分组
GET /fruit/_search
{
"query": {
"term": {
"description": {
"value": "好吃"
}
}
},
"aggs": {
"price_group": {
"terms": {
"field": "price"
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# b、求最大值
GET /fruit/_search
{
"aggs": {
"price_max": {
"max": {
"field": "price"
}
}
}
}
2
3
4
5
6
7
8
9
10
# c、求最小值
GET /fruit/_search
{
"aggs": {
"price_min": {
"min": {
"field": "price"
}
}
}
}
2
3
4
5
6
7
8
9
10
# d、求平均值
GET /fruit/_search
{
"aggs": {
"price_agv": {
"avg": {
"field": "price"
}
}
}
}
2
3
4
5
6
7
8
9
10
# e、求和
GET /fruit/_search
{
"aggs": {
"price_sum": {
"sum": {
"field": "price"
}
}
}
}
2
3
4
5
6
7
8
9
10
# 3、整合应用
@Test
public void testAggsPrice() throws IOException {
SearchRequest searchRequest = new SearchRequest("fruit");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.aggregation(AggregationBuilders.terms("group_price").field("price"));
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Aggregations aggregations = searchResponse.getAggregations();
ParsedDoubleTerms terms = aggregations.get("group_price");
List<? extends Terms.Bucket> buckets = terms.getBuckets();
for (Terms.Bucket bucket : buckets) {
System.out.println(bucket.getKey() + ", "+ bucket.getDocCount());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
// 求不同名称的数量
@Test
public void testAggsTitle() throws IOException {
SearchRequest searchRequest = new SearchRequest("fruit");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.aggregation(AggregationBuilders.terms("group_title").field("title"));
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Aggregations aggregations = searchResponse.getAggregations();
ParsedStringTerms terms = aggregations.get("group_title");
List<? extends Terms.Bucket> buckets = terms.getBuckets();
for (Terms.Bucket bucket : buckets) {
System.out.println(bucket.getKey() + ", "+ bucket.getDocCount());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 求和
@Test
public void testAggsSum() throws IOException {
SearchRequest searchRequest = new SearchRequest("fruit");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.aggregation(AggregationBuilders.sum("sum_price").field("price"));
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
ParsedSum parsedSum = searchResponse.getAggregations().get("sum_price");
System.out.println(parsedSum.getValue());
}
2
3
4
5
6
7
8
9
10
11