掌握 ElasticSearch 聚合查询:Aggregations 入门与实战

掌握 ElasticSearch 聚合查询:Aggregations 入门与实战

    • 一、引言 (Introduction)
    • 二、数据准备 (Data Preparation)
      • 2.1 创建索引 (Create Index)
      • 2.2 批量导入数据 (Bulk Import Data)
    • 三、聚合查询基础 (Aggregation Basics)
      • 3.1 什么是聚合查询?(What are Aggregations?)
      • 3.2 聚合查询的基本结构 (Basic Aggregation Structure)
      • 3.3 聚合类型 (Aggregation Types)
    • 四、指标聚合 (Metrics Aggregations)
      • 4.1 `avg` (平均值)
      • 4.2 `min` (最小值)
      • 4.3 `max` (最大值)
      • 4.4 `sum` (总和)
      • 4.5 `stats` (统计信息)
      • 4.6 `value_count` (值计数)
      • 4.7 `cardinality` (基数/去重计数)
    • 五、桶聚合 (Bucket Aggregations)
      • 5.1 `terms` (词条聚合)
      • 5.2 嵌套桶聚合
    • 六、管道聚合 (Pipeline Aggregations)
      • 6.1 什么是管道聚合?
      • 6.2 `min_bucket` (最小桶)
      • 6.3 其他管道聚合
    • 七、实战案例 (Practical Examples)
      • 案例 1:统计每个产品类别中,价格最高的产品的价格,并按最高价格降序排列
      • 案例 2:找出每个月销售额最高的日期
    • 八、总结 (Conclusion)

一、引言 (Introduction)

在信息检索和数据分析的世界中,我们常常需要做的不仅仅是找到匹配特定关键词的文档。很多时候,我们需要从海量数据中提取出更深层次的、有价值的洞察。例如:

  • 我想知道我的电商网站上所有商品的平均价格是多少?
  • 哪个产品类别下的商品数量最多?
  • 我的网站上有多少种不同的商品品牌?
  • 在过去的一年中,每个月的销售总额是多少?
  • 哪一天的销售额是最高的?

这些问题都涉及对数据的统计和分析,而不仅仅是简单的搜索。为了满足这些需求,Elasticsearch 提供了强大的聚合查询(Aggregations) 功能。聚合查询就像一个多功能的瑞士军刀,或者说是一个强大的数据分析工具箱,它允许你对数据进行各种分组、统计和计算,从而提取出隐藏在数据背后的关键信息。

你可以把聚合查询想象成 SQL 中的 GROUP BY 子句和各种聚合函数(COUNT, SUM, AVG, MIN, MAX)的组合,但 Elasticsearch 的聚合功能远比 SQL 更加灵活和强大。

本文将带你深入了解 Elasticsearch 7.10 版本中聚合查询的基础知识。通过本文,你将学习到:

  • 聚合查询的基本概念和工作原理。
  • 三种核心的聚合类型:指标聚合(Metrics Aggregations)、桶聚合(Bucket Aggregations)和管道聚合(Pipeline Aggregations)。
  • 如何使用各种指标聚合函数(avg, min, max, sum, stats, value_count, cardinality)。
  • 如何使用 terms 聚合进行分组。
  • 如何使用管道聚合对聚合结果进行二次聚合。
  • 通过实战案例学习如何在实际应用中运用聚合查询,解决真实的数据分析问题。

二、数据准备 (Data Preparation)

在开始学习聚合查询之前,我们需要先准备一些示例数据。我们将创建一个名为 product 的索引,并批量导入一些商品数据。

2.1 创建索引 (Create Index)

首先,我们创建一个名为 product 的索引,并定义其 mappings(映射)。Mappings 定义了索引中每个字段的数据类型以及如何进行索引和搜索。

PUT product
{
  "mappings": {
    "properties": {
      "createtime": {
        "type": "date"
      },
      "date": {
        "type": "date"
      },
      "desc": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "lv": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "name": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "price": {
        "type": "long"
      },
      "tags": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "type": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

2.2 批量导入数据 (Bulk Import Data)

接下来,我们使用 Elasticsearch 的 _bulk API 来批量导入一些商品数据。_bulk API 可以一次性执行多个索引、更新或删除操作,效率更高。

POST /product/_bulk
{"index":{"_index": "product"}}
{"name": "小米手机", "desc": "手机中的战斗机", "price": 3999, "lv": "旗舰机", "type": "手机", "createtime": "2020-10-01T08:00:00Z", "tags": [ "性价比", "发烧", "不卡顿" ]}
{"index":{"_index": "product"}}
{"name": "小米NFC手机", "desc": "支持全功能NFC,手机中的滑翔机", "price": 4999, "lv": "旗舰机", "type": "手机", "createtime": "2020-05-21T08:00:00Z", "tags": [ "性价比", "发烧", "公交卡" ]}
{"index":{"_index": "product"}}
{"name": "NFC手机", "desc": "手机中的轰炸机", "price": 2999, "lv": "高端机", "type": "手机", "createtime": "2020-06-20T08:00:00Z", "tags": [ "性价比", "快充", "门禁卡" ]}
{"index":{"_index": "product"}}
{"name": "小米耳机", "desc": "耳机中的黄焖鸡", "price": 999, "lv": "百元机", "type": "耳机", "createtime": "2020-06-23T08:00:00Z", "tags": [ "降噪", "防水", "蓝牙" ]}
{"index":{"_index": "product"}}
{"name": "红米耳机", "desc": "耳机中的肯德基", "price": 399, "type": "耳机", "lv": "百元机", "createtime": "2020-07-20T08:00:00Z", "tags": [ "防火", "低音炮", "听声辨位" ]}
{"index":{"_index": "product"}}
{"name": "小米手机10", "desc": "充电贼快掉电更快,超级无敌望远镜,高刷电竞屏", "price": null, "lv": "旗舰机", "type": "手机", "createtime": "2020-07-27T08:00:00Z", "tags": [ "120HZ刷新率", "120W快充", "120倍变焦" ]}
{"index":{"_index": "product"}}
{"name": "挨炮 SE2", "desc": "除了CPU,一无是处", "price": 3299, "lv": "旗舰机", "type": "手机", "createtime": "2020-07-21T08:00:00Z", "tags": [ "割韭菜", "割韭菜", "割新韭菜" ]}
{"index":{"_index": "product"}}
{"name": "XS Max", "desc": "听说要出新款12手机了,终于可以换掉手中的4S了", "price": 4399, "lv": "旗舰机", "type": "手机", "createtime": "2020-08-19T08:00:00Z", "tags": [ "5V1A", "4G全网通", "大" ]}
{"index":{"_index": "product"}}
{"name": "小米电视", "desc": "70寸性价比只选,不要一万八,要不要八千八,只要两千九百九十八", "price": 2998, "lv": "高端机", "type": "电视", "createtime": "2020-08-16T08:00:00Z", "tags": [ "巨馍", "家庭影院", "游戏" ]}
{"index":{"_index": "product"}}
{"name": "红米电视", "desc": "我比上边那个更划算,我也2998,我也70寸,但是我更好看", "price": 2999, "type": "电视", "lv": "高端机", "createtime": "2020-08-28T08:00:00Z", "tags": [ "大片", "蓝光8K", "超薄" ]}
{"index":{"_index": "product"}}
{"name": "红米电视", "desc": "我比上边那个更划算,我也2998,我也70寸,但是我更好看", "price": 2998, "type": "电视", "lv": "高端机", "createtime": "2020-08-28T08:00:00Z", "tags": [ "大片", "蓝光8K", "超薄" ]}

代码解释:

  • POST /product/_bulk: 使用 _bulk API 向 product 索引发送批量请求。
  • 每一行是一个 JSON 对象,表示一个操作。

现在,我们已经准备好了数据,可以开始学习 Elasticsearch 的聚合查询了!

三、聚合查询基础 (Aggregation Basics)

3.1 什么是聚合查询?(What are Aggregations?)

聚合查询(Aggregations)是 Elasticsearch 中一种强大的数据分析功能,它允许你对文档数据进行各种统计分析。与搜索查询(返回匹配的文档)不同,聚合查询返回的是聚合后的统计结果。

你可以将聚合查询类比为 SQL 中的 GROUP BY 子句和聚合函数(如 COUNT, SUM, AVG, MIN, MAX)。 例如,你可以使用 SQL 来计算每个部门的平均工资:

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;

Elasticsearch 的聚合查询提供了类似的功能,但更加灵活和强大。它可以处理更复杂的数据结构和分析场景,并且可以进行多层嵌套的聚合。

3.2 聚合查询的基本结构 (Basic Aggregation Structure)

聚合查询的基本语法结构如下:

GET /<index>/_search
{
  "size": 0,
  "aggs": {
    "<aggregation_name>": {
      "<aggregation_type>": {
        "<aggregation_parameters>"
      },
      "aggs": {
        "<nested_aggregation_name>": {
          "<nested_aggregation_type>": {
            "<nested_aggregation_parameters>"
          }
        }
      }
    }
  }
}

解释:

  • GET /<index>/_search: 这是 Elasticsearch 的搜索 API,我们在这里使用它来执行聚合查询。
  • "size": 0: 这是一个可选参数。通常,在执行聚合查询时,我们只关心聚合结果,而不关心具体的文档内容。"size": 0 表示不返回任何文档,只返回聚合结果。
  • "aggs" (或 "aggregations"): 这是聚合查询的顶层关键字。所有聚合操作都定义在 aggs 对象中。
  • "<aggregation_name>": 这是你为聚合操作指定的名称。这个名称可以是任意的,它将作为聚合结果的一部分返回,方便你识别和引用。例如,你可以将计算平均价格的聚合命名为 "avg_price"
  • "<aggregation_type>": 这是聚合的类型。Elasticsearch 提供了多种聚合类型,每种类型都有不同的功能。常见的聚合类型包括:
    • avg (平均值)
    • min (最小值)
    • max (最大值)
    • sum (总和)
    • terms (词条聚合)
    • stats (统计信息)
    • 等等…
  • "<aggregation_parameters>": 这是特定于聚合类型的参数。不同的聚合类型有不同的参数。例如,avg 聚合需要指定要计算平均值的字段,terms 聚合需要指定要分组的字段。
  • "aggs": { ... } (在 <aggregation_name> 内部): 这是可选的嵌套聚合。你可以在一个聚合操作中嵌套另一个聚合操作,以实现更复杂的分析。例如,你可以先按产品类别分组,然后在每个类别中计算平均价格。

3.3 聚合类型 (Aggregation Types)

Elasticsearch 提供了三种主要的聚合类型:

  1. Metrics Aggregations (指标聚合): 这类聚合主要用于计算单个数值指标。例如:

    • avg: 计算平均值。
    • min: 计算最小值。
    • max: 计算最大值。
    • sum: 计算总和。
    • stats: 一次性计算多个统计值(avg, min, max, sum, count)。
    • value_count: 计算非空字段的文档数量。
    • cardinality: 计算字段的不同值的数量(去重)。
  2. Bucket Aggregations (桶聚合): 这类聚合主要用于将文档分组到不同的“桶”中。每个桶代表一个分组。例如:

    • terms: 按字段值对文档进行分组。
    • date_histogram: 按日期范围对文档进行分组。
    • range: 按自定义数值范围对文档进行分组。
    • filter: 根据指定的过滤条件将文档分到一个桶
    • filters: 根据指定的多个过滤条件将文档分到多个桶
  3. Pipeline Aggregations (管道聚合): 这类聚合比较特殊,它们不直接操作文档,而是对其他聚合的结果进行进一步的聚合。例如:

    • min_bucket: 找出包含最小值的桶。
    • max_bucket: 找出包含最大值的桶。
    • avg_bucket: 计算桶的平均值。
    • sum_bucket: 计算桶的总和。
    • stats_bucket: 对桶进行统计分析
    • derivative: 计算导数(例如,计算销售额的变化率)。

本文将重点介绍这三种聚合类型的基础用法。接下来,我们将分别深入探讨每种聚合类型,并通过示例演示如何在实际应用中使用它们。

四、指标聚合 (Metrics Aggregations)

指标聚合用于计算单个数值指标,例如平均值、最小值、最大值、总和等。这些指标可以帮助你了解数据的整体特征。

4.1 avg (平均值)

avg 聚合用于计算指定字段的平均值。

示例: 计算 product 索引中所有产品的平均价格。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "avg_price": {
      "avg": {
        "field": "price"
      }
    }
  }
}

代码解释:

  • "size": 0: 不返回文档,只返回聚合结果。
  • "aggs": 聚合查询的开始。
  • "avg_price": 我们为这个聚合操作指定的名称。
  • "avg": 指定聚合类型为 avg (平均值)。
  • "field": "price": 指定要计算平均值的字段为 price

结果 (部分):

{
  ...
  "aggregations": {
    "avg_price": {
      "value": 3008.8
    }
  }
}

结果中的 "value" 字段显示了所有产品价格的平均值。

4.2 min (最小值)

min 聚合用于计算指定字段的最小值。

示例: 计算 product 索引中所有产品的最低价格。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "min_price": {
      "min": {
        "field": "price"
      }
    }
  }
}

结果 (部分):

{
  ...
  "aggregations": {
    "min_price": {
      "value": 399.0
    }
  }
}

4.3 max (最大值)

max 聚合用于计算指定字段的最大值。

示例: 计算 product 索引中所有产品的最高价格。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "max_price": {
      "max": {
        "field": "price"
      }
    }
  }
}

结果 (部分):

{
  ...
  "aggregations": {
    "max_price": {
      "value": 4999.0
    }
  }
}

4.4 sum (总和)

sum 聚合用于计算指定字段的总和。

示例: 计算 product 索引中所有产品的价格总和。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "sum_price": {
      "sum": {
        "field": "price"
      }
    }
  }
}

结果 (部分):

{
  ...
  "aggregations": {
    "sum_price": {
      "value": 30088.0
    }
  }
}

4.5 stats (统计信息)

stats 聚合可以一次性计算多个统计值,包括:

  • count: 文档数量。
  • min: 最小值。
  • max: 最大值。
  • avg: 平均值。
  • sum: 总和。

示例: 获取 product 索引中所有产品的价格统计信息。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "price_stats": {
      "stats": {
        "field": "price"
      }
    }
  }
}

结果 (部分):

{
  ...
  "aggregations" : {
    "statistics" : {
      "count" : 10,
      "min" : 399.0,
      "max" : 4999.0,
      "avg" : 3008.8,
      "sum" : 30088.0
    }
  }
}

结果中一次性返回了countminmaxavgsum

4.6 value_count (值计数)

value_count 聚合用于计算指定字段的 非空 值的文档数量。

示例: 计算 product 索引中有多少个文档具有 price 字段(即有多少个产品有价格信息)。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "price_count": {
      "value_count": {
        "field": "price"
      }
    }
  }
}

结果 (部分):

{
  ...
  "aggregations": {
    "price_count": {
      "value": 10
    }
  }
}

注意,由于有一个文档的 price 字段为 null,因此结果为 10,而不是 11。

4.7 cardinality (基数/去重计数)

cardinality 聚合用于计算指定字段的不同值的数量(即去重计数)。

示例: 计算 product 索引中有多少种不同的产品等级 (lv)。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "lv_cardinality": {
      "cardinality": {
        "field": "lv.keyword"
      }
    }
  }
}

代码解释:

  • "lv_cardinality": 聚合的名称。
  • "cardinality": 指定聚合类型为 cardinality
  • "field": "lv.keyword": 指定要计算基数的字段为 lv.keyword。 这里使用 .keyword 子字段是因为我们要对原始的、未分词的 lv 值进行去重计数。

结果 (部分):

{
  ...
  "aggregations": {
    "lv_cardinality": {
      "value": 3
    }
  }
}

结果表明,product 索引中有 3 种不同的产品等级。

cardinality 聚合的计算结果是近似的,而不是完全精确的。对于低基数字段(即不同值较少),结果通常是准确的。但对于高基数字段(即不同值非常多),为了提高性能,Elasticsearch 使用了一种称为 HyperLogLog++ 的算法进行近似计算。你可以通过 precision_threshold 参数来控制精度和内存使用之间的权衡。如果需要完全精确的去重计数,并且数据集较小,可以考虑使用 terms 聚合,并设置一个足够大的 size 值。但对于大数据集,cardinality 聚合通常是更好的选择。

五、桶聚合 (Bucket Aggregations)

桶聚合(Bucket Aggregations)用于将文档分组到不同的“桶”中。每个桶代表一个分组,可以根据不同的条件来创建桶。桶聚合本身不进行统计运算,其主要作用是分组。通常会在桶聚合内嵌套一个或者多个指标聚合,用于统计每个桶内的指标。

5.1 terms (词条聚合)

terms 聚合是最常用的桶聚合之一。它根据指定字段的值对文档进行分组,每个不同的字段值都会创建一个桶。

示例:tags.keyword 字段对 product 索引中的产品进行分组,并统计每个标签下的文档数量。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "tag_bucket": {
      "terms": {
        "field": "tags.keyword",
        "size": 10,
        "order": {
          "_count": "desc"
        }
      }
    }
  }
}

代码解释:

  • "size": 0: 不返回文档,只返回聚合结果。
  • "aggs": 聚合查询的开始。
  • "tag_bucket": 我们为这个聚合操作指定的名称。
  • "terms": 指定聚合类型为 terms (词条聚合)。
  • "field": "tags.keyword": 指定要进行分组的字段为 tags.keyword。使用 .keyword 子字段是因为我们要基于标签的原始值进行分组,而不是分词后的结果。
  • "size": 10: 指定返回的桶的最大数量。默认情况下,terms 聚合会返回文档数量最多的前 10 个桶。
  • "order": { "_count": "desc" }: 指定桶的排序方式。这里按照每个桶中文档数量 (_count) 的降序 (desc) 进行排序。

结果(部分):

{
  ...
  "aggregations": {
    "tag_bucket": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 8,
      "buckets": [
        {
          "key": "性价比",
          "doc_count": 3
        },
        {
          "key": "发烧",
          "doc_count": 2
        },
        {
          "key": "大片",
          "doc_count": 2
        },
        {
          "key": "蓝光8K",
          "doc_count": 2
        },
        {
          "key": "超薄",
          "doc_count": 2
        },
		{
          "key": "割韭菜",
          "doc_count": 2
        },
        {
          "key": "120W快充",
          "doc_count": 1
        },
        {
          "key": "120HZ刷新率",
          "doc_count": 1
        },
        {
          "key": "120倍变焦",
          "doc_count": 1
        },
        {
            "key": "4G全网通",
            "doc_count": 1
        }
      ]
    }
  }
}

结果解释:

  • "buckets": 这是一个数组,包含了根据 tags.keyword 字段值分组后的桶。
  • "key": 每个桶的键,即 tags.keyword 字段的值(例如 “性价比”, “发烧”)。
  • "doc_count": 每个桶中的文档数量。
  • "doc_count_error_upper_bound":由于terms聚合默认情况下返回文档数量最多的前N个桶,这个值表示因为桶数量限制,没有被统计到的文档数量的最大可能误差值。
  • "sum_other_doc_count": 由于terms聚合默认情况下返回文档数量最多的前N个桶,这个值表示未返回的其他桶中文档数量的总和。

size 参数:

size 参数控制返回的桶的数量。 如果你想返回所有桶,可以将 size 设置为一个较大的值(例如,大于字段中不同值的数量)。 但是,请注意,如果字段的基数非常高(即有很多不同的值),返回所有桶可能会消耗大量内存。

order 参数:

order 参数控制桶的排序方式。除了按 _count 排序外,还可以:

  • _key 排序:"order": { "_key": "asc" } (按字段值升序) 或 "order": { "_key": "desc" } (按字段值降序)。
  • 按桶内指标聚合的结果排序(稍后在嵌套聚合中介绍)。

5.2 嵌套桶聚合

在实际应用中,我们经常需要进行多层级的聚合。例如,我们想先按type进行分组,然后统计每个typeprice的平均值。这种情况下我们就需要用到嵌套聚合。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "type_bucket": {
      "terms": {
        "field": "type.keyword"
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

代码解释:

  • 外层是一个terms聚合, 根据type.keyword字段进行分组。
  • 内层是一个avg聚合, 计算每个分组内price字段的平均值。
  • 内层聚合的结果会作为外层聚合每个桶的一个属性。

结果(部分):

{
  ...
  "aggregations": {
    "type_bucket": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key" : "手机",
          "doc_count" : 6,
          "avg_price" : {
            "value" : 3939.0
          }
        },
        {
          "key" : "耳机",
          "doc_count" : 3,
          "avg_price" : {
            "value" : 1465.3333333333333
          }
        },
        {
          "key" : "电视",
          "doc_count" : 2,
          "avg_price" : {
            "value" : 2998.5
          }
        }
      ]
    }
  }
}

结果解释:

  • "buckets": 这是一个数组,包含了根据 type.keyword 字段值分组后的桶。
  • "key": 每个桶的键,即 type.keyword 字段的值(例如 “手机”, “耳机”)。
  • "doc_count": 每个桶中的文档数量。
  • "avg_price": 每个桶中嵌套聚合的结果, 即该类型商品的平均价格。

通过嵌套聚合,我们可以轻松实现多层级的数据分析。我们可以根据需求自由组合不同的聚合类型,构建出非常复杂的聚合查询。

六、管道聚合 (Pipeline Aggregations)

管道聚合(Pipeline Aggregations)是一种特殊的聚合类型。它们不像指标聚合和桶聚合那样直接操作文档,而是对其他聚合的结果进行进一步的聚合。这就像在数据处理流程中添加了一个额外的“管道”,对上游聚合的输出进行处理。

6.1 什么是管道聚合?

管道聚合的核心思想是:输入是另一个聚合(或多个聚合)的输出,而不是文档本身。这使得我们可以进行诸如以下操作:

  • 找出平均价格最低的产品类别。
  • 计算每个月销售额的总和,然后找出销售额最高的月份。
  • 计算某个指标的导数或移动平均值。

管道聚合的关键参数是 buckets_path,它用于指定要作为输入的聚合的路径。

6.2 min_bucket (最小桶)

min_bucket 管道聚合用于找出包含最小值的桶。

示例: 找出平均价格最低的产品分类(基于之前嵌套聚合的结果)。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "type_bucket": {
      "terms": {
        "field": "type.keyword"
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    },
    "min_avg_price_bucket": {
      "min_bucket": {
        "buckets_path": "type_bucket>avg_price"
      }
    }
  }
}

代码解释:

  • "type_bucket": 这是一个 terms 聚合,按产品类型 (type.keyword) 分组。
  • "avg_price": 这是一个嵌套的 avg 聚合,计算每个产品类型的平均价格。
  • "min_avg_price_bucket": 这是我们定义的管道聚合的名称。
  • "min_bucket": 指定聚合类型为 min_bucket
  • "buckets_path": "type_bucket>avg_price": 这是 buckets_path 参数,它指定了要处理的聚合路径。
    • type_bucket: 表示外层的 terms 聚合。
    • >: 表示嵌套关系。
    • avg_price: 表示内层的 avg 聚合。
    • 所以,"type_bucket>avg_price" 表示我们要找到 type_bucket 聚合中,avg_price 聚合结果最小的那个桶。

结果(部分):

{
  ...
  "aggregations": {
    "type_bucket": {
      ... // 省略了 type_bucket 的详细结果
    },
    "min_avg_price_bucket": {
      "value": 1465.3333333333333,
      "keys": [
        "耳机"
      ]
    }
  }
}

结果解释:

  • "min_avg_price_bucket": 管道聚合的结果。
  • "value": 最小值 (最低的平均价格)。
  • "keys": 取得最小值的桶的key值数组, 在本例中, 平均价格最低的分类是 “耳机”。

6.3 其他管道聚合

除了 min_bucket 之外,ElasticSearch 还提供了其他几种管道聚合:

  • max_bucket: 找出包含最大值的桶。用法与min_bucket类似, 只是找出最大值。
  • avg_bucket: 计算所有桶中某个指标的平均值。
  • sum_bucket: 计算所有桶中某个指标的总和。
  • stats_bucket:一次性计算多个统计值, 类似于stats指标聚合, 但是stats_bucket是作用于桶聚合的结果之上。
  • derivative: 计算导数(例如,计算销售额的变化率)。
  • moving_avg: 计算移动平均值(例如,计算过去 7 天的平均销售额)。
  • bucket_script: 使用脚本对桶的指标进行自定义计算。
  • bucket_selector: 根据脚本过滤桶。
  • bucket_sort: 对桶进行排序。

这些管道聚合提供了更高级的数据分析功能。你可以在 ElasticSearch 的官方文档中找到关于它们的详细信息。

七、实战案例 (Practical Examples)

现在,让我们通过几个更贴近实际应用的示例,来展示如何组合不同类型的聚合,以解决真实的数据分析问题。

案例 1:统计每个产品类别中,价格最高的产品的价格,并按最高价格降序排列

这个案例结合了 terms 桶聚合、max 指标聚合和排序。

GET product/_search
{
  "size": 0, 
  "aggs": {
    "type_bucket": {
      "terms": {
        "field": "type.keyword",
        "order": {
          "max_price": "desc"
        }
      },
      "aggs": {
        "max_price": {
          "max": {
            "field": "price"
          }
        }
      }
    }
  }
}

代码解释:

  • "type_buckets": terms 聚合,按 type.keyword 字段(产品类型)分组。
  • "order": { "max_price": "desc" }: 按嵌套的 max_price 聚合的结果(即每个类别中的最高价格)进行降序排序。
  • "max_price": 嵌套的 max 聚合,计算每个类别中的最高价格。

结果(部分):

{
  ...
  "aggregations": {
    "type_buckets": {
      ...
      "buckets": [
        {
          "key" : "手机",
          "doc_count" : 6,
          "max_price" : {
            "value" : 4999.0
          }
        },
        {
          "key" : "电视",
          "doc_count" : 2,
          "max_price" : {
            "value" : 2999.0
          }
        },
        {
          "key" : "耳机",
          "doc_count" : 3,
          "max_price" : {
            "value" : 2998.0
          }
        }
      ]
    }
  }
}

案例 2:找出每个月销售额最高的日期

这个案例结合了 date_histogram 桶聚合、sum 指标聚合和 max_bucket 管道聚合。

GET /product/_search
{
  "size": 0,
  "aggs": {
    "sales_per_month": {
      "date_histogram": {
        "field": "createtime",
        "calendar_interval": "month"
      },
      "aggs": {
        "sales_per_day": {
          "date_histogram": {
            "field": "createtime",
            "calendar_interval": "day"
          },
          "aggs": {
            "daily_sales": {
              "sum": {
                "field": "price"
              }
            }
          }
        },
        "max_daily_sales": {
          "max_bucket": {
            "buckets_path": "sales_per_day>daily_sales"
          }
        }
      }
    }
  }
}

代码解释:

  1. sales_per_month (外层 date_histogram):

    • 按月对文档进行分组("calendar_interval": "month")。
    • field: “createtime”
  2. sales_per_day (内层 date_histogram):

    • 在每个月的桶内,再按天对文档进行分组("calendar_interval": "day")。
    • field: “createtime”
  3. daily_sales (指标聚合):

    • 在每个天的桶内,计算当天的销售总额("sum": { "field": "price" })。
  4. max_daily_sales (管道聚合):

    • 使用 max_bucket 管道聚合。
    • "buckets_path": "sales_per_day>daily_sales": 找出每个月内,daily_sales (销售总额) 最高的那个 sales_per_day (天) 桶。

结果 (部分):

{
  ...
  "aggregations": {
    "sales_per_month": {
      "buckets": [
        {
          "key_as_string": "2020-05-01T00:00:00.000Z",
          "key": 1588291200000,
          "doc_count": 1,
          "sales_per_day": {
            ...
          },
          "max_daily_sales": {
            "value": 4999.0,
            "keys": [
              "2020-05-21T00:00:00.000Z"
            ]
          }
        },
        {
          "key_as_string": "2020-06-01T00:00:00.000Z",
          "key": 1590969600000,
          "doc_count": 2,
           "sales_per_day": {
            ...
          },
          "max_daily_sales": {
            "value": 2999.0,
             "keys": [
              "2020-06-20T00:00:00.000Z"
            ]
          }
        },
		...
      ]
    }
  }
}

结果显示, 对于每个月, 销售额最高的那一天的日期和销售额都被找了出来. 例如, 在2020年5月, 销售额最高的那一天是2020-05-21, 销售额是4999.

这两个案例展示了如何将不同类型的聚合组合起来,以解决更复杂的数据分析问题。 ElasticSearch 聚合的强大之处在于其灵活性和可组合性,你可以根据自己的需求设计出各种各样的聚合查询。\

八、总结 (Conclusion)

在本教程中,我们深入探讨了 Elasticsearch 7.10 中聚合查询的基础知识。聚合查询是 Elasticsearch 中进行数据分析的强大工具,它能够帮助你从海量数据中提取出有价值的统计信息和洞察。

我们学习了:

  • 聚合查询的基本概念和结构: 了解了聚合查询与搜索查询的区别,以及聚合查询的基本 JSON 结构。
  • 三种核心的聚合类型:
    • 指标聚合 (Metrics Aggregations): 用于计算单个数值指标,如平均值、最小值、最大值、总和、去重计数等。
    • 桶聚合 (Bucket Aggregations): 用于将文档分组到不同的桶中,如按字段值分组、按日期范围分组等。
    • 管道聚合 (Pipeline Aggregations): 用于对其他聚合的结果进行进一步的聚合,如找出最大值、最小值、计算导数等。
  • 各种常用的聚合函数: avg, min, max, sum, stats, value_count, cardinality, terms, min_bucket, max_bucket 等。
  • 如何使用嵌套聚合: 将不同类型的聚合组合起来,实现更复杂的数据分析。
  • 实战案例: 通过两个实际案例,展示了如何运用聚合查询解决真实的数据分析问题。

Elasticsearch 的聚合功能远不止于此。本文只是一个入门指南,涵盖了最基础和最常用的部分。要充分发挥 Elasticsearch 聚合的威力,你需要不断学习和实践,探索更高级的聚合类型和用法。

进一步学习的建议:

  • 阅读 Elasticsearch 官方文档: 官方文档是学习 ElasticSearch 的最佳资源。关于聚合的详细文档,请参考
  • 尝试更多的聚合类型: 除了本文介绍的聚合类型外,ElasticSearch 还提供了许多其他聚合类型,如 date_histogramrangefiltersgeo_distancepercentilestop_hits 等等。
  • 练习、练习、再练习: 最好的学习方法就是实践。尝试使用不同的数据集和不同的聚合组合,来解决各种数据分析问题。

希望本文能帮助你入门 Elasticsearch 聚合查询。祝你在数据分析的道路上不断进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/980859.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TVbox蜂蜜影视:智能电视观影新选择,简洁界面与强大功能兼具

蜂蜜影视是一款基于猫影视开源项目 CatVodTVJarLoader 开发的智能电视软件&#xff0c;专为追求简洁与高效观影体验的用户设计。该软件从零开始编写&#xff0c;界面清爽&#xff0c;操作流畅&#xff0c;特别适合在智能电视上使用。其最大的亮点在于能够自动跳过失效的播放地址…

【word】电子签名设置、保存和调用

设置电子签名&#xff1a;将扫描版或照片 转化为 word的电子签名 保存电子签名&#xff1a;将上述电子签名 存储到 word资料库中 调用电子签名&#xff1a;在正文中使用 快捷键 快速调用word电子签名 1. 设置电子签名 1.1 手写版签名 1.2 插入到word 插入 - 图片 1.3 着色效…

KVM虚拟机磁盘创建探究-1

在使用 virt-install 命令时&#xff0c;像 --disk path/var/lib/libvirt/images/vm1.qcow2,size20 这样的参数配置会自动创建指定路径和大小的磁盘镜像文件&#xff0c;不需要再单独使用 qemu-img 去创建。 详细解释 当你使用 virt-install 并指定 --disk 参数时&#xff0c…

第三十三:6.3. 【mitt】 任意组件通讯

概述&#xff1a;与消息订阅与发布&#xff08;pubsub&#xff09;功能类似&#xff0c;可以实现任意组件间通信。 // 引入mitt import mitt from "mitt";// 创建emitter const emitter mitt()/*// 绑定事件emitter.on(abc,(value)>{console.log(abc事件被触发,…

Android Stuido 调整左侧文件导航栏文字大小

Android Studio左侧文件导航栏文字大小默认比较小&#xff0c;这里记录下调整的路径&#xff1a; File-->Settings-->Appearance & Behavior-->Appearance-->勾上“Use custom font:” 就可以调整文字大小了&#xff0c;然后确定就好了。

大模型学习笔记------LLM模型开发流程

大模型学习笔记------LLM模型开发流程 1、总体开发流程2、各部分说明3、总结 LLM(Large Language Model)模型&#xff0c;即大型语言模型是大模型中极其重要的分支。它包含了GPT、BERT、Gemini、Qwen、Llama等&#xff0c;这些大模型衍生了相当多的各种改进版本。这些大模型的开…

剑指 Offer II 040. 矩阵中最大的矩形

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20040.%20%E7%9F%A9%E9%98%B5%E4%B8%AD%E6%9C%80%E5%A4%A7%E7%9A%84%E7%9F%A9%E5%BD%A2/README.md 剑指 Offer II 040. 矩阵中最大的矩形 题目描述 给定一个由 …

【含文档+PPT+源码】基于SpringBoot+Vue医药知识学习与分享平台的设计与实现

项目介绍 本课程演示的是一款 基于SpringBootVue医药知识学习与分享平台的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运…

基于提示驱动的潜在领域泛化的医学图像分类方法(Python实现代码和数据分析)

摘要 医学图像分析中的深度学习模型易受数据集伪影偏差、相机差异、成像设备差异等导致的分布偏移影响&#xff0c;导致在真实临床环境中诊断不可靠。领域泛化&#xff08;Domain Generalization, DG&#xff09;方法旨在通过多领域训练提升模型在未知领域的性能&#xff0c;但…

【监督学习】支持向量机步骤及matlab实现

支持向量机 &#xff08;四&#xff09;支持向量机1.算法步骤2. MATLAB 实现参考资料 &#xff08;四&#xff09;支持向量机 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种用于分类、回归分析以及异常检测的监督学习模型。SVM特别擅长处理高维空间的…

数据集/API 笔记:湿球黑球温度(WBGT)观测数据

data.gov.sg WBGT是一个综合指标&#xff0c;考虑了气温、湿度、风速和太阳辐射&#xff0c;与气温不同。 报告的WBGT是过去15分钟内的平均值&#xff0c;每15分钟更新一次。 API 调用 curl --request GET \--url https://api-open.data.gov.sg/v2/real-time/api/weather …

基于 DataEase 的企业数据分析实践

1. 前言 在上一篇《基于 Selenium 实现的必应企业信息抓取工具》中&#xff0c;成功实现了对企业信息的批量抓取与导出。接下来&#xff0c;将对这些数据进行深入分析&#xff0c;包括地区分布、所属行业、规模大小等维度。其中&#xff0c;最直接的需求是统计每个省份的企业数…

教资信息技术之数据库技术

一、概述 1.1 基本概念 数据&#xff1a;描述事物的符号记录称为数据 数据库&#xff1a;长期存储在计算机内、有组织的、可共享的大量数据的集合。 数据库管理系统&#xff1a;位于用户和操作系统之间的一层数据管理软件 数据库系统&#xff1a;数据库系统是由数据库、数据…

JavaAPI(反射)

反射机制简介 获取一个类的实例对象&#xff0c;一般用new关键字来调用构造器获取实例&#xff0c;但是使用new有优点也有缺点。 优点&#xff1a; 性能高&#xff0c;JVM已经对这种调用进行了优化。不需要额外的权限检查、直接调用构造器获取实例、简单方便 缺点&#xff…

零信任沙箱:为网络安全筑牢“隔离墙”

在数字化浪潮汹涌澎湃的今天&#xff0c;网络安全如同一艘船在波涛汹涌的大海中航行&#xff0c;面临着重重挑战。数据泄露、恶意软件攻击、网络钓鱼等安全威胁层出不穷&#xff0c;让企业和个人用户防不胜防。而零信任沙箱&#xff0c;就像是一座坚固的“隔离墙”&#xff0c;…

开源嵌入式实时操作系统NuttX介绍

一、NuttX RTOS的发展历程&#xff1a;从个人项目到Apache顶级开源项目 NuttX 是一款轻量级、可扩展的实时操作系统&#xff08;RTOS&#xff09;&#xff0c;其发展历程堪称开源社区的经典案例。 起源与初创&#xff08;2003-2007&#xff09; NuttX 由 Gregory Nutt 于2003…

【蓝桥杯单片机】第十二届省赛

一、真题 二、模块构建 1.编写初始化函数(init.c) void Cls_Peripheral(void); 关闭led led对应的锁存器由Y4C控制关闭蜂鸣器和继电器 由Y5C控制 2.编写LED函数&#xff08;led.c&#xff09; void Led_Disp(unsigned char ucLed); 将ucLed取反的值赋给P0 开启锁存器…

清华大学AI赋能医药代表销售培训讲师专家培训师唐兴通Deepseek医药数字化营销大健康数字化转型医药新媒体营销

唐兴通 数字商业创新实践专家、数字营销与销售顾问 沃顿商学院特邀演讲嘉宾&#xff5c;美国营销协会艾菲奖评委 核心专长&#xff1a; AI商业化应用、新药上市、数字化转型、医药数字营销创新、医药新销售能力体系打造、 教学经历&#xff1a;从教20年&#xff0c;执教12所…

关于后端使用Boolean或boolean时前端收到的参数的区别

当后端使用的是Boolean时&#xff0c;调用的方法是setIsLoginUser&#xff0c;前端收到的参数的参数名是isLoginUser 而当后端使用的是boolean时&#xff0c;调用的方法是setLoginUser&#xff0c;前端收到的参数的参数名是loginUser 封装类和基本数据类型在使用时需要注意这…

【二.提示词工程与实战应用篇】【3.Prompt调优:让AI更懂你的需求】

最近老张在朋友圈秀出用AI生成的国风水墨画,隔壁王姐用AI写了份惊艳全场的年终总结,就连楼下小卖部老板都在用AI生成营销文案。你看着自己跟AI对话时满屏的"我不太明白您的意思",是不是怀疑自己买了台假电脑?别慌,这可能是你的打开方式不对。今天咱们就聊聊这个…