• 主页
  • 架构
  • 编程语言
  • 数据存储
  • 网络
  • VMware
  • 服务器
  • 组网
  • AI
  • 算法系列
  • 设计模式
  • 读书笔记
  • 思考
  • 工具
  • 其它技术

  • 主页
  • 架构
  • 编程语言
  • 数据存储
  • 网络
  • VMware
  • 服务器
  • 组网
  • AI
  • 算法系列
  • 设计模式
  • 读书笔记
  • 思考
  • 工具
  • 其它技术

6 Elasticsearch聚合分析

2025-02-17

上一次聊了5 Elasticsearch深入搜索,这次来看看聚合。API链接为: https://www.elastic.co/guide/en/elasticsearch/reference/7.1/query-dsl-nested-query.html 。

聚合说明

什么是聚合?Kibana上的这些图就是聚合,底层通过ES能够实现。

image-20250212210850879

ES支持哪些聚合?聚合有很多类型,主要看Metrics和Bucket

image-20250212210619651

  • Bucket Aggregation:一些列满足特定条件的文档的集合
  • Metric Aggregation:一些数学运算,可以对文档字段进行统计分析
  • Pipeline Aggreagtion:对其它的聚合结果进行二次聚合
  • Matrix Aggregation:支持对多个字段的操作并提供一个结果矩阵

Bucket和Metric如果用MySQL类比

image-20250212211613564

聚合API

Aggregation属于Search的一部分,语法如下

image-20250212211916678

Metric

说明

  1. Metric会基于数据集计算结果,除了支持在字段上进行计算,同时也支持在脚本(painless script)产生的结果之上进行计算
  2. 大多数Metric是数学计算,仅输出一个值,如min/max/sum/avg/cardinality
  3. 部分metric支持输出多个数值,如stats/percentiles/percentile_ranks

image-20250212212144767

实战

查询电影中,最大的一年

image-20250212212656863

如果size大于1,会返回对应的条目信息

image-20250212212731320

Bucket

说明

  1. 按照⼀定的规则,将⽂档分配到不同的桶中,从⽽达到分类的⽬的。类似于MySQL的group。
  2. ⽀持嵌套:也就在桶⾥再做分桶。⼦聚合分析可以是Bucket和Metric
  3. Term Aggregations对于text字段,需要打开fielddata才可以使用

image-20250212213025548

实战

按照年group

image-20250212234035303

设置返回数量

image-20250212234002406

先按年group,然后按年内的类型group

image-20250212234524753

聚合执行过程

聚合其实是从各个分片获取数据,然后进行组合的过程,Min和Term的聚合过程如下

image-20250212234728199

image-20250212234758637

通过Terms的样例,能够发现聚合的结果未必是准确的,因为数据是分散的,每个Node的top3未必是全局的top3。ES提供了一些参数可以用来解决或者优化这个问题。

关联查询

Joining queries为”关联查询” 或 “连接查询”。这种查询方式主要用于在 Elasticsearch 中处理具有层次结构的数据,例如,一个博客文章(父文档)和它的评论(子文档)。通过使用has_child、has_parent、parent_id等查询类型,可以实现对这类数据的有效检索。

image-20250212235500140

Nested(嵌套)场景

“nested”(嵌套)是一种数据类型和查询方式,用于处理复杂的数据结构。具体来说,它允许你在文档中存储数组类型的对象,并且这些对象中的每个元素都可以被单独索引和查询。

假设写了一个电影的mapping

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
PUT my_movies
{
"mappings" : {
"properties" : {
"actors" : {
"properties" : {
"first_name" : {
"type" : "keyword"
},
"last_name" : {
"type" : "keyword"
}
}
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}

写入一条电影doc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST my_movies/_doc/1
{
"title":"Speed",
"actors":[
{
"first_name":"Keanu",
"last_name":"Reeves"
},

{
"first_name":"Dennis",
"last_name":"Hopper"
}

]
}

进行查询

1
2
3
4
5
6
7
8
9
10
11
POST my_movies/_search
{
"query": {
"bool": {
"must": [
{"match": {"actors.first_name": "Keanu"}},
{"match": {"actors.last_name": "Hopper"}}
]
}
}
}

发现竟然能够查到结果:

image-20250213000015471

这是因为ES存储时,内部对象的边界并没有考虑在内,JSON 格式被处理成扁平式键值对的结构

image-20250213000111823

为了解决这个问题,我们使用Nested。创建 Nested 对象 Mapping,即增加type为nested

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT my_movies
{
"mappings" : {
"properties" : {
"actors" : {
"type": "nested",
"properties" : {
"first_name" : {"type" : "keyword"},
"last_name" : {"type" : "keyword"}
}},
"title" : {
"type" : "text",
"fields" : {"keyword":{"type":"keyword","ignore_above":256}}
}
}
}
}

重新插入数据,使用nested进行查询发现查不到了,如果使用正确的first_name和last_name可以查到

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
POST my_movies/_search
{
"query": {
"bool": {
"must": [
{"match": {"title": "Speed"}},
{
"nested": {
"path": "actors",
"query": {
"bool": {
"must": [
{"match": {
"actors.first_name": "Keanu"
}},

{"match": {
"actors.last_name": "Hopper"
}}
]
}
}
}
}
]
}
}
}

image-20250213000521668

image-20250213000612516

这是因为在ES内部, Nested ⽂档会被保存在两个 Lucene⽂档中,会在查询时做 Join 处理

image-20250213000709403

Nested(嵌套)聚合

我们可以在Nested上做聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
POST my_movies/_search
{
"size": 0,
"aggs": {
"actors": {
"nested": {
"path": "actors"
},
"aggs": {
"actor_name": {
"terms": {
"field": "actors.first_name",
"size": 10
}
}
}
}
}
}

image-20250213000950611

扫一扫,分享到微信

微信分享二维码
晋升系列2:职级详解
晋升系列1:晋升前的基础认知
© 2025 John Doe
Hexo Theme Yilia by Litten