【问题标题】:hierarchical faceting with Elasticsearch使用 Elasticsearch 进行分层刻面
【发布时间】:2013-12-16 18:31:44
【问题描述】:

我正在使用elasticsearch,需要对分层对象实现分面搜索,如下所示:

  • 类别 1 (10)
    • 子类别 1 (4)
    • 子类别 2 (6)
  • 类别 2 (X)
    • ...

所以我需要获取两个相关对象的方面。文档说可以获得数值的这种方面是可能的,但我需要它来处理字符串http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-stats-facet.html

这是另一个有趣的话题,不幸的是它很老:http://elasticsearch-users.115913.n3.nabble.com/Pivot-facets-td2981519.html

弹性搜索可以吗? 如果是这样,我该怎么做?

【问题讨论】:

    标签: lucene full-text-search elasticsearch pivot-table faceted-search


    【解决方案1】:

    之前的解决方案非常有效,直到您在单个文档上只有一个多级标签。在这种情况下,简单的聚合不起作用,因为 lucene 字段的扁平结构混合了内部聚合的结果。 请参见下面的示例:

    DELETE /test_category
    POST /test_category
    
    # Insert a doc with 2 hierarchical tags 
    POST /test_category/test/1 
    {
      "categories": [
        {
          "cat_1": "1",
          "cat_2": "1.1"
        },
        {
          "cat_1":  "2",
          "cat_2": "2.2"
        }
      ]
    }
    
    # Simple two-levels aggregations query
    GET /test_category/test/_search?search_type=count
    {
      "aggs": {
        "main_category": {
          "terms": {
            "field": "categories.cat_1"
          },
          "aggs": {
            "sub_category": {
              "terms": {
                "field": "categories.cat_2"
              }
            }
          }
        }
      }
    }
    

    这是我在 ES 1.4 上得到的错误响应,其中内部聚合的字段在文档级别混合:

    {
       ...
       "aggregations": {
          "main_category": {
             "buckets": [
                {
                   "key": "1",
                   "doc_count": 1,
                   "sub_category": {
                      "buckets": [
                         {
                            "key": "1.1",
                            "doc_count": 1
                         },
                         {
                            "key": "2.2",  <= WRONG
                            "doc_count": 1
                         }
                      ]
                   }
                },
                {
                   "key": "2",
                   "doc_count": 1,
                   "sub_category": {
                      "buckets": [
                         {
                            "key": "1.1", <= WRONG
                            "doc_count": 1
                         },
                         {
                            "key": "2.2",
                            "doc_count": 1
                         }
                      ]
                   }
                }
             ]
          }
       }
    }
    

    解决方案可以是使用嵌套对象。这些是要做的步骤:

    1) 用嵌套对象在模式中定义一个新类型

    POST /test_category/test2/_mapping
    {
      "test2": {
        "properties": {
          "categories": {
            "type": "nested",
            "properties": {
              "cat_1": {
                "type": "string"
              },
              "cat_2": {
                "type": "string"
              }
            }
          }
        }
      }
    }
    
    # Insert a single document 
    POST /test_category/test2/1 
    {"categories":[{"cat_1":"1","cat_2":"1.1"},{"cat_1":"2","cat_2":"2.2"}]}
    

    2) 运行嵌套聚合查询:

    GET /test_category/test2/_search?search_type=count
    {
      "aggs": {
        "categories": {
          "nested": {
            "path": "categories"
          },
          "aggs": {
            "main_category": {
              "terms": {
                "field": "categories.cat_1"
              },
              "aggs": {
                "sub_category": {
                  "terms": {
                    "field": "categories.cat_2"
                  }
                }
              }
            }
          }
        }
      }
    }
    

    这就是我得到的响应,现在是正确的:

    {
           ...
           "aggregations": {
              "categories": {
                 "doc_count": 2,
                 "main_category": {
                    "buckets": [
                       {
                          "key": "1",
                          "doc_count": 1,
                          "sub_category": {
                             "buckets": [
                                {
                                   "key": "1.1",
                                   "doc_count": 1
                                }
                             ]
                          }
                       },
                       {
                          "key": "2",
                          "doc_count": 1,
                          "sub_category": {
                             "buckets": [
                                {
                                   "key": "2.2",
                                   "doc_count": 1
                                }
                             ]
                          }
                       }
                    ]
                 }
              }
           }
        }
    

    相同的解决方案可以扩展到多于两级的层次结构方面。

    【讨论】:

      【解决方案2】:

      目前,elasticsearch 不支持开箱即用的分层分面。但是即将发布的 1.0 版本具有一个新的 aggregations 模块,可用于获取这些方面(更像是枢轴方面而不是分层方面)。 1.0 版目前处于测试阶段,您可以download the second beta 并自行测试聚合。您的示例可能看起来像

      curl -XPOST 'localhost:9200/_search?pretty' -d '
      {
         "aggregations": {
            "main category": {
               "terms": {
                  "field": "cat_1",
                  "order": {"_term": "asc"}
               },
               "aggregations": {
                  "sub category": {
                     "terms": {
                        "field": "cat_2",
                        "order": {"_term": "asc"}
                     }
                  }
               }
            }
         }
      }'
      

      我们的想法是,为每个级别的分面设置不同的字段,并根据第一级 (cat_1) 的条款对您的分面进行分类。然后,这些聚合将具有子存储桶,基于第二级 (cat_2) 的条款。结果可能看起来像

      {
        "aggregations" : {
          "main category" : {
            "buckets" : [ {
              "key" : "category 1",
              "doc_count" : 10,
              "sub category" : {
                "buckets" : [ {
                  "key" : "subcategory 1",
                  "doc_count" : 4
                }, {
                  "key" : "subcategory 2",
                  "doc_count" : 6
                } ]
              }
            }, {
              "key" : "category 2",
              "doc_count" : 7,
              "sub category" : {
                "buckets" : [ {
                  "key" : "subcategory 1",
                  "doc_count" : 3
                }, {
                  "key" : "subcategory 2",
                  "doc_count" : 4
                } ]
              }
            } ]
          }
        }
      }
      

      【讨论】:

      • 谢谢!此外,在 github 和相关帖子上发现了错误,该错误说它将在 ES 1.0 中修复。 Beta 2 中已经提供了实现。现在就开始玩吧 :) 谢谢!
      • @knutwalker,您能否修改从 elasticsearch 6.4 开始的答案?我在这里发布了我的问题:stackoverflow.com/q/52940790/681676
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      相关资源
      最近更新 更多