多项式聚合编辑

一种基于多桶值源的聚合,其中桶是动态构建的 - 每个唯一值集一个。多项式聚合与 terms 聚合 非常相似,但在大多数情况下,它会比 terms 聚合慢,并且会消耗更多内存。因此,如果始终使用相同的字段集,则将这些字段的组合键作为单独的字段索引,并在该字段上使用 terms 聚合会更有效。

当您需要按多个文档或复合键上的度量聚合进行排序并获取前 N 个结果时,多项式聚合最为有用。如果不需要排序,并且预期所有值都将使用嵌套 terms 聚合或 复合聚合 来检索,则它将是更快、更节省内存的解决方案。

示例

response = client.search(
  index: 'products',
  body: {
    aggregations: {
      genres_and_products: {
        multi_terms: {
          terms: [
            {
              field: 'genre'
            },
            {
              field: 'product'
            }
          ]
        }
      }
    }
  }
)
puts response
GET /products/_search
{
  "aggs": {
    "genres_and_products": {
      "multi_terms": {
        "terms": [{
          "field": "genre" 
        }, {
          "field": "product"
        }]
      }
    }
  }
}

multi_terms 聚合可以使用与 terms 聚合 相同的字段类型,并支持大多数 terms 聚合参数。

响应

{
  ...
  "aggregations" : {
    "genres_and_products" : {
      "doc_count_error_upper_bound" : 0,  
      "sum_other_doc_count" : 0,          
      "buckets" : [                       
        {
          "key" : [                       
            "rock",
            "Product A"
          ],
          "key_as_string" : "rock|Product A",
          "doc_count" : 2
        },
        {
          "key" : [
            "electronic",
            "Product B"
          ],
          "key_as_string" : "electronic|Product B",
          "doc_count" : 1
        },
        {
          "key" : [
            "jazz",
            "Product B"
          ],
          "key_as_string" : "jazz|Product B",
          "doc_count" : 1
        },
        {
          "key" : [
            "rock",
            "Product B"
          ],
          "key_as_string" : "rock|Product B",
          "doc_count" : 1
        }
      ]
    }
  }
}

每个项的文档计数误差的上限,请参见 <<search-aggregations-bucket-multi-terms-aggregation-approximate-counts,below>

当存在大量唯一项时,Elasticsearch 仅返回前 N 项;此数字是所有未包含在响应中的桶的文档计数之和

前 N 个桶的列表。

键是值数组,排序方式与聚合的 terms 参数中的表达式相同

默认情况下,multi_terms 聚合将返回按 doc_count 排序的前十个项的桶。可以通过设置 size 参数来更改此默认行为。

聚合参数编辑

支持以下参数。有关这些参数的更详细说明,请参见 terms 聚合

size

可选。定义应从总体项列表中返回多少个项桶。默认为 10。

shard_size

可选。请求的 size 越高,结果越准确,但计算最终结果的成本也越高。默认 shard_size(size * 1.5 + 10)

show_term_doc_count_error

可选。计算每个项的文档计数误差。默认为 false

order

可选。指定桶的顺序。默认为每个桶的文档数量。对于具有相同文档计数的桶,桶项值用作平局决胜符。

min_doc_count

可选。桶中要返回的最小文档数。默认为 1。

shard_min_doc_count

可选。每个分片上桶中要返回的最小文档数。默认为 min_doc_count

collect_mode

可选。指定数据收集策略。支持 depth_firstbreadth_first 模式。默认为 breadth_first

脚本编辑

使用脚本生成项

response = client.search(
  index: 'products',
  body: {
    runtime_mappings: {
      'genre.length' => {
        type: 'long',
        script: "emit(doc['genre'].value.length())"
      }
    },
    aggregations: {
      genres_and_products: {
        multi_terms: {
          terms: [
            {
              field: 'genre.length'
            },
            {
              field: 'product'
            }
          ]
        }
      }
    }
  }
)
puts response
GET /products/_search
{
  "runtime_mappings": {
    "genre.length": {
      "type": "long",
      "script": "emit(doc['genre'].value.length())"
    }
  },
  "aggs": {
    "genres_and_products": {
      "multi_terms": {
        "terms": [
          {
            "field": "genre.length"
          },
          {
            "field": "product"
          }
        ]
      }
    }
  }
}

响应

{
  ...
  "aggregations" : {
    "genres_and_products" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : [
            4,
            "Product A"
          ],
          "key_as_string" : "4|Product A",
          "doc_count" : 2
        },
        {
          "key" : [
            4,
            "Product B"
          ],
          "key_as_string" : "4|Product B",
          "doc_count" : 2
        },
        {
          "key" : [
            10,
            "Product B"
          ],
          "key_as_string" : "10|Product B",
          "doc_count" : 1
        }
      ]
    }
  }
}

缺失值编辑

missing 参数定义了如何处理缺少值的文档。默认情况下,如果任何键组件丢失,则整个文档将被忽略,但也可以使用 missing 参数将其视为具有值。

response = client.search(
  index: 'products',
  body: {
    aggregations: {
      genres_and_products: {
        multi_terms: {
          terms: [
            {
              field: 'genre'
            },
            {
              field: 'product',
              missing: 'Product Z'
            }
          ]
        }
      }
    }
  }
)
puts response
GET /products/_search
{
  "aggs": {
    "genres_and_products": {
      "multi_terms": {
        "terms": [
          {
            "field": "genre"
          },
          {
            "field": "product",
            "missing": "Product Z"
          }
        ]
      }
    }
  }
}

响应

{
   ...
   "aggregations" : {
    "genres_and_products" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : [
            "rock",
            "Product A"
          ],
          "key_as_string" : "rock|Product A",
          "doc_count" : 2
        },
        {
          "key" : [
            "electronic",
            "Product B"
          ],
          "key_as_string" : "electronic|Product B",
          "doc_count" : 1
        },
        {
          "key" : [
            "electronic",
            "Product Z"
          ],
          "key_as_string" : "electronic|Product Z",  
          "doc_count" : 1
        },
        {
          "key" : [
            "jazz",
            "Product B"
          ],
          "key_as_string" : "jazz|Product B",
          "doc_count" : 1
        },
        {
          "key" : [
            "rock",
            "Product B"
          ],
          "key_as_string" : "rock|Product B",
          "doc_count" : 1
        }
      ]
    }
  }
}

product 字段中没有值的文档将与具有值 Product Z 的文档落入同一个桶中。

混合字段类型编辑

在对多个索引进行聚合时,聚合字段的类型可能在所有索引中都不相同。某些类型彼此兼容(integerlongfloatdouble),但当类型是十进制数和非十进制数的混合时,terms 聚合将把非十进制数提升为十进制数。这会导致桶值精度损失。

子聚合和排序示例编辑

与大多数桶聚合一样,multi_term 支持子聚合,并按度量子聚合对桶进行排序

response = client.search(
  index: 'products',
  body: {
    aggregations: {
      genres_and_products: {
        multi_terms: {
          terms: [
            {
              field: 'genre'
            },
            {
              field: 'product'
            }
          ],
          order: {
            total_quantity: 'desc'
          }
        },
        aggregations: {
          total_quantity: {
            sum: {
              field: 'quantity'
            }
          }
        }
      }
    }
  }
)
puts response
GET /products/_search
{
  "aggs": {
    "genres_and_products": {
      "multi_terms": {
        "terms": [
          {
            "field": "genre"
          },
          {
            "field": "product"
          }
        ],
        "order": {
          "total_quantity": "desc"
        }
      },
      "aggs": {
        "total_quantity": {
          "sum": {
            "field": "quantity"
          }
        }
      }
    }
  }
}
{
  ...
  "aggregations" : {
    "genres_and_products" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : [
            "jazz",
            "Product B"
          ],
          "key_as_string" : "jazz|Product B",
          "doc_count" : 1,
          "total_quantity" : {
            "value" : 10.0
          }
        },
        {
          "key" : [
            "rock",
            "Product A"
          ],
          "key_as_string" : "rock|Product A",
          "doc_count" : 2,
          "total_quantity" : {
            "value" : 9.0
          }
        },
        {
          "key" : [
            "electronic",
            "Product B"
          ],
          "key_as_string" : "electronic|Product B",
          "doc_count" : 1,
          "total_quantity" : {
            "value" : 3.0
          }
        },
        {
          "key" : [
            "rock",
            "Product B"
          ],
          "key_as_string" : "rock|Product B",
          "doc_count" : 1,
          "total_quantity" : {
            "value" : 1.0
          }
        }
      ]
    }
  }
}