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

标签 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方面完成此工作,这将使我免于修改大量现有代码。

谢谢!

最佳答案

根据sramalingam24的评论,我进行了以下操作以使其工作:

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

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

{
  "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
                }
              ]
            }
          }
        ]
      }
    }
  }
}

关于elasticsearch - ES-基于存储桶属性中的值而不是文档值的子存储桶,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53285218/

相关文章:

javascript - Delete By Query API 以 curl 方式工作,但不在 Node-Red 中

syntax - 针对特定索引的 Elasticsearch 查询

logstash - 屏蔽许可证过期后使用Kibana

elasticsearch - Elasticsearch搜索被勒索软件锁定

elasticsearch - 在 Elasticsearch 上将字段类型从文本迁移到关键字

scala - java.lang.IllegalArgumentException:无法解析查询:{“query”:

elasticsearch - 在 Elasticsearch 中过滤出分支

java - Elasticsearch查询不会间歇性地获取结果

elasticsearch - 不使用 Elastic APM 将 OpenTelemetry 导出到 Elastic Search

elasticsearch - 数据操作的API命名约定