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

时间:2017-09-19 11:10:49

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

1 个答案:

答案 0 :(得分:4)

您无法在一个查询中执行此操作,但在两个查询中相当容易:

检索属性列表

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

std::vector<int> populate(std::vector<int> ary, int a)
{
    for (int i = 1; i <= a; i++)
    {
        if (i % 2 != 0)
        {

            ary.push_back(i);
        }

    }
    return ary;
}



int main()
{

    std::vector<int> loli(100);




    for (int value : populate(loli, 31))
    {

        std::cout << value << " ";
        system("pause");
    }



}

检索其值

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

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

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

这个20个值的限制是一个限制,以防止一个巨大的响应(如果您有几十亿个文档具有唯一的字段)。你可以修改&#34;尺寸&#34;术语聚合的参数增加它。根据您的要求,我猜选择比每个字段所采用的不同值的数量的粗略估计大10倍的东西应该可以做到。

如何处理值上的巨大基数

您还可以使用cardinality 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 } }, ... } }'

cardinality * 2

如何处理值上的巨大基数

如果没有那么多不同的属性,之前的作品。 如果有,您应该更改文档的存储方式以防止Mapping explosion

像这样存储它们:

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"
      }
    },
    ...
  }
}'

可以解决问题,您可以在&#34; name&#34;上使用术语聚合。然后是&#34;值&#34;上的子项聚合得到你想要的东西:

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

需要使用Nested mapping作为属性。