我是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方面完成此工作,这将使我免于修改大量现有代码。
谢谢!
答案 0 :(得分:1)
我更改了映射,以告诉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
}
]
}
}
]
}
}
}
}