使用 Elasticsearch 查询字段的所有唯一值

Posted

技术标签:

【中文标题】使用 Elasticsearch 查询字段的所有唯一值【英文标题】:Query all unique values of a field with Elasticsearch 【发布时间】:2013-01-06 03:20:05 【问题描述】:

如何使用 Elasticsearch 搜索给定字段的所有唯一值?

我有类似select full_name from authors 这样的查询,所以我可以在表单上向用户显示列表。

【问题讨论】:

【参考方案1】:

您可以在“全名”字段中创建terms facet。但是为了正确地做到这一点,您需要确保在索引时没有对其进行标记,否则构面中的每个条目都将是作为字段内容一部分的不同术语。您很可能需要在映射中将其配置为“not_analyzed”。如果您也在搜索它并且仍想对其进行标记,则可以使用multi field 以两种不同的方式对其进行索引。

您还需要考虑到,根据作为 full_name 字段一部分的唯一术语的数量,此操作可能很昂贵并且需要相当多的内存。

【讨论】:

【参考方案2】:

对于 Elasticsearch 1.0 及更高版本,您可以利用 terms aggregation 来执行此操作,

查询 DSL:


  "aggs": 
    "NAME": 
      "terms": 
        "field": "",
        "size": 10
      
    
  

一个真实的例子:


  "aggs": 
    "full_name": 
      "terms": 
        "field": "authors",
        "size": 0
      
    
  

然后你可以得到authors字段的所有唯一值。 size=0 表示不限制词条数(这要求 es 为 1.1.0 或更高版本)。

回复:


    ...

    "aggregations" : 
        "full_name" : 
            "buckets" : [
                
                    "key" : "Ken",
                    "doc_count" : 10
                ,
                
                    "key" : "Jim Gray",
                    "doc_count" : 10
                ,
            ]
        
    

见Elasticsearch terms aggregations。

【讨论】:

全名是什么意思? @neustart47 full_name 只是聚合的名称【参考方案3】:

现有的答案在 Elasticsearch 5.X 中对我不起作用,原因如下:

我需要在索引时标记我的输入。 "size": 0 解析失败,因为“[size] 必须大于 0。” "Fielddata is disabled on text fields by default." 这意味着默认情况下您无法搜索 full_name 字段。但是,未分析的 keyword 字段可用于聚合。

解决方案 1:使用 Scroll API。它通过保持搜索上下文并发出多个请求来工作,每次都返回后续批次的结果。如果您使用的是 Python,则 elasticsearch 模块具有 scan() helper function 来为您处理滚动并返回所有结果。

解决方案 2:使用 Search After API。它类似于 Scroll,但提供了一个实时光标而不是保留搜索上下文。因此对于实时请求更有效。

【讨论】:

我不确定这是否能解决 "size":0 问题,因为我从文档中看到的默认值是 10...【参考方案4】:

为 Elasticsearch 5.2.2 工作

curl -XGET  http://localhost:9200/articles/_search?pretty -d '

    "aggs" : 
        "whatever" : 
            "terms" :  "field" : "yourfield", "size":10000 
        
    ,
    "size" : 0
'

"size":10000 表示(最多)获得 10000 个唯一值。如果没有这个,如果您有超过 10 个唯一值,则仅返回 10 个值。

"size":0 表示结果中,"hits" 将不包含任何文档。默认返回 10 个文档,我们不需要。


参考:bucket terms aggregation

另外请注意,根据this page,在 Elasticsearch 1.0 中,facets 已被聚合取代,这是 facets 的超集。

【讨论】:

【参考方案5】:

直觉: 用 SQL 的说法:

Select distinct full_name from authors;

等价于

Select full_name from authors group by full_name;

因此,我们可以使用 ElasticSearch 中的分组/聚合语法来查找不同的条目。

假设弹性搜索中存储的结构如下:

[
    "author": "Brian Kernighan"
  ,
  
    "author": "Charles Dickens"
  ]

什么不起作用:普通聚合


  "aggs": 
    "full_name": 
      "terms": 
        "field": "author"
      
    
  

我收到以下错误:


  "error": 
    "root_cause": [
      
        "reason": "Fielddata is disabled on text fields by default...",
        "type": "illegal_argument_exception"
      
    ]
  

什么是魅力:在字段中附加 .keyword


  "aggs": 
    "full_name": 
      "terms": 
        "field": "author.keyword"
      
    
  

样本输出可能是:


  "aggregations": 
    "full_name": 
      "buckets": [
        
          "doc_count": 372,
          "key": "Charles Dickens"
        ,
        
          "doc_count": 283,
          "key": "Brian Kernighan"
        
      ],
      "doc_count": 1000
    
  

额外提示:

让我们假设有问题的字段嵌套如下:

[
    "authors": [
        "details": [
            "name": "Brian Kernighan"
          ]
      ]
  ,
  
    "authors": [
        "details": [
            "name": "Charles Dickens"
          ]
      ]
  
]

现在正确的查询变成:


  "aggregations": 
    "full_name": 
      "aggregations": 
        "author_details": 
          "terms": 
            "field": "authors.details.name"
          
        
      ,
      "nested": 
        "path": "authors.details"
      
    
  ,
  "size": 0

【讨论】:

以上是关于使用 Elasticsearch 查询字段的所有唯一值的主要内容,如果未能解决你的问题,请参考以下文章

[Elasticsearch] 关于字段重复值的常用查询和操作总结

如何在elasticsearch中为给定查询按字段获取不同的结果?

ElasticSearch查询之——Search API

ElasticSearch - SpringBoot整合ES:解析搜索返回字段

Elasticsearch和RestHighLevelClient的使用

(Elasticsearch)如何获取所有文档的嵌套字段的最后一个元素然后执行子聚合