一尘不染

ElasticSearch-从索引中获取所有可用的过滤器(聚合)

elasticsearch

假设我有:

"hits": [
      {
        "_index": "products",
        "_type": "product",
        "_id": "599c2b3fc991ee0a597034fa",
        "_score": 1,
        "_source": {,
          "attributes": {
            "1": [
              "a"
            ],
            "2": [
              "b",
              "c"
            ],
            "3": [
              "d",
              "e"
            ],
            "4": [
              "f",
              "g"
            ],
            "5": [
              "h",
              "i"
            ]
          }
        }
      },
      {
        "_index": "products",
        "_type": "product",
        "_id": "599c4bb4b970c25976ced8bd",
        "_score": 1,
        "_source": {
          "attributes": {
            "1": [
              "z"
            ],
            "2": [
              "y"
            ]
          }
        }

每个产品都有属性。每个属性都有ID和一个值。我可以按属性筛选产品,但现在我要从MongoDB创建“可能的属性”列表。我想找到一种单独从ElasticSearch生成这样的列表的方法(也许只是向MongoDB查询其他数据)。

我需要的是:

{
  1: [a, z],
  2: [b, c, y],
  etc.
}

这样的聚合看起来如何?获取所有可用属性(按分组attribute.id)及其所有可能值(在所有产品中)?


阅读 220

收藏
2020-06-22

共1个答案

一尘不染

您无法在一个查询中做到这一点,但在两个查询中却很简单:

检索属性列表

您可以使用映射来获取文档中的所有字段:

curl -XGET "http://localhost:9200/your_index/your_type/_mapping"

检索他们的价值

然后,您可以使用多个术语聚合来获取字段的所有值:

curl -XGET "http://localhost:9200/your_index/your_type/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "field1Values": {
      "terms": {
        "field": "field1",
        "size": 20
      }
    },
    "field2Values": {
      "terms": {
        "field": "field2",
        "size": 20
      }
    },
    "field3Values": {
      "terms": {
        "field": "field3",
        "size": 20
      }
    },
    ...
  }
}'

这将检索每个字段的前20个最常出现的值。

限制为20个值是防止产生巨大响应的限制(例如,如果您有数十亿个具有唯一字段的文档)。您可以修改术语聚合的“大小”参数以增加它。根据您的要求,我想选择一个比每个字段获取的不同值的数量的大致估计大10倍的方法可以解决问题。

如何处理价值的巨大基数

您还可以使用基数聚合进行中间查询,以获取此实际值,然后将其用作术语聚合的大小。请注意,基数不是一个大数的估计值,因此您可能想使用cardinality * 2

curl -XGET "http://localhost:9200/your_index/your_type/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "field1Cardinality": {
      "cardinality": {
        "field": "field1"
      }
    },
    "field2Cardinality": {
      "cardinality": {
        "field": "field2"
      }
    },
    "field3Cardinality": {
      "cardinality": {
        "field": "field3"
      }
    },
    ...
  }
}'

如何处理价值的巨大基数

如果没有太多不同的属性,则前一种方法适用。如果有的话,您应该更改文档的存储方式,以防止Mapping爆炸

像这样存储它们:

{
    "attributes":[
        {
            "name":"1",
            "value":[
                "a"
            ]
        },
        {
            "name":"2",
            "value":[
                "b",
                "c"
            ]
        },
        {
            "name":"3",
            "value":[
                "d",
                "e"
            ]
        },
        {
            "name":"4",
            "value":[
                "f",
                "g"
            ]
        },
        {
            "name":"5",
            "value":[
                "h",
                "i"
            ]
        }
    ]
}

将解决此问题,您将能够在“名称”上使用术语汇总,然后在“值”上使用子术语汇总来获得所需的内容:

curl -XGET "http://localhost:9200/your_index/your_type/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "attributes": {
      "terms": {
        "field": "attributes.name",
        "size": 1000
      },
      "aggs": {
        "values": {
          "terms": {
            "field": "attributes.value",
            "size": 100
          }
        }
      }
    }
  }
}'

它要求对属性使用嵌套映射

2020-06-22