ElasticSearch - 返回唯一值

Cha*_*rdy 109 elasticsearch

如何languages从记录中获取所有值的值并使其唯一.

记录

PUT items/1
{ "language" : 10 }

PUT items/2
{ "language" : 11 }

PUT items/3
{ "language" : 10 }
Run Code Online (Sandbox Code Playgroud)

询问

GET items/_search
{ ... }

# => Expected Response
[10, 11]
Run Code Online (Sandbox Code Playgroud)

任何帮助都会很棒.

Ant*_*ton 148

您可以使用聚合术语.

{
"size": 0,
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  "size" : 500 }
    }
}}
Run Code Online (Sandbox Code Playgroud)

搜索将返回如下内容:

{
"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
       } ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为这个答案没有涉及OP.原始问题需要不同的*值*不计数.我错过了什么吗? (3认同)
  • @BHBH,答案确实提供了不同的价值观.它们是"关键"值,即"10","11"和"12".(聚合> langs> buckets> key ...) (3认同)
  • `"fields":["language"]`带回相同的结果.您是否可以扩展您的答案,看看聚合框架是否只能返回语言值?`#=> [10,11,10]` (2认同)

小智 13

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

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

{
"aggs" : {
    "langs" : {
        "terms" : { "field" : "language",  
                    "size" : 500 }
    }
}}
Run Code Online (Sandbox Code Playgroud)

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

"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."
            }
        ]}
Run Code Online (Sandbox Code Playgroud)

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

   {
    "aggs" : {
        "langs" : {
            "terms" : { "field" : "language.keyword",  
                        "size" : 500 }
        }
    }}
Run Code Online (Sandbox Code Playgroud)


bra*_*ido 8

Elasticsearch 1.1+具有基数聚合,它将为您提供唯一的计数

请注意,它实际上是一个近似值,并且高基数数据集的精度可能会降低,但在我的测试中它通常非常准确.

您还可以使用precision_threshold参数调整精度.权衡,当然,是内存使用.

来自文档的此图表显示了更高的结果如何precision_threshold导致更准确的结果.


相对误差与阈值

  • 我相信这个答案是错误的.基数聚合是一个很好的工具.但是,任务是自己检索术语,而不是估计有多少不同的术语. (11认同)
  • [Cardinality Aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html)是否保证如果某个术语存在,那么它将出现在结果(计数> = 1)?或者它可能会遗漏一些只出现在大型数据集中的术语? (2认同)
  • @mark取决于您设置的精度阈值.阈值越高,它错过的可能性就越小.请注意,精度阈值设置的限制为40,000.这意味着,数据集高于该数据集,将会有估计值,因此可能会错过单个值 (2认同)

小智 8

如果您想获取每个language字段唯一值的第一个文档,您可以这样做:

{
 "query": {
    "match_all": {
    }
  },
  "collapse": {
    "field": "language.keyword",
    "inner_hits": {
    "name": "latest",
      "size": 1
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Hil*_*hka 7

如果您想在没有任何近似值或设置幻数 ( 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);
Run Code Online (Sandbox Code Playgroud)