【问题标题】:ElasticSearch - get all available filters (aggregate) from indexElasticSearch - 从索引中获取所有可用的过滤器(聚合)
【发布时间】:2017-09-19 11:10:49
【问题描述】:

假设我有:

"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 分组)及其所有可能值(在所有产品中)?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    你不能在一个查询中做到这一点,但在两个查询中相当容易:

    检索属性列表

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

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

    检索它们的值

    然后您可以使用多个Terms aggregation 来获取一个字段的所有值:

    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 aggregation 进行中间查询以获取此实际值,然后将其用作术语聚合的大小。请注意,基数是大数时的估计值,因此您可能需要使用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 explosion

    像这样存储它们:

    {
        "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
              }
            }
          }
        }
      }
    }'
    

    属性需要使用Nested mapping

    【讨论】:

    • 我同意@Pandawan。您不能对分析的文本字段进行术语聚合,使用_field_stats / _field_caps API 来区分哪些字段适合术语聚合。您可以将字段列表缓存在内存中,因为它不应该经常更改。 nested 类型对性能有负面影响,并使查询/聚合变得复杂。默认情况下,索引(实际上是映射)限制为 1000 个字段,以避免映射爆炸。
    • 听起来很不错,似乎非常适合我的用例。
    猜你喜欢
    • 2015-09-17
    • 2014-02-02
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多