[ELK实战] Elasticsearch 聚合查询二: Bucketing/桶聚合

本文详细介绍了Elasticsearch中的聚合查询,包括Metric、Bucketing、Matrix和Pipeline四种聚合方式。通过实例展示了如何进行范围聚合、时间范围聚合、分组聚合、直方图和时间直方图统计,以及如何进行嵌套聚合以获取更复杂的统计信息,如每年最高工资和各年龄区间的工资总和。聚合查询是Elasticsearch强大分析能力的体现,能帮助用户深入理解数据。

简介

目前在官方文档有4种聚合(Aggregations )方式分别是:

  1. Metric (指标聚合):
    最常用的聚合方式例如 平均值,求和等等

  2. Bucketing (桶聚合):
    就是常说的分组聚合

  3. Matrix (矩阵聚合) :
    在多个字段上操作并根据从请求的文档字段提取的值生成矩阵结果的聚合族。与度量聚合和桶聚合不同,此聚合族尚不支持脚本。

  4. Pipeline (管道聚合):
    由于每个 bucket 有效地定义了一个文档集(属于 bucket 的所有文档) ,因此可以潜在地在 bucket 级别上关联聚合,并且这些聚合将在 bucket 的上下文中执行。这就是聚合的真正威力所在: 聚合可以被嵌套!

方法 / 步骤

一: 简介并加入测试数据

1.1 聚合相关参数

指标聚合有参数有:range / date_range / terms / histogram / date_histogram / …

聚合类型聚合参数简介
BucketingRange Aggregation- 范围聚合查询
BucketingDate Range Aggregation- 时间范围聚合查询
BucketingTerms Aggregation- 分组统计
BucketingHistogram Aggregation- 直方图统计
BucketingDate histogram aggregation- 时间直方图统计

1.2 DSL 查询格式

"aggregations" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation>]+ } ]?
    }
    [,"<aggregation_name_2>" : { ... } ]*
}

1.3 插入批量测试数据

POST /staff/_bulk
{"index":{"_id":1}}
{"name":"zs","realname":"张三","age":10,"birthday":"2018-12-27","salary":1000.0,"address":"北京市北海公园"}
{"index":{"_id":2}}
{"name":"ls","realname":"李四","age":20,"birthday":"2017-10-20","salary":2000.0,"address":"北京市京东大峡谷"}
{"index":{"_id":3}}
{"name":"ww","realname":"王五","age":30,"birthday":"2016-03-15","salary":3000.0,"address":"北京市陶然亭"}
{"index":{"_id":4}}
{"name":"zl","realname":"赵六","age":40,"birthday":"2003-04-19","salary":4000.0,"address":"北京市玉渊潭"}
{"index":{"_id":5}}
{"name":"tq","realname":"田七","age":50,"birthday":"2001-08-11","salary":5000.0,"address":"北京市圆明园"}

插入完成后,查看索引数据:

GET /staff/_search

在这里插入图片描述

二: 常规查询

2.1 Range Aggregation / 返回聚合

每个范围表示一个桶。在聚合过程中,将根据每个bucket范围和相关/匹配文档的“bucket”检查从每个文档提取的值。

如: 统计0-20岁,20-40岁,40~60岁各个区间段的用户人数

POST /staff/_search
{
  "aggs": {
    "age_ranges_count": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 0,
            "to": 20
          },
          {
            "from": 20,
            "to": 40
          },
          {
            "from": 40,
            "to": 60
          }
        ]
      }
    }
  }
}
  • 返回内容
	.....
  "aggregations" : {
    "age_ranges_count" : {
      "buckets" : [
        {
          "key" : "0.0-20.0",
          "from" : 0.0,
          "to" : 20.0,
          "doc_count" : 1
        },
        {
          "key" : "20.0-40.0",
          "from" : 20.0,
          "to" : 40.0,
          "doc_count" : 2
        },
        {
          "key" : "40.0-60.0",
          "from" : 40.0,
          "to" : 60.0,
          "doc_count" : 2
        }
      ]
    }
  }
  	.....
  • 如果第一个区间开始值和最后一个区间结束值不想指定的话,可以不用写from和to,如下:
POST /staff/_search
{
  "aggs": {
    "age_ranges_count": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "to": 20
          },
          {
            "from": 20,
            "to": 40
          },
          {
            "from": 40,
            "to": 60
          }
        ]
      }
    }
  }
}
  • 返回内容
....
  "aggregations" : {
    "age_ranges_count" : {
      "buckets" : [
        {
          "key" : "*-20.0",
          "to" : 20.0,
          "doc_count" : 1
        },
        {
          "key" : "20.0-40.0",
          "from" : 20.0,
          "to" : 40.0,
          "doc_count" : 2
        },
        {
          "key" : "40.0-60.0",
          "from" : 40.0,
          "to" : 60.0,
          "doc_count" : 2
        }
      ]
    }
  }
  ....

2.2 Date Range Aggregation / 时间范围聚合

此聚合与Range Aggregation常规范围聚合的主要区别在于,可以用日期数学表达式表示from和to值,而且还可以指定返回from和to响应字段的日期格式。注意,此聚合包含每个范围的from值并排除to值。

  • now+10y:表示从现在开始的第10年。
  • now+10M:表示从现在开始的第10个月。
  • 1990-01-10||+20y:表示从1990-01-01开始后的第20年,即2010-01-01。
  • now/y:表示在年位上做舍入运算。

如: 统计生日在2017年、2018年、2019年的用户

now/y:当前年的1月1日
now:当前时间
now/y-1y:当前年上一年的1月1日

POST /staff/_search
{
  "aggs": {
    "birthday_count": {
      "date_range": {
        "field": "birthday",
        "format": "yyyy-MM-dd",
        "ranges": [
          {
            "from": "now/y-1y",
            "to": "now/y"
          },
          {
            "from": "now/y-2y",
            "to": "now/y-1y"
          },
          {
            "from": "now/y-3y",
            "to": "now/y-2y"
          }
        ]
      }
    }
  }
}
  • 返回数据
  "aggregations" : {
    "birthday_count" : {
      "buckets" : [
        {
          "key" : "2019-01-01-2020-01-01",
          "from" : 1.5463008E12,
          "from_as_string" : "2019-01-01",
          "to" : 1.5778368E12,
          "to_as_string" : "2020-01-01",
          "doc_count" : 0
        },
        {
          "key" : "2020-01-01-2021-01-01",
          "from" : 1.5778368E12,
          "from_as_string" : "2020-01-01",
          "to" : 1.6094592E12,
          "to_as_string" : "2021-01-01",
          "doc_count" : 0
        },
        {
          "key" : "2021-01-01-2022-01-01",
          "from" : 1.6094592E12,
          "from_as_string" : "2021-01-01",
          "to" : 1.6409952E12,
          "to_as_string" : "2022-01-01",
          "doc_count" : 0
        }
      ]
    }
  }

2.3 Terms Aggregation / 分组聚合

  • 对年龄进行聚合,显示3条数据

POST /staff/_search
{
  "aggs": {
    "age_count": {
      "terms": {
        "field": "age",
        "size": 3
      }
    }
  }
}
  • 聚合结果
    key年龄 为10,20 ,30各为一条
	......
  "aggregations" : {
    "age_count" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 2,
      "buckets" : [
        {
          "key" : 10,
          "doc_count" : 1
        },
        {
          "key" : 20,
          "doc_count" : 1
        },
        {
          "key" : 30,
          "doc_count" : 1
        }
      ]
    }
  }
  	......

2.4 Histogram Aggregation / 直方图聚合

它与前面介绍的Range聚合非常像,只不过Range可以任意划分区间,而Histogram做等间距划分。既然是等间距划分,那么参数里面必然有距离参数,就是interval参数。
如:根据年龄间隔(20岁)统计各个年龄段的员工总人数

POST /staff/_search?size=0
{
  "aggs": {
    "salary_value_count": {
      "value_count": {
        "field": "salary"
      }
    }
  }
}
  • 返回结果
	.....
  "aggregations" : {
    "age_histogram_count" : {
      "buckets" : [
        {
          "key" : 0.0,
          "doc_count" : 1
        },
        {
          "key" : 20.0,
          "doc_count" : 2
        },
        {
          "key" : 40.0,
          "doc_count" : 2
        }
      ]
    }
  }
  	.....

2.5 Date histogram aggregation / 时间直方图聚合

日期直方图聚合,专门对时间类型的字段做直方图聚合。这种需求是比较常用见得的,我们在统计时,通常就会按照固定的时间断(1个月或1年等)来做统计

如:按年统计用户生日的总人数

POST /staff/_search
{
  "aggs": {
    "birthday_data_histogram_count": {
      "date_histogram": {
        "field": "birthday",
        "interval": "year",
        "format": "yyyy-MM-dd"
      }
    }
  }
}
  • 返回结果
	.....
  "aggregations" : {
    "birthday_data_histogram_count" : {
      "buckets" : [
        {
          "key_as_string" : "2001-01-01",
          "key" : 978307200000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2002-01-01",
          "key" : 1009843200000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2003-01-01",
          "key" : 1041379200000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2004-01-01",
          "key" : 1072915200000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2005-01-01",
          "key" : 1104537600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2006-01-01",
          "key" : 1136073600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2007-01-01",
          "key" : 1167609600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2008-01-01",
          "key" : 1199145600000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2009-01-01",
          "key" : 1230768000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2010-01-01",
          "key" : 1262304000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2011-01-01",
          "key" : 1293840000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2012-01-01",
          "key" : 1325376000000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2013-01-01",
          "key" : 1356998400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2014-01-01",
          "key" : 1388534400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2015-01-01",
          "key" : 1420070400000,
          "doc_count" : 0
        },
        {
          "key_as_string" : "2016-01-01",
          "key" : 1451606400000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2017-01-01",
          "key" : 1483228800000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2018-01-01",
          "key" : 1514764800000,
          "doc_count" : 1
        }
      ]
    }
  }
  	.....

三: 聚合查询嵌套使用

通过嵌套,可以使得metric类型的聚合操作作用在每一bucket上。我们可以使用ES的嵌套聚合操作来完成稍微复杂一点的统计功能。

3.1 统计每年中用户的最高工资

POST /staff/_search
{
  "aggs": {
    "birthday_data_histogram_count": {
      "date_histogram": {
        "field": "birthday",
        "interval": "year",
        "format": "yyyy-MM-dd"
      },
      "aggs": {
        "max_salary": {
          "max": {
            "field": "salary"
          }
        }
      }
    }
  }
}
  • 返回结果
	.....
  "aggregations" : {
    "birthday_data_histogram_count" : {
      "buckets" : [
        {
          "key_as_string" : "2001-01-01",
          "key" : 978307200000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 5000.0
          }
        },
        {
          "key_as_string" : "2002-01-01",
          "key" : 1009843200000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2003-01-01",
          "key" : 1041379200000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 4000.0
          }
        },
        {
          "key_as_string" : "2004-01-01",
          "key" : 1072915200000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2005-01-01",
          "key" : 1104537600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2006-01-01",
          "key" : 1136073600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2007-01-01",
          "key" : 1167609600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2008-01-01",
          "key" : 1199145600000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2009-01-01",
          "key" : 1230768000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2010-01-01",
          "key" : 1262304000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2011-01-01",
          "key" : 1293840000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2012-01-01",
          "key" : 1325376000000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2013-01-01",
          "key" : 1356998400000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2014-01-01",
          "key" : 1388534400000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2015-01-01",
          "key" : 1420070400000,
          "doc_count" : 0,
          "max_salary" : {
            "value" : null
          }
        },
        {
          "key_as_string" : "2016-01-01",
          "key" : 1451606400000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 3000.0
          }
        },
        {
          "key_as_string" : "2017-01-01",
          "key" : 1483228800000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 2000.0
          }
        },
        {
          "key_as_string" : "2018-01-01",
          "key" : 1514764800000,
          "doc_count" : 1,
          "max_salary" : {
            "value" : 1000.0
          }
        }
      ]
    }
  }
  	.....

先通过date_histogram按照年分组,然后再通过嵌套max聚合查询统计出每年最高工资是多少。

3.2 求每个年龄区间段的工资总和

....
  "aggregations" : {
    "age_ranges_count" : {
      "buckets" : [
        {
          "key" : "0.0-20.0",
          "from" : 0.0,
          "to" : 20.0,
          "doc_count" : 1,
          "sum_salary" : {
            "value" : 1000.0
          }
        },
        {
          "key" : "20.0-40.0",
          "from" : 20.0,
          "to" : 40.0,
          "doc_count" : 2,
          "sum_salary" : {
            "value" : 5000.0
          }
        },
        {
          "key" : "40.0-60.0",
          "from" : 40.0,
          "to" : 60.0,
          "doc_count" : 2,
          "sum_salary" : {
            "value" : 9000.0
          }
        }
      ]
    }
  }
  ....

参考资料 & 致谢

[1]官方文档
[2] ElasticSearch全文搜索引擎之Aggregation聚合查询(结合Kibana)

<think>好的,用户现在问的是关于docker-compose.yml文件的配置,特别是询问在哪个配置文件中进行操作。用户之前已经提供了一段docker-compose.yml的示例,里面配置了Elasticsearch、Logstash和Kibana服务,也就是ELK堆栈。用户的问题可能是在确认这些配置应该放在哪个配置文件中,或者如何正确配置这些服务。 首先,我需要确认用户是否了解docker-compose.yml的基本结构和用途。用户可能已经有一定的Docker基础,但需要更详细的指导。用户提供的示例文件看起来是正确的,版本是3,定义了三个服务,每个服务都有镜像、卷、端口等配置。用户的问题可能集中在具体的配置细节,比如卷挂载的路径是否正确,端口映射是否合适,或者是否需要额外的环境变量。 接下来,用户提到的“在哪个配置文件下操作”可能是在问这些服务各自的配置文件应该放在哪里。例如,Logstash的配置文件通常需要挂载到容器内的指定目录,用户已经将./logstash-config挂载到/usr/share/logstash/pipeline,这意味着用户需要在本地的logstash-config目录下放置Logstash的管道配置文件,比如logstash.conf。而Elasticsearch和Kibana可能也有自己的配置需求,比如Elasticsearch的环境变量设置或者Kibana的yml配置。 另外,用户可能没有提到的是Elasticsearch在8.x版本后的安全特性,比如默认启用安全配置,需要设置密码或者证书。如果用户直接运行当前的docker-compose.yml,可能会遇到连接问题,因为Elasticsearch和Kibana需要正确的安全配置才能通信。这时候可能需要添加环境变量,比如ELASTIC_PASSWORD,或者在Kibana配置中指定Elasticsearch的地址和凭证。 此外,用户配置的端口映射是否正确?例如,Elasticsearch的9200端口用于HTTP API,而Kibana的5601端口用于Web界面。Logstash的5000端口可能用于接收日志数据,比如通过TCP/UDP。用户需要确认这些端口在主机上是否可用,并且防火墙设置允许访问。 还有卷的配置,比如Elasticsearch的数据目录挂载到本地的./elk/elasticsearch/data,这有助于数据持久化,避免容器重启后数据丢失。用户需要确保该目录存在,并且有正确的权限,否则Elasticsearch容器可能会启动失败。 可能用户还希望知道如何启动和管理这些服务,比如使用docker-compose up -d命令,以及如何查看日志,进行故障排除。此外,是否需要设置网络,让这三个服务在同一个Docker网络中,以便它们可以通过服务名互相访问,而不需要暴露所有端口到主机。 总结来说,用户需要详细的步骤指导,包括配置文件的放置位置、必要的环境变量、安全设置、网络配置以及数据持久化的注意事项。需要一步步解释每个服务的配置细节,并指出常见问题及解决方法,确保用户能够顺利部署ELK堆栈。</think>以下是针对您提供的 `docker-compose.yml` 文件的逐层解析和操作指南,重点说明配置文件的操作位置及关键配置项的作用: --- ### **一、文件结构解析** ```yaml version: '3' # 定义 Docker Compose 版本 services: # 服务列表 elasticsearch: # 服务1:Elasticsearch image: elasticsearch:8.5.3 volumes: - ./elk/elasticsearch/data:/usr/share/elasticsearch/data # 数据持久化 ports: - "9200:9200" # 暴露 Elasticsearch HTTP API 端口 logstash: # 服务2:Logstash image: logstash:8.5.3 volumes: - ./logstash-config:/usr/share/logstash/pipeline # 挂载 Logstash 配置文件目录 ports: - "5000:5000" # 日志输入端口(TCP/UDP) kibana: # 服务3:Kibana image: kibana:8.5.3 ports: - "5601:5601" # 暴露 Kibana Web 界面端口 ``` --- ### **、配置文件操作位置** #### 1. **Elasticsearch** - **核心配置**:默认从容器内部加载 `/usr/share/elasticsearch/config/elasticsearch.yml`。 - **自定义配置**: - **方法1**:直接挂载配置文件(推荐): ```yaml volumes: - ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml ``` - **方法2**:通过环境变量覆盖(部分配置): ```yaml environment: - discovery.type=single-node # 单节点模式 - ES_JAVA_OPTS=-Xms512m -Xmx512m # JVM 内存限制 ``` #### 2. **Logstash** - **核心配置**:配置文件需放在挂载目录下的 `.conf` 文件中。 - **操作步骤**: 1. 在本地创建 `logstash-config` 目录。 2. 在目录中创建 `logstash.conf`,定义输入、过滤、输出管道: ```conf input { tcp { port => 5000 # 与 docker-compose 中端口映射一致 } } filter { # 添加数据处理逻辑(如解析 JSON) } output { elasticsearch { hosts => ["http://elasticsearch:9200"] # 通过服务名访问 Elasticsearch } } ``` #### 3. **Kibana** - **核心配置**:默认从容器内部加载 `/usr/share/kibana/config/kibana.yml`。 - **自定义配置**: ```yaml volumes: - ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml ``` - **关键配置项**(在 `kibana.yml` 中): ```yml server.host: "0.0.0.0" # 允许外部访问 elasticsearch.hosts: ["http://elasticsearch:9200"] # 指向 Elasticsearch 服务 ``` --- ### **三、安全配置(Elasticsearch 8.x 必选)** Elasticsearch 8.x 默认启用安全功能,需配置密码和证书: ```yaml # 在 elasticsearch 服务中添加环境变量 environment: - ELASTIC_PASSWORD=your_password # 设置默认用户 elastic 的密码 - xpack.security.enabled=true ``` Kibana 需配置 Elasticsearch 凭据: ```yaml # 在 kibana 服务中添加环境变量 environment: - ELASTICSEARCH_USERNAME=elastic - ELASTICSEARCH_PASSWORD=your_password ``` --- ### **四、网络配置优化** 默认情况下,Docker Compose 会创建独立网络,服务间可通过服务名互通(如 `elasticsearch:9200`)。如需自定义网络: ```yaml networks: elk-net: driver: bridge services: elasticsearch: networks: - elk-net logstash: networks: - elk-net kibana: networks: - elk-net ``` --- ### **五、完整操作流程** 1. **创建目录结构**: ``` ├── docker-compose.yml ├── elasticsearch/ │ └── config/ │ └── elasticsearch.yml ├── logstash-config/ │ └── logstash.conf └── kibana/ └── config/ └── kibana.yml ``` 2. **启动服务**: ```bash docker-compose up -d ``` 3. **验证服务**: - Elasticsearch:`curl http://localhost:9200` - Kibana:浏览器访问 `http://localhost:5601` --- ### **六、常见问题** 1. **Elasticsearch 启动失败**: - 检查 `data` 目录权限:`chmod 777 ./elk/elasticsearch/data` - 确认内存配置:JVM 堆大小需适配宿主机内存 2. **Logstash 连接 Elasticsearch 超时**: - 检查服务名称 `elasticsearch` 是否一致 - 确认 Elasticsearch 安全配置已正确传递密码 3. **Kibana 无法加载页面**: - 检查 `kibana.yml` 中 `elasticsearch.hosts` 地址 - 确认防火墙开放 5601 端口 --- 是否需要针对证书配置或日志过滤规则提供更详细的说明?
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OxYGC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值