ES-子存储桶基于存储桶属性中的值而不是文档值

时间:2018-11-13 16:18:50

标签: elasticsearch

我是ElasticSearch的新手,我想按层次结构对来自搜索的对象进行存储。

对于问题的长度,我事先表示歉意,但我想提供足够的样本和信息,以使需求尽可能清楚。

我要实现的目标

问题在于类别构成层次结构,但被表示为对象的平面阵列,每个对象都有深度。我想生成一个按类别和类别深度进行分类的聚合。

这是仅包含最少数据的文档的简化映射:

{
  "mappings": {
    "_doc": {
      "properties": {
        "categoriesList": {
          "properties": {
            "depth": {
              "type": "long"
            },
            "title": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        }
      }
    }
  }
}

这是一个简化的示例文档:

{
  "_index": "x",
  "_type": "_doc",
  "_id": "wY0w5GYBOIOl7fi31c_b",
  "_score": 22.72073,
  "_source": {
    "categoriesList": [
      {
        "title": "category_lvl_2_2",
        "depth": 2
      },
      {
        "title": "category_lvl_2",
        "depth": 2,
      },
      {
        "title": "category_lvl_1",
        "depth": 1
      }
    ]
  }
}

现在,我要实现的目标是根据深度对类别进行分层存储,即我想要一个存储区,其中包含所有匹配中深度为1的所有类别标题,然后是另一个存储区(或子存储区)以及所有匹配中的深度为2的类别的标题,依此类推。 像这样:

"aggregations": {
    "depth": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 1,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_1",
                "doc_count": 47,
                "depth_1": {
                  "doc_count": 47
                }
              }
            ]
          }
        },
        {
          "key": 2,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_2_1",
                "doc_count": 47
              },
              {
                "key": "category_lvl_2_2",
                "doc_count": 33
              }
            ]
          }
        }
      ]
    }
  }

我尝试过的

起初,我试图简单地创建嵌套聚合,如下所示:

  "aggs": {
    "depth": {
      "terms": {
        "field": "categoriesList.depth"
      },
      "aggs": {
        "name": {
          "terms": {
            "field": "categoriesList.title.keyword"
          },
        }
      }
    }
  }

这当然没有提供我想要的。它基本上给了我一些桶,这些桶的键是按深度排列的,但是无论深度如何,它都包含所有类别的所有标题。内容是相同的。类似于以下内容:

  "aggregations": {
    "depth": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": 1,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_1",
                "doc_count": 47
              },
              {
                "key": "category_lvl_2_1",
                "doc_count": 33
              },
              {
                "key": "category_lvl_2_2",
                "doc_count": 15
              }
            ]
          }
        },
        {
          "key": 2,
          "doc_count": 47,
          "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "category_lvl_1",
                "doc_count": 47
              },
              {
                "key": "category_lvl_2_1",
                "doc_count": 33
              },
              {
                "key": "category_lvl_2_2",
                "doc_count": 15
              }
            ]
          }
        }
      ]
    }
  }

然后,我尝试通过尝试按深度1的值过滤一个子存储桶来查看过滤后的聚合是否有效:

  "aggs": {
    "depth": {
      "terms": {
        "field": "categoriesList.depth"
      },
      "aggs": {
        "name": {
          "terms": {
            "field": "categoriesList.title.keyword"
          },
          "aggs": {
            "depth_1": {
              "filter": {
                "term": {
                  "categoriesList.depth": 1
                }
              }
            }
          }
        }
      }
    }
  }

这给出了与上面的简单聚合查询相同的结果,但是额外的嵌套级别没有用。

问题

以我目前对ES的理解,我所看到的是有道理的:它遍历搜索中的每个文档,然后根据类别深度创建存储桶,但是由于每个文档至少具有一个深度的类别,因此整个类别列表已添加到存储桶中。

我想用ES做些什么吗?我感觉这是行不通的,因为我基本上是在尝试存储和筛选初始存储查询所使用的属性,而不是处理文档属性。

我也可以直接在代码中存储自己,因为我们正在获取类别结果,但是我想知道是否有可能在ES方面完成此工作,这将使我免于修改大量现有代码。

谢谢!

1 个答案:

答案 0 :(得分:1)

根据enter image description here的评论,我进行了以下操作以使其正常运行:

使用指定嵌套类型的映射创建索引

我更改了映射,以告诉ES类别列表属性是一个嵌套对象。为此,我使用以下映射创建了一个新索引:

{
  "mappings": {
    "_doc": {
      "properties": {
        "categoriesList": {
          "type": "nested",
          "properties": {
            "depth": {
              "type": "long"
            },
            "title": {
              "type": "text",
              "fields": {
                "keyword": {
                  "type": "keyword",
                  "ignore_above": 256
                }
              }
            }
          }
        }
      }
    }
  }
}

重新索引到新索引

然后我将旧索引重新索引到新索引。

{
  "source": {
    "index": "old_index"
  },
  "dest": {
    "index": "index_with_nested_mapping"
  }
}

使用嵌套聚合

然后我使用了类似于以下的嵌套聚合:

{
  "aggs": {
    "categories": {
      "nested": {
        "path": "categoriesList"
      },
      "aggs": {
        "depth": {
          "terms": {
            "field": "categoriesList.depth"
          },
          "aggs": {
            "sub-categories": {
              "terms": {
                "field": "categoriesList.title.keyword"
              }
            }
          }
        }
      }
    }
  }
}

哪个给了我我想要的结果:

{
  "aggregations": {
    "categories": {
      "doc_count": 96,
      "depth": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": 2,
            "doc_count": 49,
            "sub-categories": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "category_lvl_2_1",
                  "doc_count": 33
                },
                {
                  "key": "category_lvl_2_2",
                  "doc_count": 15
                }
              ]
            }
          },
          {
            "key": 1,
            "doc_count": 47,
            "sub-categories": {
              "doc_count_error_upper_bound": 0,
              "sum_other_doc_count": 0,
              "buckets": [
                {
                  "key": "category_lvl_1",
                  "doc_count": 47
                }
              ]
            }
          }
        ]
      }
    }
  }
}