ElasticSearch - Bucket Script 使用指南

文章目录

  • 官方文档
  • [Bucket Script 官文](#Bucket Script 官文)
  • [1. 什么是 ElasticSearch 中的 Bucket Script?](#1. 什么是 ElasticSearch 中的 Bucket Script?)
  • [2. 适用场景](#2. 适用场景)
  • [3. Bucket Script 的基本结构](#3. Bucket Script 的基本结构)
  • [4. 关键参数详解](#4. 关键参数详解)
  • [5. 示例](#5. 示例)
    • [官方示例:计算每月 T 恤销售额占总销售额的比率百分比](#官方示例:计算每月 T 恤销售额占总销售额的比率百分比)
    • 示例计算:点击率 (CTR)
  • [6. 注意事项与限制](#6. 注意事项与限制)
  • [7. 最佳实践](#7. 最佳实践)

官方文档

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html


Bucket Script 官文

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-pipeline-bucket-script-aggregation.html



  1. 介绍 Bucket Script 的概念和作用
  2. 展示基本使用场景,帮助理解其核心原理
  3. 通过实例展示如何实现 Bucket Script
  4. 总结关键要点与最佳实践

1. 什么是 ElasticSearch 中的 Bucket Script?

Bucket Script 是 ElasticSearch 中一种强大的管道聚合(pipeline aggregation),允许你基于已有的聚合结果执行数学计算。 它用于对多个 桶(buckets) 内的数据进行后处理,适合在聚合结果上进行进一步计算,比如计算比率、加权平均等。


2. 适用场景

  • 计算字段的 百分比(如收入增长率)
  • 生成两个字段之间的 比值(如点击率 CTR)
  • 在聚合结果中求得更复杂的 数学表达式
  • 处理基于时间序列的数据分析,例如 同比、环比 增长计算

3. Bucket Script 的基本结构

Bucket Script 聚合的基本结构如下:

json 复制代码
{
  "aggs": {
    "sales_per_month": {
      "date_histogram": {
        "field": "order_date",
        "calendar_interval": "month"
      },
      "aggs": {
        "total_sales": {
          "sum": {
            "field": "sales"
          }
        },
        "total_units": {
          "sum": {
            "field": "units_sold"
          }
        },
        "sales_per_unit": {
          "bucket_script": {
            "buckets_path": {
              "sales": "total_sales",
              "units": "total_units"
            },
            "script": "params.sales / params.units"
          }
        }
      }
    }
  }
}
  1. sales_per_month :使用 date_histogram 按月份进行分桶。
  2. total_salestotal_units:分别计算总销售额和总售出单位数。
  3. sales_per_unit :使用 bucket_script 在每个桶内计算销售额与售出单位的比值。

4. 关键参数详解

  • buckets_path:指定需要参与计算的聚合结果路径,路径指向的聚合必须出现在当前或上层的桶中。
  • script :定义计算逻辑,使用 Painless 脚本语言 编写。

5. 示例

官方示例:计算每月 T 恤销售额占总销售额的比率百分比

java 复制代码
PUT /sales
{
  "mappings": {
    "properties": {
      "type": {
        "type": "keyword"
      },
      "price": {
        "type": "float"
      },
      "date": {
        "type": "date"
      }
    }
  }
}


POST /sales/_bulk
{ "index": { "_index": "sales" } }
{ "type": "t-shirt", "price": 19.99, "date": "2024-01-05" }
{ "index": { "_index": "sales" } }
{ "type": "t-shirt", "price": 25.50, "date": "2024-01-15" }
{ "index": { "_index": "sales" } }
{ "type": "jeans", "price": 49.99, "date": "2024-01-20" }
{ "index": { "_index": "sales" } }
{ "type": "t-shirt", "price": 15.99, "date": "2024-02-01" }
{ "index": { "_index": "sales" } }
{ "type": "shoes", "price": 75.00, "date": "2024-02-10" }
{ "index": { "_index": "sales" } }
{ "type": "t-shirt", "price": 29.99, "date": "2024-02-15" }

POST sales/_search

POST /sales/_search
{
  "size": 0,
  "aggs": {
    "sales_per_month": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "month"
      },
      "aggs": {
        "total_sales": {
          "sum": {
            "field": "price"
          }
        },
        "t-shirts": {
          "filter": {
            "term": {
              "type": "t-shirt"
            }
          },
          "aggs": {
            "sales": {
              "sum": {
                "field": "price"
              }
            }
          }
        },
        "t-shirt-percentage": {
          "bucket_script": {
            "buckets_path": {
              "tShirtSales": "t-shirts>sales",
              "totalSales": "total_sales"
            },
            "script": "params.tShirtSales / params.totalSales * 100"
          }
        }
      }
    }
  }
}

此查询的目的是:

  1. 统计每个月的总销售额
  2. 计算"T-shirt"类型商品的销售额
  3. 计算"T-shirt"销售额占总销售额的百分比

  1. "size": 0

    • 表示这次查询不返回任何文档,仅返回聚合结果。
  2. 聚合:sales_per_month

    • 使用 date_histogram 来按月对销售数据进行分桶:

      json 复制代码
      "date_histogram": {
        "field": "date",
        "calendar_interval": "month"
      }
    • 字段 date 决定销售的日期。calendar_interval 设置为 "month",意味着每个月作为一个桶。

  3. 聚合:total_sales

    • 计算每个月的总销售额

      json 复制代码
      "total_sales": {
        "sum": {
          "field": "price"
        }
      }
    • 字段 price 表示商品价格,通过 sum 聚合计算总和。

  4. 过滤聚合:t-shirts

    • 使用 filter 过滤出类型为 t-shirt 的销售:

      json 复制代码
      "filter": {
        "term": {
          "type": "t-shirt"
        }
      }
    • 嵌套的sum聚合 计算T-shirt类型商品的销售额:

      json 复制代码
      "sales": {
        "sum": {
          "field": "price"
        }
      }
  5. 桶脚本聚合:t-shirt-percentage

    • 计算T-shirt销售额占总销售额的百分比

      json 复制代码
      "bucket_script": {
        "buckets_path": {
          "tShirtSales": "t-shirts>sales",
          "totalSales": "total_sales"
        },
        "script": "params.tShirtSales / params.totalSales * 100"
      }
    • buckets_path 用于从其他聚合中引用路径:

      • "tShirtSales" 引用的是 t-shirts>sales 聚合。
      • "totalSales" 引用的是 total_sales 聚合。
    • script 执行的逻辑是:T-shirt销售额 / 总销售额 * 100,计算百分比。


查询结果格式

java 复制代码
{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "sales_per_month" : {
      "buckets" : [
        {
          "key_as_string" : "2024-01-01T00:00:00.000Z",
          "key" : 1704067200000,
          "doc_count" : 3,
          "total_sales" : {
            "value" : 95.48000144958496
          },
          "t-shirts" : {
            "doc_count" : 2,
            "sales" : {
              "value" : 45.489999771118164
            }
          },
          "t-shirt-percentage" : {
            "value" : 47.64348458366713
          }
        },
        {
          "key_as_string" : "2024-02-01T00:00:00.000Z",
          "key" : 1706745600000,
          "doc_count" : 3,
          "total_sales" : {
            "value" : 120.97999954223633
          },
          "t-shirts" : {
            "doc_count" : 2,
            "sales" : {
              "value" : 45.97999954223633
            }
          },
          "t-shirt-percentage" : {
            "value" : 38.00628179551602
          }
        }
      ]
    }
  }
}

这个结果表示:

  • 2024年1月的总销售额为 ** 95.48**。
  • 其中 45.48 元来自于 T-shirt。
  • T-shirt 的销售占比为 ** 47.6%**。


示例计算:点击率 (CTR)

假设有个广告展示量和点击量的聚合,想计算每个广告的点击率:

json 复制代码
{
  "aggs": {
    "ads": {
      "terms": {
        "field": "ad_id"
      },
      "aggs": {
        "impressions": {
          "sum": {
            "field": "impression_count"
          }
        },
        "clicks": {
          "sum": {
            "field": "click_count"
          }
        },
        "ctr": {
          "bucket_script": {
            "buckets_path": {
              "clicks": "clicks",
              "impressions": "impressions"
            },
            "script": "params.clicks / params.impressions"
          }
        }
      }
    }
  }
}

逻辑:

  • 使用 terms 聚合按广告 ID 分组
  • 分别计算广告的展示量 (impressions) 和点击量 (clicks)
  • 使用 bucket_script 聚合计算 点击率(CTR) = 点击量 / 展示量

6. 注意事项与限制

  1. 性能影响:由于 Bucket Script 在已有聚合结果上执行计算,处理大量桶时可能会导致性能下降。
  2. 路径依赖buckets_path 必须引用当前层级内或父层级的聚合结果,不能跨层级引用。
  3. 脚本限制:ElasticSearch 默认使用 Painless 脚本, 确保脚本逻辑高效,否则可能导致查询超时。
  4. 溢出处理:注意在脚本中处理除零异常或数据溢出。

7. 最佳实践

  • 数据过滤:提前过滤无关数据,减少参与计算的桶数。
  • 逐步聚合:将复杂计算分解为多个简单的管道聚合,以提高可读性和维护性。
  • 性能调优 :如果计算复杂,可以限制返回结果的桶数(例如通过 size 限制 top-N 结果)。

相关推荐
码农易小航3 小时前
封装ES高亮Yxh-Es
大数据·elasticsearch·搜索引擎
TechCraftsman数据库专栏3 小时前
为什么需要 ElasticSearch
数据库·elasticsearch
程序员爱中国3 小时前
Elasticsearch - 基础入门篇
大数据·elasticsearch·搜索引擎
蜡笔小柯南9 小时前
Elasticsearch 安装教程:驾驭数据海洋的星际导航仪
大数据·elasticsearch·jenkins
寰梦9 小时前
es安装拼音分词后Kibana出现内存错误
大数据·elasticsearch·jenkins
Elastic 中国社区官方博客11 小时前
将你的 Kibana Dev Console 请求导出到 Python 和 JavaScript 代码
大数据·开发语言·前端·javascript·python·elasticsearch·ecmascript
御前一品带刀侍卫20 小时前
elasticsearch基础
大数据·elasticsearch·搜索引擎
武子康21 小时前
大数据-191 Elasticsearch - ES 集群模式 配置启动 规划调优
java·大数据·elk·elasticsearch·搜索引擎·全文检索
落落落sss21 小时前
es实现自动补全
大数据·服务器·elasticsearch·搜索引擎·全文检索