ElasticSearch-返回唯一值


122

我将如何languages从记录中获取所有值并使其唯一。

记录

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }

询问

GET items/_search
{ ... }

# => Expected Response
[10, 11]

任何帮助都会很棒。


1
fields: [languages]将仅给出给定字段的值,但使它们唯一可能在代码中更容易实现。虽然可能有一个方便的汇总可以为您完成。
2014年

1
对于那些研究此主题的人,这里还有个有用的讨论:
Elasticsearch中

Answers:


165

您可以使用术语聚合

{
"size": 0,
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  "size" : 500 }
    }
}}

搜索将返回如下内容:

{
"took" : 16,
"timed_out" : false,
"_shards" : {
  "total" : 2,
  "successful" : 2,
  "failed" : 0
},
"hits" : {
"total" : 1000000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
  "langs" : {
    "buckets" : [ {
      "key" : "10",
      "doc_count" : 244812
    }, {
      "key" : "11",
      "doc_count" : 136794

    }, {
      "key" : "12",
      "doc_count" : 32312
       } ]
    }
  }
}

size聚合中的参数指定要包含在聚合结果中的最大术语数。如果需要所有结果,请将其设置为大于数据中唯一术语数的值。


2
"fields" : ["language"]返回相同的结果。您能否扩展答案以查看聚合框架是否只能返回语言值?#=> [10, 11, 10]
ChuckJHardy 2014年

1
@CharlesJHardy,它没有相同的结果。您要查找的数据在“聚合”键下。我用示例结果编辑了答案。您也可以/应该将“ size”设置为:0,以便不包括任何文档,仅包含您想要的汇总结果。
安东2014年

1
请注意,如果您有许多可能的值,则language可能要添加size=0shard_size=0,以确保获得所有值。见elasticsearch.org/guide/en/elasticsearch/reference/current/...
德罗尔

3
我认为这个答案不能解决OP。最初的问题想要独特的价值而不是计数。我想念什么吗?
blowlow '16

4
@BHBH,答案确实提供了不同的值。它们是“键”值,即“ 10”,“ 11”和“ 12”。(集合> langs> buckets> key ...)
Anton

9

Elasticsearch 1.1+具有基数聚合,可为您提供独特的计数

请注意,这实际上是一个近似值,对于高基数的数据集,准确性可能会降低,但在我的测试中通常是相当准确的。

您也可以使用precision_threshold参数调整精度。权衡或过程当然是内存使用情况。

文档中的这张图显示了较高的值如何precision_threshold导致更准确的结果。


相对误差与阈值


2
基数汇总是否可以确保如果存在一个术语,则该术语将出现在结果中(计数> = 1)?还是可能错过一些在大型数据集中只出现一次的术语?
2016年

2
@mark取决于您设置的精度阈值。阈值越高,错过的机会就越小。请注意,精度阈值设置的上限为40,000。也就是说,如果数据集大于该值,则会有一个估算值,因此可能会遗漏单个值
Sundar,2016年

12
我相信这个答案是错误的。基数聚合是一个很好的工具。但是,任务是检索术语本身,而不是估计有多少个不同的术语。
安东

4

如果要获取每个language字段唯一值的第一个文档,则可以执行以下操作:

{
 "query": {
    "match_all": {
    }
  },
  "collapse": {
    "field": "language.keyword",
    "inner_hits": {
    "name": "latest",
      "size": 1
    }
  }
}

3

我也在为自己寻找这种解决方案。我发现参考术语聚合

因此,根据以下说明是正确的解决方案。

{
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  
                    "size" : 500 }
    }
}}

但是,如果遇到以下错误:

"error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "Fielddata is disabled on text fields by default. Set fielddata=true on [fastest_method] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."
            }
        ]}

在这种情况下,您必须在请求中添加“ KEYWORD ”,如下所示:

   {
    "aggs" : {
        "langs" : {
            "terms" : { "field" : "language.keyword",  
                        "size" : 500 }
        }
    }}

1

如果要获得所有唯一值而没有任何近似值或设置幻数(size: 500),请使用COMPOSITE AGGREGATION(ES 6.5+)

根据官方文件

“如果要检索嵌套术语聚合中的所有术语或术语的所有组合,则应使用COMPOSITE AGGREGATION,它允许对所有可能的术语进行分页,而不是设置大于术语聚合中字段基数的大小。术语汇总旨在返回最热门的术语,并且不允许分页。”

JavaScript中的实现示例:

const ITEMS_PER_PAGE = 1000;

const body =  {
    "size": 0, // Returning only aggregation results: https://www.elastic.co/guide/en/elasticsearch/reference/current/returning-only-agg-results.html
    "aggs" : {
        "langs": {
            "composite" : {
                "size": ITEMS_PER_PAGE,
                "sources" : [
                    { "language": { "terms" : { "field": "language" } } }
                ]
            }
        }
     }
};

const uniqueLanguages = [];

while (true) {
  const result = await es.search(body);

  const currentUniqueLangs = result.aggregations.langs.buckets.map(bucket => bucket.key);

  uniqueLanguages.push(...currentUniqueLangs);

  const after = result.aggregations.langs.after_key;

  if (after) {
      // continue paginating unique items
      body.aggs.langs.composite.after = after;
  } else {
      break;
  }
}

console.log(uniqueLanguages);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.