Skip to main content
 首页 » 编程设计

深入理解Elasticsearch Pipeline聚集(2)

2022年07月19日142虾米哥

深入理解Elasticsearch Pipeline聚集(2)

前文中我们讨论管道聚集的结构,带你学习了几个典型的管道聚集类型:导数、累加求和等。

本文我们继续讨论管道聚集分析,主要包括统计、移动平均、移动函数、百分位、分组排序以及分组脚本等。示例数据仍然使用上文中的数据,这里不再说明。

1. 统计管道聚集

在度量聚集中,统计聚集计算索引中数值类型的统计指标,包括最小、最大、平均、求和以及次数。elasticsearch也提供了对其他聚集产生的分组计算统计指标,当stats聚合所需的值必须首先使用其他聚集计算产生每个分组时,则需要使用统计管道聚集。请看示例:

GET /traffic_stats/_search 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                } 
            } 
        }, 
        "stats_monthly_visits": { 
            "stats_bucket": { 
                "buckets_path": "visits_per_month>total_visits"  
            } 
        } 
    } 
} 

这个查询首先生成日期直方图,计算所有月份的访问量,生成多个分组;接下来使用stats管道聚集计算这些分组的统计指标,响应结果如下:

{ 
  "took" : 120, 
  "timed_out" : false, 
  "_shards" : { 
    "total" : 1, 
    "successful" : 1, 
    "skipped" : 0, 
    "failed" : 0 
  }, 
  "hits" : { 
    "total" : { 
      "value" : 27, 
      "relation" : "eq" 
    }, 
    "max_score" : null, 
    "hits" : [ ] 
  }, 
  "aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2018-10-01T00:00:00.000Z", 
          "key" : 1538352000000, 
          "doc_count" : 3, 
          "total_visits" : { 
            "value" : 2060.0 
          } 
        }, 
        { 
          "key_as_string" : "2018-11-01T00:00:00.000Z", 
          "key" : 1541030400000, 
          "doc_count" : 3, 
          "total_visits" : { 
            "value" : 2141.0 
          } 
        }, 
        { 
          "key_as_string" : "2018-12-01T00:00:00.000Z", 
          "key" : 1543622400000, 
          "doc_count" : 3, 
          "total_visits" : { 
            "value" : 2949.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-01-01T00:00:00.000Z", 
          "key" : 1546300800000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 1844.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-02-01T00:00:00.000Z", 
          "key" : 1548979200000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2411.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-03-01T00:00:00.000Z", 
          "key" : 1551398400000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3103.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-04-01T00:00:00.000Z", 
          "key" : 1554076800000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2639.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-05-01T00:00:00.000Z", 
          "key" : 1556668800000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2212.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-06-01T00:00:00.000Z", 
          "key" : 1559347200000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2661.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-07-01T00:00:00.000Z", 
          "key" : 1561939200000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2887.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-08-01T00:00:00.000Z", 
          "key" : 1564617600000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2966.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3121.0 
          } 
        } 
      ] 
    }, 
    "stats_monthly_visits" : { 
      "count" : 12, 
      "min" : 1844.0, 
      "max" : 3121.0, 
      "avg" : 2582.8333333333335, 
      "sum" : 30994.0 
    } 
  } 
} 

统计管道聚集执行对日期直方图的每个分组计算各个统计指标,并附加在响应结果的后面。

对于扩展统计聚集逻辑一样,只是返回一些额外指标,如方差、标准差、平方和等,稍微调整下上面的示例使用扩展统计:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                } 
            } 
        }, 
        "stats_monthly_visits": { 
            "extended_stats_bucket": { 
                "buckets_path": "visits_per_month>total_visits"  
            } 
        } 
    } 
} 

响应结果只是最后增加几项指标:

    "stats_monthly_visits" : { 
      "count" : 12, 
      "min" : 1844.0, 
      "max" : 3121.0, 
      "avg" : 2582.8333333333335, 
      "sum" : 30994.0, 
      "sum_of_squares" : 8.21767E7, 
      "variance" : 177030.30555555597, 
      "std_deviation" : 420.7496946588981, 
      "std_deviation_bounds" : { 
        "upper" : 3424.3327226511296, 
        "lower" : 1741.3339440155373 
      } 
    } 

2. 百分位分组聚集

百分位统计指标表示有多少值落入百分位内,如:第65百分位是65%的观测值位于该值以下。
简单百分位度量聚集计算索引中数值类型字段对于百分位。

一些场景中使用如日期直方图生成分组,然后对这些分组产生的值应用百分位统计。这种情况下即可以基于父聚集也可以基于兄弟聚集计算百分位统计。请看示例:

GET /traffic_stats/_search?size=0 
{ 
  "aggs" : { 
    "visits_per_month" : { 
      "date_histogram" : { 
          "field" : "date", 
          "interval" : "month" 
      }, 
      "aggs": { 
            "percentiles_monthly_visits": { 
              "percentiles": { 
                  "field": "visits",  
                  "percents": [ 15.0, 50.0, 75.0, 99.0 ]  
              } 
            } 
        } 
    } 
  } 
} 

这时直接对日期分组内中每个中文档进行百分位计算。下面另一个示例先对每个日期分组求和,在对这些分组和计算百分位:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                } 
            } 
        }, 
        "percentiles_monthly_visits": { 
            "percentiles_bucket": { 
                "buckets_path": "visits_per_month>total_visits", 
                "percents": [ 15.0, 50.0, 75.0, 99.0 ]  
            } 
        } 
    } 
} 

与正常百分位统计类似,也可以设置一组百分位,这里设置了15th, 50th, 75th, 99th 四个。运行结果会在追加所有分组的百分位统计:

"percentiles_monthly_visits" : { 
    "values" : { 
    "15.0" : 2141.0, 
    "50.0" : 2661.0, 
    "75.0" : 2949.0, 
    "99.0" : 3121.0 
    } 
} 

通过结果可以看出所有月份中99%的访问量都在3121次以下。

3. 移动平均聚集

移动平均或滚动平均是一个计算技术,它构造完整数据集的一系列平均值子集。子集通常称为窗口大小。事实上,窗口大小表示每个迭代中数据的数量。在每个迭代中,算法计算窗口内所有数的平均值,然后向前滑动,排除前面子集的第一个数,包括下一个子集的第一个数。这种方法称为移动平均。

举例:给定[1, 5, 8, 23, 34, 28, 7, 23, 20, 19],我们可以计算简单移动平均,设定窗口为5:

  • (1 + 5 + 8 + 23 + 34) / 5 = 14.2
  • (5 + 8 + 23 + 34+ 28) / 5 = 19.6
  • (8 + 23 + 34 + 28 + 7) / 5 = 20
  • ……

移动平均通常用于时间序列数据,抹平短期波动、特出长期趋势。主要为了消除高频波动或随机噪声数据,避免低频趋势明显。

  • 移动平均模型

moving_avg聚集支持5中移动平均模型:simple, linear, exponentially weighted(ewma), holt-linear, holt-winters。这些模型在窗口值的加权方式上有所不同。

随着数据值离现在越远(即窗口从它们滑走),权重可能会变得不同。我们可以通过model参数设置不同模型计算移动平均聚集。

下面章节我们主要讨论 simple, linear, and exponentially weighted (ewma) 三种常用模型,其他模型读者可参考官方文档。

3.1. 简单模型

simple模型首先计算所有窗口内数据值之和,然后除以窗口大小。也就是说,该模型简单计算每个窗口数据集的算数平均数。

下面示例使用simple模型,设置窗口大小为30.聚集将对日期直方图生成的分组计算移动平均。

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "the_movavg":{ 
                   "moving_avg":{ 
                      "buckets_path": "total_visits", 
                      "window" : 30, 
                      "model" : "simple" 
                    } 
                 } 
            } 
        } 
    } 
} 

响应结果为:

"aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
       ... 
        { 
          "key_as_string" : "2019-08-01T00:00:00.000Z", 
          "key" : 1564617600000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2966.0 
          }, 
          "the_movavg" : { 
            "value" : 2490.7 
          } 
        }, 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3121.0 
          }, 
          "the_movavg" : { 
            "value" : 2533.909090909091 
          } 
        } 
      ] 
    } 
  } 

窗口大小能改变移动平均的结果。窗口大小较小时("window": 10),将紧紧遵循原始数据,仅平滑小幅度波动。相反使用较大窗口("window": 100)会平滑所有较高频波动,仅保留低频、长期趋势。它也倾向于比实际数据“滞后”很多。

3.2. 线性模型

该模型对序列中的数据点赋予不同的线性权值。所以旧数据值(即接近窗口开始点)对最终平均计算占比较少。.这种方法用于减少数据平均值背后的“滞后”,因为较早的数据点对最终结果的影响较小。

与简单模型类似,线性模型往往“滞后”于实际数据,虽然比简单模型程度更小。请看下面示例,使用窗口大小30:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "the_movavg":{ 
                   "moving_avg":{ 
                      "buckets_path": "total_visits", 
                      "window" : 30, 
                      "model" : "linear" 
                    } 
                 } 
            } 
        } 
    } 
} 

响应数据为:

"aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2019-08-01T00:00:00.000Z", 
          "key" : 1564617600000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2966.0 
          }, 
          "the_movavg" : { 
            "value" : 2539.75 
          } 
        }, 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3121.0 
          }, 
          "the_movavg" : { 
            "value" : 2609.731343283582 
          } 
        } 
      ] 
    } 
  } 

3.3. 指数模型

该模型与线性模型逻辑类似,除了对旧数据的权重按照指数递减————不是线性。旧数据的递减速度可以通过alpha参数进行控制。alpha较小权重递减慢,平滑性更好。相反alpha较大使得权重递减更快,减少它们对移动平均线的影响。缺省alpha值为0.3,其值得范围是包括[0~1]之间任何浮点数。

下面示例与上面类似,除了增加额外settings设置alpha

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "the_movavg":{ 
                   "moving_avg":{ 
                      "buckets_path": "total_visits", 
                      "window" : 30, 
                      "model" : "ewma", 
                       "settings": { 
                           "alpha": 0.5 
                       } 
                    } 
                 } 
            } 
        } 
    } 
} 

生成响应结果为:

"aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2019-08-01T00:00:00.000Z", 
          "key" : 1564617600000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2966.0 
          }, 
          "the_movavg" : { 
            "value" : 2718.958984375 
          } 
        }, 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3121.0 
          }, 
          "the_movavg" : { 
            "value" : 2842.4794921875 
          } 
        } 
      ] 
    } 
  } 

3.4. 推断预测

有时基于当前数据的趋势进行预测。所有的移动平均模型都支持预测模型,尝试根据当前平滑的移动平均数来预测未来数据。依赖模型参数,这些预测可能准确也可以不准确。simple, linear 和 ewma模型都产生平滑的预测,收敛于集合中最后一个值的平均值。

使用predict参数指定需要预测几个数值附加在数据序列之后。这些预测将与你预测分组的时间间隔相同。请看示例:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "the_movavg":{ 
                   "moving_avg":{ 
                      "buckets_path": "total_visits", 
                      "window" : 30, 
                      "model" : "linear", 
                      "predict" : 3 
                    } 
                 } 
            } 
        } 
    } 
} 

响应结果在分组列表后面增加三个预测结果:

"aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        ... 
        { 
          "key_as_string" : "2019-10-01T00:00:00.000Z", 
          "key" : 1569888000000, 
          "doc_count" : 0, 
          "the_movavg" : { 
            "value" : 2687.3924050632913 
          } 
        }, 
        { 
          "key_as_string" : "2019-11-01T00:00:00.000Z", 
          "key" : 1572566400000, 
          "doc_count" : 0, 
          "the_movavg" : { 
            "value" : 2687.3924050632913 
          } 
        }, 
        { 
          "key_as_string" : "2019-12-01T00:00:00.000Z", 
          "key" : 1575158400000, 
          "doc_count" : 0, 
          "the_movavg" : { 
            "value" : 2687.3924050632913 
          } 
        } 
      ] 
    } 
  } 

太好了!我们预测网站未来三个月的数据访问量。我们看到预测值很“平稳”,三个月数值相同。如果您希望根据局部的或全局的稳定趋势进行推断,那么应该选择holt模型。

4. 移动函数聚集(6.4之后)

前节介绍的移动平均聚集在6.4之后已不建议使用,可以使用移动函数聚集代替。

与移动平均聚集一样,移动函数聚集也是对数据集的子集进行计算,在数据集上逐渐滑动窗口。但是移动函数可以指定自定义脚本在每个窗口数据上执行。elasticsearch内置提供了一些脚本,如min/max,移动平均等。请看移动函数聚集的标准定义:

{ 
    "moving_fn": { 
        "buckets_path": "the_sum", 
        "window": 10, 
        "script": "MovingFunctions.min(values)" 
    } 
} 

我们看到定义了一个移动函数聚集在窗口大小为10的数据集上使用内置的min聚集脚本,需要注意的是moving_fn聚集必须嵌入在histogram 或 date_histogram聚集内。

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                   "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "the_movfn": { 
                    "moving_fn": { 
                         "buckets_path": "total_visits",  
                         "window": 10, 
                         "script": "MovingFunctions.unweightedAvg(values)" 
                    } 
                } 
            } 
        } 
    } 
} 

移动函数平均是total_visits聚集的兄弟聚集,visits_per_month的子聚集。上面示例实现simple移动平均计算。

elasticsearch内置聚集脚本有:

  • max()
  • min()
  • sum()
  • stdDev()
  • unweightedAvg()
  • linearWeightedAvg()
  • ewma()
  • holt()
  • holtWinters()

所有函数访问都需要通过MovingFunctions命名空间,如:MovingFunctions.min()

5. 分组选择器聚集

有时根据条件过滤有日期直方图或其他聚集生成的分组。我们可以使用分组选择器聚集,它包括一段脚本决定哪个分组应该被输出。

指定的度量必须是数值型并且脚本必须返回布尔值。

下面示例首先计算每个月访问量之和,然后评估是否大于3000,符合条件则保留在结果集中,否则被过滤。

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "visits_bucket_filter": { 
                   "bucket_selector": { 
                       "buckets_path": { 
                          "total_visits": "total_visits" 
                        }, 
                    "script": "params.total_visits > 3000" 
                  } 
              } 
         } 
      } 
   } 
} 

结果仅保留两个符合规则的分组,响应结果:

{ 
  "took" : 1646, 
  "timed_out" : false, 
  "_shards" : { 
    "total" : 1, 
    "successful" : 1, 
    "skipped" : 0, 
    "failed" : 0 
  }, 
  "hits" : { 
    "total" : { 
      "value" : 27, 
      "relation" : "eq" 
    }, 
    "max_score" : null, 
    "hits" : [ ] 
  }, 
  "aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2019-03-01T00:00:00.000Z", 
          "key" : 1551398400000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3103.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3121.0 
          } 
        } 
      ] 
    } 
  } 
} 

6. 分组排序聚集

分组排序是父管道聚集,其针对父多个分组聚集(如日期直方图)返回的分组进行排序。可以指定多个字段进行排序,可以基于_key_count或其子聚集。也能通过设置fromsize参数删除一些分组结果。

下面我们对父日期直方图计算的total_visits值进行排序。按照降序进行排序并返回第一页。

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "visits_bucket_sort": { 
                    "bucket_sort": { 
                        "sort": [ 
                          {"total_visits": {"order": "desc"}} 
                        ], 
                        "size": 5 
                    } 
                } 
            } 
        } 
    } 
} 

响应结果为前5条:

{ 
  "took" : 15, 
  "timed_out" : false, 
  "_shards" : { 
    "total" : 1, 
    "successful" : 1, 
    "skipped" : 0, 
    "failed" : 0 
  }, 
  "hits" : { 
    "total" : { 
      "value" : 27, 
      "relation" : "eq" 
    }, 
    "max_score" : null, 
    "hits" : [ ] 
  }, 
  "aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3121.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-03-01T00:00:00.000Z", 
          "key" : 1551398400000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 3103.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-08-01T00:00:00.000Z", 
          "key" : 1564617600000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2966.0 
          } 
        }, 
        { 
          "key_as_string" : "2018-12-01T00:00:00.000Z", 
          "key" : 1543622400000, 
          "doc_count" : 3, 
          "total_visits" : { 
            "value" : 2949.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-07-01T00:00:00.000Z", 
          "key" : 1561939200000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 2887.0 
          } 
        } 
      ] 
    } 
  } 
} 
 

也可以使用该聚集不进行任何排序并删除部分结果,仅需要使用fromsize,不指定sort参数。下面示例仅返回第二、三两个分组:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                "visits_bucket_sort": { 
                    "bucket_sort": { 
                        "from": 2, 
                        "size": 2 
                    } 
                } 
            } 
        } 
    } 
} 

响应结果:

{ 
  "took" : 5, 
  "timed_out" : false, 
  "_shards" : { 
    "total" : 1, 
    "successful" : 1, 
    "skipped" : 0, 
    "failed" : 0 
  }, 
  "hits" : { 
    "total" : { 
      "value" : 27, 
      "relation" : "eq" 
    }, 
    "max_score" : null, 
    "hits" : [ ] 
  }, 
  "aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2018-12-01T00:00:00.000Z", 
          "key" : 1543622400000, 
          "doc_count" : 3, 
          "total_visits" : { 
            "value" : 2949.0 
          } 
        }, 
        { 
          "key_as_string" : "2019-01-01T00:00:00.000Z", 
          "key" : 1546300800000, 
          "doc_count" : 2, 
          "total_visits" : { 
            "value" : 1844.0 
          } 
        } 
      ] 
    } 
  } 
} 

还可以同时使用选择器和排序:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "total_visits": { 
                    "sum": { 
                        "field": "visits" 
                    } 
                }, 
                 "visits_bucket_filter": { 
                   "bucket_selector": { 
                       "buckets_path": { 
                          "total_visits": "total_visits" 
                        }, 
                    "script": "params.total_visits > 3000" 
                  } 
                }, 
                "visits_bucket_sort": { 
                    "bucket_sort": { 
                        "from": 0, 
                        "size": 2 
                    } 
                } 
            } 
        } 
    } 
} 

7. 分组脚本聚集

父管道聚集对每个父级每个分组的度量值执行脚本进行计算。特定度量值必须是数值型,脚本也需返回数值类型。脚本可以是内联的,或在文件、索引中。

下面示例首先对日期直方图分组计算分组中的最大值和最小值,然后通过脚本实现最小值除以最大值计算每个分组中两者的比率:

GET /traffic_stats/_search?size=0 
{ 
    "aggs" : { 
        "visits_per_month" : { 
            "date_histogram" : { 
                "field" : "date", 
                "interval" : "month" 
            }, 
            "aggs": { 
                "min_visits": { 
                    "min": { 
                        "field": "visits" 
                    } 
                }, 
                "max_visits": { 
                    "max": { 
                        "field":"visits" 
                    } 
                }, 
                "min_max_ratio": { 
                   "bucket_script": { 
                       "buckets_path": { 
                          "min_visits": "min_visits", 
                          "max_visits": "max_visits" 
                        }, 
                    "script": "params.min_visits / params.max_visits" 
                  } 
              } 
         } 
      } 
  } 
} 

聚集计算每个分组的min_max_ratio,并附加在每个分组之后:

{ 
  "took" : 170, 
  "timed_out" : false, 
  "_shards" : { 
    "total" : 1, 
    "successful" : 1, 
    "skipped" : 0, 
    "failed" : 0 
  }, 
  "hits" : { 
    "total" : { 
      "value" : 27, 
      "relation" : "eq" 
    }, 
    "max_score" : null, 
    "hits" : [ ] 
  }, 
  "aggregations" : { 
    "visits_per_month" : { 
      "buckets" : [ 
        { 
          "key_as_string" : "2018-10-01T00:00:00.000Z", 
          "key" : 1538352000000, 
          "doc_count" : 3, 
          "min_visits" : { 
            "value" : 488.0 
          }, 
          "max_visits" : { 
            "value" : 789.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.6185044359949303 
          } 
        }, 
        { 
          "key_as_string" : "2018-11-01T00:00:00.000Z", 
          "key" : 1541030400000, 
          "doc_count" : 3, 
          "min_visits" : { 
            "value" : 394.0 
          }, 
          "max_visits" : { 
            "value" : 1299.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.30331023864511164 
          } 
        }, 
        { 
          "key_as_string" : "2018-12-01T00:00:00.000Z", 
          "key" : 1543622400000, 
          "doc_count" : 3, 
          "min_visits" : { 
            "value" : 768.0 
          }, 
          "max_visits" : { 
            "value" : 1194.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.6432160804020101 
          } 
        }, 
        { 
          "key_as_string" : "2019-01-01T00:00:00.000Z", 
          "key" : 1546300800000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 872.0 
          }, 
          "max_visits" : { 
            "value" : 972.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.897119341563786 
          } 
        }, 
        { 
          "key_as_string" : "2019-02-01T00:00:00.000Z", 
          "key" : 1548979200000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 827.0 
          }, 
          "max_visits" : { 
            "value" : 1584.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.5220959595959596 
          } 
        }, 
        { 
          "key_as_string" : "2019-03-01T00:00:00.000Z", 
          "key" : 1551398400000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 1499.0 
          }, 
          "max_visits" : { 
            "value" : 1604.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.9345386533665836 
          } 
        }, 
        { 
          "key_as_string" : "2019-04-01T00:00:00.000Z", 
          "key" : 1554076800000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 1247.0 
          }, 
          "max_visits" : { 
            "value" : 1392.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.8958333333333334 
          } 
        }, 
        { 
          "key_as_string" : "2019-05-01T00:00:00.000Z", 
          "key" : 1556668800000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 984.0 
          }, 
          "max_visits" : { 
            "value" : 1228.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.8013029315960912 
          } 
        }, 
        { 
          "key_as_string" : "2019-06-01T00:00:00.000Z", 
          "key" : 1559347200000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 1238.0 
          }, 
          "max_visits" : { 
            "value" : 1423.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.8699929725931131 
          } 
        }, 
        { 
          "key_as_string" : "2019-07-01T00:00:00.000Z", 
          "key" : 1561939200000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 1388.0 
          }, 
          "max_visits" : { 
            "value" : 1499.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.9259506337558372 
          } 
        }, 
        { 
          "key_as_string" : "2019-08-01T00:00:00.000Z", 
          "key" : 1564617600000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 1443.0 
          }, 
          "max_visits" : { 
            "value" : 1523.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.9474720945502298 
          } 
        }, 
        { 
          "key_as_string" : "2019-09-01T00:00:00.000Z", 
          "key" : 1567296000000, 
          "doc_count" : 2, 
          "min_visits" : { 
            "value" : 1534.0 
          }, 
          "max_visits" : { 
            "value" : 1587.0 
          }, 
          "min_max_ratio" : { 
            "value" : 0.9666036546943919 
          } 
        } 
      ] 
    } 
  } 
} 

8. 总结

你真棒,两节都看完基本已经学完所有的管道聚集,管道聚集实现涉及中间值的复杂计算。你可以利用elasticsearch脚本对返回度量实现自定义编程逻辑。举例:可以评估如果分组匹配一定规则则计算自定义度量,不是缺省内置的逻辑,如最小/最大比率。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/104435860
阅读延展