Elasticsearch 常用Api

mapping映射属性

官方文档链接

mapping用于约束es中索引库中的文档,定义文档中的字段如何存储和索引的过程。

字段参数配置

是否创建索引

表示字段是否需要用于搜索。index:是否创建索引,默认为true。

分词器

analyzer:使用哪个分词器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"mappings": {
"properties": {
"name": {
"type": "text",
"fields": {
"length": {
"type": "integer",
"analyzer": "standard"
}
}
}
}
}
}

字段数据类型

type:字段数据类型。每一个类型都可以作为数组使用。

字符串

type 描述
text 可分词的文本
keyword 精确值,不可分词,例如:品牌、链接、国家、ip地址等,存储和查询时效率较高

数值

type 描述
long 带符号的 64 位整数,最小值为 -2⁶³,最大值为 2⁶³-1
integer 带符号的 32 位整数,最小值为 -2³¹,最大值为 2³¹-1
short 带符号的 16 位整数,最小值为 -32,768,最大值为 32,767
byte 带符号的 8 位整数,最小值为 -128,最大值为 127
double 双精度 64 位 IEEE 754 浮点数,限制为有限值。
float 单精度 32 位 IEEE 754 浮点数,限制为有限值。
half_float 半精度 16 位 IEEE 754 浮点数,限制为有限值。
scaled_float 一个浮点数,由一个固定的 double 比例因子缩放的 long 支持。通过比例因子将浮点数转换为整数存储,节省磁盘空间,适合精度要求不高的场景。
unsigned_long 无符号 64 位整数,最小值为 0,最大值为 2⁶⁴-1。

布尔

boolean:true / false。

日期

type 描述
date 支持指定日期格式类型,例如常用的 yyyy-MM-dd HH:mm:ssyyyy-MM-dd等。默认的日期格式为: `strict_date_optional_time
date_nanos date 数据类型的补充。date_nanos 数据类型以纳秒分辨率存储日期,这限制了其日期范围大约从 1970 年到 2262 年,因为日期仍然存储为自纪元以来的纳秒数的长整型。对纳秒的查询在内部会转换为对此长整型表示的范围查询,聚合和存储字段的结果会根据与该字段关联的日期格式转换回字符串。

使用||作为分隔符来让日期同时支持多种格式,会轮流尝试每一种格式,直到与之相匹配,第一种格式会被用来把毫秒值转换回字符串。

1
2
3
4
5
6
7
8
9
10
{
"mappings": {
"properties": {
"my_date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}

JSON没有专门的日期(date)类型, 在ES中date类型可以表现为:

  • 字符串格式的日期, 比如: 2015-01-01, 2015/01/01 12:10:30

  • long类型的自 epoch (1970-1-1) 以来的毫秒数

  • integer类型的自 epoch (1970-1-1) 以来的秒数(时间戳,timestamp)

在ES内部,日期被转换为UTC格式(如果指定了时区),并存储为long类型的自 epoch (1970-1-1) 以来的毫秒数。date总是被显示为字符串格式,即使他们在JSON文档中是long类型。

binary

二进制类型,值以Base64编码字符串的形式存储。_source默认不会存储该类型的值,也不可搜索;如果需要实际的存储,请设置 store属性为true,默认是false。

  • store:是否应存储字段值并可从 _source 字段单独检索。
  • doc_values:是否应以列式方式将字段存储在磁盘上,以便后续用于排序、聚合或脚本。
1
2
3
4
5
6
7
8
9
10
11
{
"mappings": {
"properties": {
"my_blob": {
"type": "binary",
"doc_values": false,
"store": false
}
}
}
}

IP

ip类型的字段只能存储ipv4或ipv6地址。

Array

ES没有独立的数组类型,默认任何字段都可以包含一个或多个值,但数组中的值必须是同一种类型,例如:[“hello”,”world”]、[1,2,3]…。数组可以包含null值,它会被配置的 null_value 替代 或者 直接被忽略。空数组 [] 会被视为没有值的字段。

1
2
3
4
5
6
7
8
9
10
{
"mappings": {
"properties": {
"my_array": {
"type": "keyword",
"null_value": "NULL"
}
}
}
}

对象

Object 是type的默认值。假设定义name字段为对象类型,不需要显式定义type的属性值。

JSON对象示例:

1
2
3
4
5
6
7
8
9
10
11
{
"region": "US",
"manager": {
"age": 30,
"name": {
"first": "John",
"last": "Smith"
}
}
}

在ES内部,下方示例的json对象会被作为文档,此文档被索引为简单的键值对扁平列表

1
2
3
4
5
6
{
"region": "US",
"manager.age": 30,
"manager.name.first": "John",
"manager.name.last": "Smith"
}

mapping声明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"mappings": {
"properties": {
"region": { "type": "keyword" },
"manager": {
"properties": {
"age": { "type": "integer" },
"name": {
"properties": {
"first": { "type": "text" },
"last": { "type": "text" }
}
}
}
}
}
}
}

那如果对象里面嵌套数组呢?比如下面这个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"group": "fans",
"user": [
{
"first": "张三",
"last": "ZhangSan"
},
{
"first": "李四",
"last": "Lisi"
}
]
}

数组类型怎么扁平化?上面的文档会被ES平铺成这样:

1
2
3
4
5
{
"group" : "fans",
"user.first" : [ "张三", "李四" ],
"user.last" : [ "ZhangSan", "Lisi" ]
}

如果将查询条件设置成 user.first=张三 and user.last=Lisi会被查询出来吗?会!

1
2
3
4
5
6
7
8
9
10
{
"query": {
"bool": {
"must": [
{ "match": { "user.first": "张三" }},
{ "match": { "user.last": "Lisi" }}
]
}
}
}

查询结果并不符合预期,可以通过显式声明类型为nested来解决。

nested

nested嵌套类型是object中的一个特例,可以让array类型的Object array独立索引和查询。

ES没有内部对象的概念,因此,ES会把具有层次结构的对象平铺成简单的Key-Values(键和值列表)。

mapping声明定义示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"mappings": {
"properties": {
"group": { "type": "keyword" },
"user": {
"type": "nested",
"properties": {
"first": { "type": "text" },
"last": { "type": "text" }
}
}
}
}
}

token_count

存储字符串值,分析并统计词的个数,实际是integer类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"mappings": {
"properties": {
"name": {
"type": "text",
"fields": {
"length": {
"type": "token_count",
"analyzer": "standard"
}
}
}
}
}
}

向文档中插入两条数据:

1
2
{ "name": "John Smith" }
{ "name": "Rachel Alice Williams" }

查询 name 字段中,分词的个数为3的文档:

1
2
3
4
5
6
7
{
"query": {
"term": {
"name.length": 3
}
}
}

range

type 描述
integer_range 带符号 32 位整数的范围,最小值为 -231,最大值为 231-1
float_range 单精度 32 位 IEEE 754 浮点值的范围。
long_range 带符号 64 位整数的范围,最小值为 -263,最大值为 263-1
double_range 双精度 64 位 IEEE 754 浮点值的范围。
date_range date 值的范围。日期范围通过 format 映射参数支持各种日期格式。无论使用哪种格式,日期值都会被解析为自 Unix 纪元以来以 UTC 毫秒为单位的无符号 64 位整数。不支持包含 now 日期数学 表达式的值。
ip_range 支持 IPv4 或 IPv6(或混合)地址的 IP 值范围。

应用示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /my_range
{
"mappings": {
"properties": {
"expected_attendees": {
"type": "integer_range"
},
"time_frame": {
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}

插入一条数据:expected_attendees 取值范围为10 ~ 20, 日期time_frame的范围是2025-01-01 23:59:59 ~ 2025-05-05

1
2
3
4
5
6
7
8
9
10
11
PUT /my_range/_doc/1?refresh
{
"expected_attendees" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2025-01-01 23:59:59",
"lte" : "2025-05-05"
}
}

范围查询

  • relation:范围查询支持 withincontains intersects(默认)。
1
2
3
4
5
6
7
8
9
10
11
12
GET /my_range/_search
{
"query" : {
"range" : {
"time_frame" : {
"gte" : "2025-01-02 23:59:59",
"lte" : "2025-04-01 08:00:00",
"relation" : "within"
}
}
}
}

索引库CURD

ES中通过restful请求操作索引库、文档。请求内容用DSL(Domain Specific Language)语句来表示。

查看全部索引

1
GET _cat/indices?v
字段 描述
health 索引的健康状态,这里是 “yellow”。Elasticsearch 索引的健康状态有三种:green(绿色,健康),yellow(黄色,部分健康),red(红色,不健康)。”yellow” 状态表示索引的某些分片处于未分配状态,但主分片是可用的。
status 索引的状态,这里是 “open”。这表示索引处于打开状态,可以进行读取和写入操作。
index 索引的名称,这里是 “nginx-access-log-2023.09.13”。
uuid 索引的唯一标识符。
pri 主分片(primary shard)的数量,这里是 1 个主分片。
rep 副本分片(replica shard)的数量,这里也是 1 个副本分片。
docs.count 索引中文档的总数,这里是 20。
docs.deleted 索引中已删除的文档数量,这里是 0。
store.size 索引的存储大小,这里是 34.1KB。
pri.store.size 主分片的存储大小,这里也是 34.1KB。

创建索引库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT  /<index>
{
"mappings": {
"properties":{
"字段名1": {
"type": "text", // 可分词的
"analyzer":"ik_smart" // 指定ik_smart分词器
},
"字段名2": {
"type": "keyword", // 精确值,不可分词的
"index": "false"
}
}
}
}

查询索引库

1
GET /<index>

删除索引库

1
DELETE /<index>

修改索引库

索引库和mapping一但创建无法修改,支持添加新的字段,语法如下:

1
2
3
4
5
6
PUT /<index>/_mapping
{
"properties": {
"新字段名": { ... }
}
}

文档CRUD

新增

如果不指定文档ID,ES会随机生成一个。

1
2
3
4
5
6
7
8
POST /<index>/_doc/文档ID
{
"字段1": "值",
"字段2": {
"子字段1":"值",
"子字段2": 0
}
}

查询

1
GET /<index>/_doc/文档ID

删除

1
DELETE /<index>/_doc/文档ID

修改

全量修改,先删除旧文档,再添加新文档。

1
2
3
4
5
PUT /<index>/_doc/文档ID
{
"字段1": "v1",
"字段2": "v2",
}

局部修改,修改指定字段。

1
2
3
4
5
6
PUT /<index>/_doc/文档ID
{
"doc": {
"字段1": "v2"
}
}

DSL查询文档

官方文档链接。ES基于JSON的DSL(Domain Specific Language)来定义查询语法。

查询基本语法结构

_source:用于设置查询结果返回什么字段,类似Select语句后面指定字段。

1
2
3
4
5
6
7
8
9
GET /<index>/_search
{
"from" : 0, // 返回搜索结果的开始位置
"size" : 10, // 分页大小,一次返回多少数据
"_source" :[ ...需要返回的字段数组... ],
"query" : { ...query子句... },
"aggs" : { ..aggs子句.. },
"sort" : { ..sort子句.. }
}

支持一次搜索多个索引,多个索引使用逗号分隔:

1
GET /<index1>,<index2>/_search

按前缀匹配索引名:

1
GET /<index>*/_search

执行查询语句,返回的JSON结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

"took" : 5, // 查询消耗时间,单位毫秒
"timed_out" : false, // 查询是否超时
"_shards" : {
// 本次查询参与的ES分片信息,查询中参与分片的总数,以及这些分片成功了多少个失败了多少个
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : { // hits字段是搜索命中的结果
"total" : { // 匹配到的文档总数
"value" : 1, // 找到1个文档
"relation" : "eq"
},
"max_score" : 1.0, // 匹配到的最大分值
"hits" : [
// 这里就是我们具体的搜索结果,是一个JSON数组
]
}
}

查询子句:

  • query:主要用来编写类似SQL的Where语句,支持布尔查询(and/or)、IN、全文搜索、模糊匹配、范围查询(大于小于)。
  • aggs:主要用来编写统计分析语句,类似SQL的group by语句
  • sort:用来设置排序条件,类似SQL的order by语句
  • 分页查询:主要通过from和size参数设置,类似MYSQL 的limit和offset语句

查询全部数据

查询所有数据,从第0条数据开始,一次返回20条数据。

1
2
3
4
5
6
7
8
GET /<index>/_search
{
"from": 0,
"size": 20,
"query": {
"match_all": {}
}
}

bool组合查询

如果需要编写类似SQL的Where语句,组合多个字段的查询条件,可以使用bool语句,类似SQL中的and (且)、or (或)。

语法结构:

  • must:类似SQL中的and,必须匹配条件。
  • must_not:跟must相反,必须不匹配条件。
  • should:类似SQL中or,只要匹配其中一个条件即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /<index>/_search
{
"query": {
"bool": {
"must": [
{匹配条件1},
{匹配条件2},
...可以有N个匹配条件...
],
"must_not": [],
"should": []
}
}
}

综合应用示例

1
select * from order_v2 where (order_no='2025051112091209991' and (shop_id>=10 and shop_id<=200)) or tag in (1,2)

等价SQL的DSL的查询方式:

1
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
GET /my_index/_search
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"term": {
"order_no": "2025051112091209991"
}
},
{
"range": {
"shop_id": {
"gte": 10,
"lte": 200
}
}
}
]
}
},
{
"terms": {
"tag": [1, 2]
}
}
]
}
}
}

单条件查询

通过match实现全文搜索,将内容分词后再搜索;

例1,搜索 message 包含 34

1
2
3
4
5
6
7
8
9
POST /<index>/_search
{
"query": {
"match": {
"message": "34"
}
},
"size": 1000
}

例2,搜索 message 包含 34 或者 包含 36

1
2
3
4
5
6
7
8
9
POST /<index>/_search
{
"query": {
"match": {
"message": "34 36"
}
},
"size": 1000
}

例3,搜索 message 包含 34 并且 包含 36

1
2
3
4
5
6
7
8
9
10
11
12
POST /<index>/_search
{
"query": {
"match": {
"message": {
"query": "34 36",
"operator": "and"
}
}
},
"size": 1000
}

例4,搜索 message 包含 34 36 15 22 中超过 50% 以上比例的

1
2
3
4
5
6
7
8
9
10
11
12
POST /<index>/_search
{
"query": {
"match": {
"message": {
"query": "34 36 15 22",
"minimum_should_match": "50%"
}
}
},
"size": 1000
}

例5,使用sort对查询数据排序,并按照size返回查询的数量(desc:降序 / asc:升序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /<index>/_search
{
"query": {
"match": {
"title": "python elasticsearch"
}
},
"sort": {
"postDate": {
"order": "desc"
}
},
"size": 2
}

多条件查询

and条件使用 mustor 条件使用 should

例1,搜索Math学科并且发布时间是指定日期的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET /<index>/_search
{
"query": {
"bool": {
"must": [
{
"match": { "class": "Math" }
},
{
"match": { "published_date": "2023-01-17T20:53:42+00:00" }
}
]
}
}
}

例2,搜索Math学科或者发布时间是指定日期的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"query": {
"bool": {
"should": [
{
"match": { "class": "Math" }
},
{
"match": { "published_date": "2023-01-17T20:53:42+00:00" }
}
]
}
}
}

例3,多个条件中,至少满足2个以上。搜索包含Math学科、指定发布日期、题型是选择题的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"query": {
"bool": {
"should": [
{
"match": { "class": "Math" }
},
{
"match": { "published_date": "2023-01-17T20:53:42+00:00" }
},
{
"match": { "question_type": "choice" }
}
],
"minimum_should_match": 2
}
}
}

例4,同时使用包含和不包含的条件。搜索Math学科,但不是选择题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"query": {
"bool": {
"must": [
{
"match": { "class": "Math" }
}
],
"must_not": [
{
"match": { "question_type": "choice" }
}
]
}
},
"size": 100
}

高亮显示查询结果

  • pre_tags:自定义标签的前半部分的html标签、属性及样式。默认标签为<em>

  • post_tags:自定义标签的后半部分样式。默认为:</em>

示例:

  • 数据部分:中国是世界上人口最多的国家

  • 搜索词:中国

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET /<index>/_search
{
"query": {
"match": {
"remark": "中国"
}
},
"highlight": {
"pre_tags": "<b class='key' style='color:red'>",
"post_tags": "</b>",
"fields": {
"remark": {}
}
}
}

搜索结果:

1
2
3
4
5
6
7
8
9
10
{
"hits": [
// 略
],
"highlight": {
"remark": [
"<b class='key' style='color:red'>中</b><b class='key' style='color:red'>国</b>"
]
}
}

聚合查询

聚合查询,类似在SQL中的group by

统计分析主要分为分组组内聚合两个步骤。组内聚合,类似在SQL中 select 编写的avgsumcount统计函数;

  • 对查询的数据首先进行一轮分组,可以设置分组条件,例如:新生入学,把所有的学生按专业分班,这个分班的过程就是对学生进行了分组。
  • 组内聚合,就是对组内的数据进行统计,例如:计算总数、求平均值等等,接上面的例子,学生都按专业分班了,那么就可以统计每个班的学生总数, 这个统计每个班学生总数的计算,就是组内聚合计算。

“桶”的概念

满足特定条件的文档的集合,叫做桶。就是一组数据的集合,对数据分组后,得到一组组的数据,就是一个个的桶。

桶等同于组,分桶和分组是一个意思,ES使用桶代表一组相同特征的数据。

桶聚合:指的就是先对数据进行分组,ES支持多种分组条件,例如:支持类似SQL的group by根据字段分组,当然ES比SQL更强大,支持更多的分组条件,以满足各种统计需求。

“指标”的概念

指标:对文档进行统计计算方式,又叫指标聚合。常用的指标有:SUMCOUNTMAX等统计函数。

桶内聚合:先对数据进行分组(分桶),然后对每一个桶内的数据进行指标聚合。

查询语法

  • aggregations - 代表聚合查询语句,可以简写为aggs
  • - 代表一个聚合计算的名字,可以随意命名,因为ES支持一次进行多次统计分析查询,后面需要通过这个名字在查询结果中找到我们想要的计算结果。
  • - 聚合类型,代表我们想要怎么统计数据,主要有两大类聚合类型,桶聚合和指标聚合,这两类聚合又包括多种聚合类型,例如:指标聚合:sumavg, 桶聚合:termsDate histogram等等。
  • - 聚合类型的参数,选择不同的聚合类型,有不同的参数。
  • aggregation_name_2 - 代表其他聚合计算的名字,意思就是可以一次进行多种类型的统计。
1
2
3
4
5
6
7
8
9
10
11
{
"aggregations" : {
"<aggregation_name>" : {
"<aggregation_type>" : {
<aggregation_body>
}
[,"aggregations" : { [<sub_aggregation>]+ } ]? // 嵌套聚合查询,支持多层嵌套
}
[,"<aggregation_name_2>" : { ... } ]* // 多个聚合查询,每个聚合查询取不同的名字
}
}

应用示例

假设存在一个order索引,存储了每一笔汽车销售订单,里面包含了汽车颜色字段color。

现需统计每一种汽车颜色的销量。

在SQL中:

1
select count(color) from order group by color

在ES中:

  • size:设置size=0的意思就是,仅返回聚合查询结果,不返回普通query查询结果。
  • aggs:聚合查询语句的简写。
  • popular_colors:给聚合查询取个名字,叫做 popular_colors
  • terms:聚合类型为terms,桶聚合的一种,类似SQL的group by的作用,根据字段分组,相同字段值的文档分为一组。
  • field:terms聚合类型的参数,这里需要设置分组的字段为color,根据color分组。
1
2
3
4
5
6
7
8
9
10
11
GET /order/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
}
}
}
}

查询结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
...
"hits": { // 因为size=0,所以query查询结果为空
"hits": []
},
"aggregations": { // 聚合查询结果
"popular_colors": { // 这个就是popular_colors聚合查询的结果,这就是为什么需要给聚合查询取个名字的原因,如果有多个聚合查询,可以通过名字查找结果
"buckets": [ // 因为是桶聚合,所以看到返回一个buckets数组,代表分组的统计情况,下面可以看到每一种颜色的销量情况
{
"key": "red",
"doc_count": 4 // 红色的汽车销量为4
},
{
"key": "blue",
"doc_count": 2
},
{
"key": "green",
"doc_count": 2
}
]
}
}
}

指标聚合

类似 SQL 的统计函数,指标聚合可以单独使用,也可以跟桶聚合一起使用。常用的统计函数如下:

  • Value Count: 类似 SQL的count函数,主要用于值聚合,统计文档总数。
  • Cardinality:类似 SQL 的count(DISTINCT 字段), 统计不重复的文档总数。
  • Avg:求平均值
  • Sum :求和
  • Max :求最大值
  • Min :求最小值

应用示例:

1
2
3
4
5
6
7
8
9
10
GET /my_index/_search?size=0
{
"aggs": {
"types_count": { // 聚合查询的名字,随便取个名字
"value_count": { // 聚合类型为:value_count
"field": "product_type" // 计算 product_type 这个字段值的总数
}
}
}
}

等价于SQL:select count(type) from sales

查询结果:

1
2
3
4
5
6
7
8
{
...
"aggregations": {
"types_count": { // 聚合查询的名字
"value": 7 // 统计结果
}
}
}

桶聚合

目的就是数据分组,先将数据按指定的条件分成多个组(桶),然后对每一个组(桶)进行统计。在ES中统一使用桶(bucket)这个术语。

桶聚合的作用跟SQL的group by的作用是一样的,区别是ES支持更加强大的数据分组能力,SQL只能根据字段的唯一值进行分组,分组的数量跟字段的唯一值的数量相等,例如: group by 店铺id, 去掉重复的店铺ID后,有多少个店铺就有多少个分组。

常用的桶聚合方式:

  • Terms: 类似SQL的group by,根据字段唯一值分组
  • Histogram:根据数值间隔分组,例如: 价格按100间隔分组,0、100、200、300等等
  • Date histogram:根据时间间隔分组,例如:按月、按天、按小时分组
  • Range:按数值范围分组,例如: 0-150一组,150-200一组,200-500一组。

应用示例:

1
2
3
4
5
6
7
8
9
10
GET /order/_search?size=0
{
"aggs": {
"shop": { // 聚合查询的名字,随便取个名字
"terms": { // 聚合类型为: terms
"field": "shop_id" // 根据shop_id字段值,分桶
}
}
}
}

等价于SQL:select shop_id, count(*) from order group by shop_id

查询结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
...
"aggregations" : {
"shop" : { // 聚合查询名字
"buckets" : [ // 桶聚合结果,下面返回各个桶的聚合结果
{
"key" : "1", // key分桶的标识,在terms聚合中,代表的就是分桶的字段值
"doc_count" : 6 // 默认的指标聚合是统计桶内文档总数
},
{
"key" : "5",
"doc_count" : 3
},
{
"key" : "9",
"doc_count" : 2
}
]
}
}
}

多桶排序

默认情况,ES会根据doc_count文档总数,降序排序。

ES桶聚合支持两种方式排序:

  • 内置排序

    _count:按文档数排序。对 terms 、 histogram 、 date_histogram 有效。

    _term:按词项的字符串值的字母顺序排序,只在 terms 内使用。

    _key:按每个桶的键值数值排序, 仅对 histogram 和 date_histogram 有效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /cars/_search
{
"size" : 0,
"aggs" : {
"colors" : { // 聚合查询名字,随便取一个
"terms" : { // 聚合类型为: terms
"field" : "color",
"order": { // 设置排序参数
"_count" : "asc" // 根据_count排序,asc升序,desc降序
}
}
}
}
}
  • 按度量指标排序

    通常情况下,根据桶聚合分桶后,都会对桶内进行多个维度的指标聚合,所以也可以根据桶内指标聚合的结果进行排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /cars/_search
{
"size" : 0,
"aggs" : {
"colors" : { // 聚合查询名字
"terms" : { // 聚合类型: terms,先分桶
"field" : "color", // 分桶字段为color
"order": { // 设置排序参数
"avg_price" : "asc" // 根据avg_price指标聚合结果,升序排序。
}
},
"aggs": { // 嵌套聚合查询,设置桶内聚合指标
"avg_price": { // 聚合查询名字,前面排序引用的就是这个名字
"avg": {"field": "price"} // 计算price字段平均值
}
}
}
}
}

限制返回桶的数量

如果分桶的数量太多,可以通过给桶聚合增加一个size参数限制返回桶的数量。

1
2
3
4
5
6
7
8
9
10
11
GET /cars/_search
{
"aggs" : {
"products" : { // 聚合查询名字
"terms" : { // 聚合类型为: terms
"field" : "product", // 根据product字段分桶
"size" : 5 // 限制最多返回5个桶
}
}
}
}