【问题标题】:Elasticsearch aggregation with hierarchical category, subcategory; limit the levels具有分层类别、子类别的 Elasticsearch 聚合;限制级别
【发布时间】:2018-10-23 03:36:32
【问题描述】:

我有带有类别字段的产品。使用聚合我可以获得包含所有子类别的完整类别。我想限制方面的级别。

例如我有这样的方面:

auto, tools & travel    (115)
auto, tools & travel > luggage tags (90)
auto, tools & travel > luggage tags > luggage spotters  (40)
auto, tools & travel > luggage tags > something else    (50)
auto, tools & travel > car organizers   (25)

使用聚合之类的

"aggs": {
    "cat_groups": {
      "terms": {
        "field": "categories.keyword",
        "size": 10,
       "include": "auto, tools & travel > .*"
      }
    }
}

我得到了喜欢的桶

"buckets": [
        {
          "auto, tools & travel > luggage tags",
          "doc_count": 90
        },
        {
          "key": "auto, tools & travel > luggage tags > luggage spotters",
          "doc_count": 40
        },
        {
          "key": "auto, tools & travel > luggage tags > something else",
          "doc_count": 50
        },
        {
          "key": "auto, tools & travel > car organizers",
          "doc_count": 25
        }
]

但我想限制级别。例如我只想获得auto, tools & travel > luggage tags 的结果。如何限制级别? 顺便说一句,"exclude": ".* > .* > .*" 不适合我。

我需要根据搜索得到不同级别的桶。有时一级,有时二级或三级。当我想要第一级时,我不希望第二级出现在存储桶上;以此类推其他级别。

Elasticsearch 6.4 版

【问题讨论】:

    标签: elasticsearch elastic-stack


    【解决方案1】:

    我终于能够弄清楚以下技术。

    我已经使用Path Hierarchy Tokenizer 实现了custom analyzer,并且我创建了名为categories 的多字段,以便您可以将categories.facets 用于聚合/构面,并使用categories 进行普通文本搜索。

    自定义分析器仅适用于categories.facets

    请注意属性"fielddata": "true" 我的字段categories.facet

    映射

    PUT myindex
    {
      "settings": {
        "analysis": {
          "analyzer": {
            "my_analyzer": {
              "tokenizer": "my_tokenizer"
            }
          },
          "tokenizer": {
            "my_tokenizer": {
              "type": "path_hierarchy",
              "delimiter": ">"
            }
          }
        }
      },
      "mappings": {
        "mydocs": {
          "properties": {
            "categories": {
              "type": "text",
              "fields": {
                "facet": { 
                  "type":  "text",
                  "analyzer": "my_analyzer",
                  "fielddata": "true"
                }
              }
            }
          }
        }
      }
    }
    

    示例文档

    POST myindex/mydocs/1
    {
        "categories" : "auto, tools & travel > luggage tags > luggage spotters"
    }
    
    POST myindex/mydocs/2
    {
        "categories" : "auto, tools & travel > luggage tags > luggage spotters"
    }
    
    POST myindex/mydocs/3
    {
        "categories" : "auto, tools & travel > luggage tags > luggage spotters"
    }
    
    POST myindex/mydocs/4
    {
        "categories" : "auto, tools & travel > luggage tags > something else"
    }
    

    查询

    您可以尝试以下您正在寻找的查询。我再次实现了Filter Aggregation,因为您只需要特定的单词以及Terms Aggregation

    {
      "size": 0,
      "aggs":{
        "facets": {
          "filter": { 
              "bool": {
                "must": [
                  { "match": { "categories": "luggage"} }
                ]
             }
          },
          "aggs": {
            "categories": {
              "terms": {
                "field": "categories.facet"
              }
            }
          }
        }
      }
    }
    

    响应

    {
        "took": 43,
        "timed_out": false,
        "_shards": {
            "total": 1,
            "successful": 1,
            "skipped": 0,
            "failed": 0
        },
        "hits": {
            "total": 11,
            "max_score": 0,
            "hits": []
        },
        "aggregations": {
            "facets": {
                "doc_count": 4,
                "categories": {
                    "doc_count_error_upper_bound": 0,
                    "sum_other_doc_count": 0,
                    "buckets": [
                        {
                            "key": "auto, tools & travel ",
                            "doc_count": 4
                        },
                        {
                            "key": "auto, tools & travel > luggage tags ",
                            "doc_count": 4
                        },
                        {
                            "key": "auto, tools & travel > luggage tags > luggage spotters",
                            "doc_count": 3
                        },
                        {
                            "key": "auto, tools & travel > luggage tags > something else",
                            "doc_count": 1
                        }
                    ]
                }
            }
        }
    }
    

    关于聊天的最终答案发布讨论

    POST myindex/_search
    {
      "size": 0,
      "aggs":{
        "facets": {
          "filter": { 
              "bool": {
                "must": [
                  { "match": { "categories": "luggage"} }
              ]
            }
          },
          "aggs": {
            "categories": {
              "terms": {
                "field": "categories.facet",
                "exclude": ".*>{1}.*>{1}.*"
              }
            }
          }
        }
      }
    }
    

    请注意,我添加了 excluderegular expression,因此它不会考虑任何出现多次 > 的方面

    如果有帮助,请告诉我。

    【讨论】:

    • 谢谢,但这对限制类别级别没有任何作用。
    • @Mainuddin 您现在可以检查答案吗?我已经更新了。
    • 你能检查一下聊天室吗?
    • @MiDaa 是的,这是正确的。它仅适用于text 字段,因为keyword 不使用analyzer。除非您对该字段有大量数据,否则您不必担心性能部分。当涉及到sortingaggregation 查询时,据说使用keyword 而不是textfielddata: true,但它不适用于这种情况,在其他方面这是我们唯一的选择有。希望澄清。
    • @Kamal 刚刚做了 :)
    【解决方案2】:

    只需添加一个名为 level 的整数字段,表示您的类别在层次结构中的级别。只需计算分隔符“>”的出现次数并将其保存为值。然后将 rangeQuery 添加到您的 boolQuery。

    将此添加到您的架构中:

    "level": {
        "type": "integer",
        "store": "true",
        "index": "true"
    }
    

    在您的代码中,您有类似这样的内容,它计算表示层次结构级别的分隔符的数量(没有分隔符意味着主类别):

    public Builder(final String path) {
        this.path = path;
        this.level = StringUtils.countMatches(path, DELIMITER);
    }
    

    然后您的查询搜索可能会是这样的:

    {
        "query": {
            "bool": {
                "filter": [
                    {
                        "prefix": {
                            "category": {
                                "value": "auto, tools & travel",
                                "boost": 1
                            }
                        }
                    },
                    {
                        "range": {
                            "level": {
                                "from": 2,
                                "to": 4,
                                "include_lower": true,
                                "include_upper": true,
                                "boost": 1
                            }
                        }
                    }
                ],
                "adjust_pure_negative": true,
                "boost": 1
            }
        }
    }
    

    【讨论】:

    • 你可以通过提供一些演示代码更好地帮助他:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-24
    • 2021-12-15
    • 2019-02-26
    • 2020-09-15
    • 1970-01-01
    • 2013-05-08
    • 1970-01-01
    相关资源
    最近更新 更多