Elasticsearch 中的多字段聚合

Posted

技术标签:

【中文标题】Elasticsearch 中的多字段聚合【英文标题】:Multi-field aggregation in Elasticsearch 【发布时间】:2021-02-14 09:10:31 【问题描述】:

我在 elasticsearch 中有一个文档索引,每个文档有 480 个字段。我要做的是搜索一个词(例如“apple”),并获取其值与搜索词匹配的所有唯一字段名称。 因此,如果我的文档是:


  "field1": "123",
  "field2": "apple stock",
  "field3": "red apple",
,

  "field1": "apple",
  "field2": "apple stock",
  "field3": "green apple",

作为查询的结果,我希望得到的是这样的聚合:


  "field1": ["apple"],
  "field2": ["apple stock"],
  "field3": ["red apple", "green apple"]

由于每个文档都有大约 480 个字段,我更喜欢执行 multi_match 查询,而不是包含所有字段的过滤器:

"query": 
        "multi_match": 
            "query": "apple",
            "type": "phrase"
        
    

在 elasticsearch 中是否可以进行此查询?

【问题讨论】:

【参考方案1】:

既然你“不知道你不知道什么”,你可能不得不求助于scripted metric aggregation:

POST myindex/_search

  "size": 0,
  "query": 
    "multi_match": 
      "query": "apple",
      "type": "phrase"
    
  ,
  "aggs": 
    "fields_breakdown": 
      "scripted_metric": 
        "params": 
          "phrase": "apple"
        , 
        "init_script": "state.key_map = [:];",
        "map_script": """
          for (def pair : params._source.entrySet()) 
            def val = pair.getValue();
            
            if (!(val instanceof String) || !val.toLowerCase().contains(params.phrase.toLowerCase())) 
              continue;
            
            
            def key = pair.getKey();
            
            if (!state.key_map.containsKey(key)) 
              state.key_map[key] = [val];
             else if (!state.key_map[key].contains(val)) 
              state.key_map[key].add(val);
            
          
        """,
        "combine_script": "return state",
        "reduce_script": "return states"
      
    
  

此代码无法很好地扩展(取决于您的索引大小),因此请谨慎使用它,也许可以分批使用(通过使用更严格的查询或限制一次聚合的字段数)。

顺便说一句,I proposed a solution 不久前用于过滤类似术语的聚合中的子字符串 - 这里可能与您相关。

【讨论】:

谢谢。我用邮递员尝试了上面的查询,它崩溃了,可能是因为索引大小。 这就是我所担心的。【参考方案2】:

我实际上正在考虑使用highlight 来获取与查询匹配的值,然后在代码中删除重复项。


    "query": 
        "multi_match": 
            "query": "apple",
            "type": "phrase"
        
    ,
    "highlight": 
        "pre_tags": [
            ""
        ],
        "post_tags": [
            ""
        ],
        "fields": 
            "*": 
        
    

【讨论】:

那很好。然后,您可以使用 elastic-dump 下载/流式传输所有内容,然后以您选择的语言对其进行后期处理。

以上是关于Elasticsearch 中的多字段聚合的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch:Elasticsearch 中的父级和兄弟级聚合

Elasticsearch:如何使 Elasticsearch 和 Kibana 中的文本字段可聚合?

Elasticsearch:如何使 Elasticsearch 和 Kibana 中的文本字段可聚合?

elasticsearch - 聚合返回 key 中的术语,但不是完整的字段,我怎样才能返回完整的字段?

Elasticsearch 中的术语聚合返回单词而不是完整字段值的存储桶

Elasticsearch日期之间的聚合字段