最顶端的度量(top_metrics)聚合

top_metrics 聚合从文档中选择具有最大或最小 "sort"(排序) 值的度量。 下面的例子将获得文档中具有最大值 s 的文档的 m 字段的值:

POST /test/_bulk?refresh
{"index": {}}
{"s": 1, "m": 3.1415}
{"index": {}}
{"s": 2, "m": 1.0}
{"index": {}}
{"s": 3, "m": 2.71828}
POST /test/_search?filter_path=aggregations
{
  "aggs": {
    "tm": {
      "top_metrics": {
        "metrics": {"field": "m"},
        "sort": {"s": "desc"}
      }
    }
  }
}

它将返回:

{
  "aggregations": {
    "tm": {
      "top": [ {"sort": [3], "metrics": {"m": 2.718280076980591 } } ]
    }
  }
}

top_metrics 在本质上与 top_hits 非常相似,但是因为对它的限制更多,所以它能够使用更少的内存来完成工作,并且通常更快。

sort

度量请求中的 sort 字段与 search 请求中的 sort 字段功能完全相同,除了: * 它不能用于 binaryflattenedipkeywordtext 字段。 * 它只支持单个 排序(sort) 值,因此当排序值相同时无法区分哪个在前。

聚合返回的度量是搜索请求返回的第一个命中结果。因此,

"sort": {"s": "desc"}
从具有最大 s 值的文档中获取度量
"sort": {"s": "asc"}
从具有最小 s 值的文档中获取度量
"sort": {"_geo_distance": {"location": "35.7796, -78.6382"}}
location(位置) 最接近 35.7796, -78.6382的文档中获取度量
"sort": "_score"
从相关性评分最高的文档中获取度量

metrics

metrics 选择要从"最顶端(top)"的文档返回的字段。 可以使用类似 "metric": {"field": "m"} 什么的来请求单个度量,或者通过使用类似 "metric": [{"field": "m"}, {"field": "i"} 的度量列表来请求多个度量。 下面是一个更完整的例子:

PUT /test
{
  "mappings": {
    "properties": {
      "d": {"type": "date"}
    }
  }
}
POST /test/_bulk?refresh
{"index": {}}
{"s": 1, "m": 3.1415, "i": 1, "d": "2020-01-01T00:12:12Z"}
{"index": {}}
{"s": 2, "m": 1.0, "i": 6, "d": "2020-01-02T00:12:12Z"}
{"index": {}}
{"s": 3, "m": 2.71828, "i": -12, "d": "2019-12-31T00:12:12Z"}
POST /test/_search?filter_path=aggregations
{
  "aggs": {
    "tm": {
      "top_metrics": {
        "metrics": [
          {"field": "m"},
          {"field": "i"},
          {"field": "d"}
        ],
        "sort": {"s": "desc"}
      }
    }
  }
}

它返回:

{
  "aggregations": {
    "tm": {
      "top": [ {
        "sort": [3],
        "metrics": {
          "m": 2.718280076980591,
          "i": -12,
          "d": "2019-12-31T00:12:12.000Z"
        }
      } ]
    }
  }
}

size

top_metrics 可以使用 size 参数返回前几个文档的度量值:

POST /test/_bulk?refresh
{"index": {}}
{"s": 1, "m": 3.1415}
{"index": {}}
{"s": 2, "m": 1.0}
{"index": {}}
{"s": 3, "m": 2.71828}
POST /test/_search?filter_path=aggregations
{
  "aggs": {
    "tm": {
      "top_metrics": {
        "metrics": {"field": "m"},
        "sort": {"s": "desc"},
        "size": 3
      }
    }
  }
}

它将返回:

{
  "aggregations": {
    "tm": {
      "top": [
        {"sort": [3], "metrics": {"m": 2.718280076980591 } },
        {"sort": [2], "metrics": {"m": 1.0 } },
        {"sort": [1], "metrics": {"m": 3.1414999961853027 } }
      ]
    }
  }
}

size 的默认值是 1。 size 的最大值默认是10,因为聚合的工作存储是“密集的”,这意味着我们为每个桶分配 size 大小的槽。 10 是一个非常保守的默认最大值,如果你需要,可以通过更改索引设置 top_metrics_max_size 来提高该值。 但是你要知道,更大的 size 值会占用相当多的内存,特别是如果它们在一个会生成很多桶的聚合中,比如一个很大的terms聚合。 如果你仍然想提高它,类似这样操作:

PUT /test/_settings
{
  "top_metrics_max_size": 100
}

如果 size 大于 1top_metrics 聚合不能用作排序的目标

示例

和 terms 一起使用

这种聚合在 terms聚合 内部应该非常有用,比如说,要找到每个服务器报告的最后一个值。

PUT /node
{
  "mappings": {
    "properties": {
      "ip": {"type": "ip"},
      "date": {"type": "date"}
    }
  }
}
POST /node/_bulk?refresh
{"index": {}}
{"ip": "192.168.0.1", "date": "2020-01-01T01:01:01", "m": 1}
{"index": {}}
{"ip": "192.168.0.1", "date": "2020-01-01T02:01:01", "m": 2}
{"index": {}}
{"ip": "192.168.0.2", "date": "2020-01-01T02:01:01", "m": 3}
POST /node/_search?filter_path=aggregations
{
  "aggs": {
    "ip": {
      "terms": {
        "field": "ip"
      },
      "aggs": {
        "tm": {
          "top_metrics": {
            "metrics": {"field": "m"},
            "sort": {"date": "desc"}
          }
        }
      }
    }
  }
}

它返回:

{
  "aggregations": {
    "ip": {
      "buckets": [
        {
          "key": "192.168.0.1",
          "doc_count": 2,
          "tm": {
            "top": [ {"sort": ["2020-01-01T02:01:01.000Z"], "metrics": {"m": 2 } } ]
          }
        },
        {
          "key": "192.168.0.2",
          "doc_count": 1,
          "tm": {
            "top": [ {"sort": ["2020-01-01T02:01:01.000Z"], "metrics": {"m": 3 } } ]
          }
        }
      ],
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0
    }
  }
}

top_hits 不同的是,可以根据此度量的结果对桶进行排序:

POST /node/_search?filter_path=aggregations
{
  "aggs": {
    "ip": {
      "terms": {
        "field": "ip",
        "order": {"tm.m": "desc"}
      },
      "aggs": {
        "tm": {
          "top_metrics": {
            "metrics": {"field": "m"},
            "sort": {"date": "desc"}
          }
        }
      }
    }
  }
}

它返回:

{
  "aggregations": {
    "ip": {
      "buckets": [
        {
          "key": "192.168.0.2",
          "doc_count": 1,
          "tm": {
            "top": [ {"sort": ["2020-01-01T02:01:01.000Z"], "metrics": {"m": 3 } } ]
          }
        },
        {
          "key": "192.168.0.1",
          "doc_count": 2,
          "tm": {
            "top": [ {"sort": ["2020-01-01T02:01:01.000Z"], "metrics": {"m": 2 } } ]
          }
        }
      ],
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0
    }
  }
}

混合的排序类型

按不同索引中具有不同类型的字段对 top_metrics 进行排序会产生一些意想不到的结果:浮点型字段总是独立于整型字段进行排序。

# 插入的文档的m字段的值有浮点型,也有整型
POST /test/_bulk?refresh
{"index": {"_index": "test1"}}
{"s": 1, "m": 3.1415}
{"index": {"_index": "test1"}}
{"s": 2, "m": 1}
{"index": {"_index": "test2"}}
{"s": 3.1, "m": 2.71828}

#搜索
POST /test*/_search?filter_path=aggregations
{
  "aggs": {
    "tm": {
      "top_metrics": {
        "metrics": {"field": "m"},
        "sort": {"s": "asc"}
      }
    }
  }
}

它返回:

{
  "aggregations": {
    "tm": {
      "top": [ {"sort": [3.0999999046325684], "metrics": {"m": 2.718280076980591 } } ]
    }
  }
}

虽然这比返回一个错误要好,但它可能不是你想要的。 虽然它确实损失了一些精度,但是你可以使用类似下面的代码将整个数值字段显式地转换为浮点型:

POST /test*/_search?filter_path=aggregations
{
  "aggs": {
    "tm": {
      "top_metrics": {
        "metrics": {"field": "m"},
        "sort": {"s": {"order": "asc", "numeric_type": "double"}}
      }
    }
  }
}

它返回的数据与我们期望的更接近:

{
  "aggregations": {
    "tm": {
      "top": [ {"sort": [1.0], "metrics": {"m": 3.1414999961853027 } } ]
    }
  }
}