管道聚合编辑

管道聚合作用于其他聚合产生的输出,而不是文档集,向输出树添加信息。管道聚合有很多不同的类型,每种类型都从其他聚合中计算不同的信息,但这些类型可以分为两个类别

父级
一类管道聚合,它使用其父级聚合的输出,并能够计算新的桶或新的聚合以添加到现有桶中。
兄弟
管道聚合使用兄弟聚合的输出,并能够计算一个新的聚合,该聚合将与兄弟聚合位于同一级别。

管道聚合可以使用 buckets_path 参数引用它们执行计算所需的聚合,以指示所需指标的路径。定义这些路径的语法可以在下面的 buckets_path 语法 部分找到。

管道聚合不能有子聚合,但根据类型,它可以在 buckets_path 中引用另一个管道,允许管道聚合进行链式操作。例如,可以将两个导数链接在一起以计算二阶导数(即导数的导数)。

由于管道聚合只是添加到输出中,因此在链接管道聚合时,每个管道聚合的输出都将包含在最终输出中。

buckets_path 语法编辑

大多数管道聚合需要另一个聚合作为其输入。输入聚合通过 buckets_path 参数定义,该参数遵循特定格式

AGG_SEPARATOR       =  `>` ;
METRIC_SEPARATOR    =  `.` ;
AGG_NAME            =  <the name of the aggregation> ;
METRIC              =  <the name of the metric (in case of multi-value metrics aggregation)> ;
MULTIBUCKET_KEY     =  `[<KEY_NAME>]`
PATH                =  <AGG_NAME><MULTIBUCKET_KEY>? (<AGG_SEPARATOR>, <AGG_NAME> )* ( <METRIC_SEPARATOR>, <METRIC> ) ;

例如,路径 "my_bucket>my_stats.avg" 将指向 "my_stats" 指标中的 avg 值,该指标包含在 "my_bucket" 桶聚合中。

以下是一些其他示例

  • multi_bucket["foo"]>single_bucket>multi_metric.avg 将指向 "multi_bucket" 多桶聚合的 "foo" 桶中,"single_bucket" 单桶内的 "multi_metric" 聚合中的 avg 指标。
  • agg1["foo"]._count 将获取多桶聚合 "multi_bucket""foo" 桶的 _count 指标

路径相对于管道聚合的位置;它们不是绝对路径,并且路径不能返回到聚合树的“上层”。例如,此导数嵌入在 date_histogram 中,并引用“兄弟”指标 "the_sum"

response = client.search(
  body: {
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'timestamp',
          calendar_interval: 'day'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'lemmings'
            }
          },
          the_deriv: {
            derivative: {
              buckets_path: 'the_sum'
            }
          }
        }
      }
    }
  }
)
puts response
POST /_search
{
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "lemmings" }              
        },
        "the_deriv": {
          "derivative": { "buckets_path": "the_sum" } 
        }
      }
    }
  }
}

指标称为 "the_sum"

buckets_path 通过相对路径 "the_sum" 引用指标

buckets_path 也用于兄弟管道聚合,其中聚合位于一系列桶的“旁边”,而不是嵌入在“内部”。例如,max_bucket 聚合使用 buckets_path 来指定嵌入在兄弟聚合中的指标

response = client.search(
  body: {
    aggregations: {
      sales_per_month: {
        date_histogram: {
          field: 'date',
          calendar_interval: 'month'
        },
        aggregations: {
          sales: {
            sum: {
              field: 'price'
            }
          }
        }
      },
      max_monthly_sales: {
        max_bucket: {
          buckets_path: 'sales_per_month>sales'
        }
      }
    }
  }
)
puts response
POST /_search
{
  "aggs": {
    "sales_per_month": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "month"
      },
      "aggs": {
        "sales": {
          "sum": {
            "field": "price"
          }
        }
      }
    },
    "max_monthly_sales": {
      "max_bucket": {
        "buckets_path": "sales_per_month>sales" 
      }
    }
  }
}

buckets_path 指示此 max_bucket 聚合,我们希望 sales_per_month 日期直方图中 sales 聚合的最大值。

如果兄弟管道聚合引用多桶聚合,例如 terms 聚合,它还可以选择从多桶中选择特定的键。例如,bucket_script 可以选择两个特定的桶(通过它们的桶键)来执行计算

response = client.search(
  body: {
    aggregations: {
      sales_per_month: {
        date_histogram: {
          field: 'date',
          calendar_interval: 'month'
        },
        aggregations: {
          sale_type: {
            terms: {
              field: 'type'
            },
            aggregations: {
              sales: {
                sum: {
                  field: 'price'
                }
              }
            }
          },
          hat_vs_bag_ratio: {
            bucket_script: {
              buckets_path: {
                hats: "sale_type['hat']>sales",
                bags: "sale_type['bag']>sales"
              },
              script: 'params.hats / params.bags'
            }
          }
        }
      }
    }
  }
)
puts response
POST /_search
{
  "aggs": {
    "sales_per_month": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "month"
      },
      "aggs": {
        "sale_type": {
          "terms": {
            "field": "type"
          },
          "aggs": {
            "sales": {
              "sum": {
                "field": "price"
              }
            }
          }
        },
        "hat_vs_bag_ratio": {
          "bucket_script": {
            "buckets_path": {
              "hats": "sale_type['hat']>sales",   
              "bags": "sale_type['bag']>sales"    
            },
            "script": "params.hats / params.bags"
          }
        }
      }
    }
  }
}

buckets_path 选择帽子和包桶(通过 ['hat']/['bag']`)专门用于脚本中,而不是从 sale_type 聚合中获取所有桶

特殊路径编辑

除了指向指标之外,buckets_path 还可以使用特殊的 "_count" 路径。这指示管道聚合使用文档计数作为其输入。例如,可以在每个桶的文档计数上计算导数,而不是特定指标

response = client.search(
  body: {
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'timestamp',
          calendar_interval: 'day'
        },
        aggregations: {
          the_deriv: {
            derivative: {
              buckets_path: '_count'
            }
          }
        }
      }
    }
  }
)
puts response
POST /_search
{
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      },
      "aggs": {
        "the_deriv": {
          "derivative": { "buckets_path": "_count" } 
        }
      }
    }
  }
}

通过使用 _count 而不是指标名称,我们可以计算直方图中文档计数的导数

buckets_path 还可以使用 "_bucket_count" 并指向多桶聚合,以在管道聚合中使用该聚合返回的桶数,而不是指标。例如,bucket_selector 可以在这里用于过滤掉不包含内部 terms 聚合的桶的桶

response = client.search(
  index: 'sales',
  body: {
    size: 0,
    aggregations: {
      histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: 'day'
        },
        aggregations: {
          categories: {
            terms: {
              field: 'category'
            }
          },
          min_bucket_selector: {
            bucket_selector: {
              buckets_path: {
                count: 'categories._bucket_count'
              },
              script: {
                source: 'params.count != 0'
              }
            }
          }
        }
      }
    }
  }
)
puts response
POST /sales/_search
{
  "size": 0,
  "aggs": {
    "histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "day"
      },
      "aggs": {
        "categories": {
          "terms": {
            "field": "category"
          }
        },
        "min_bucket_selector": {
          "bucket_selector": {
            "buckets_path": {
              "count": "categories._bucket_count" 
            },
            "script": {
              "source": "params.count != 0"
            }
          }
        }
      }
    }
  }
}

通过使用 _bucket_count 而不是指标名称,我们可以过滤掉 histo 桶,其中它们不包含 categories 聚合的桶

处理聚合名称中的点编辑

支持另一种语法来处理名称中包含点的聚合或指标,例如 99.9th 百分位数。此指标可以称为

"buckets_path": "my_percentile[99.9]"

处理数据中的间隙编辑

现实世界中的数据通常很嘈杂,有时包含 间隙 — 数据根本不存在的地方。这可能由于多种原因发生,最常见的原因是

  • 落入桶中的文档不包含必需的字段
  • 没有文档匹配一个或多个桶的查询
  • 正在计算的指标无法生成值,可能是因为另一个依赖桶缺少值。一些管道聚合有必须满足的特定要求(例如,导数无法为第一个值计算指标,因为没有先前的值,HoltWinters 移动平均需要“预热”数据才能开始计算,等等)

间隙策略是一种机制,用于告知管道聚合在遇到“间隙”或丢失数据时所需的行为。所有管道聚合都接受 gap_policy 参数。目前有两种间隙策略可供选择

跳过
此选项将丢失数据视为桶不存在。它将跳过桶并继续使用下一个可用值进行计算。
插入零
此选项将用零 (0) 替换丢失的值,管道聚合计算将照常进行。
保留值
此选项类似于跳过,除了如果指标提供非空、非 NaN 值,则使用此值,否则将跳过空桶。