这是我偶然发现的一个非常古老的问题,所以我将展示两种不同的方法来处理这个问题。
让我们先准备索引和一些测试数据:
PUT /bookindex
{
  "mappings": {
    "book": {
      "properties": {
        "title": {
          "type": "string"
        },
        "chapters": {
          "type": "nested",
          "properties": {
            "title": {
              "type": "string"
            },
            "length": {
              "type": "long"
            }
          }
        }
      }
    }
  }
}
PUT /bookindex/book/1
{
  "title": "My first book ever",
  "chapters": [
    {
      "title": "epilogue",
      "length": 1230
    },
    {
      "title": "intro",
      "length": 200
    }
  ]
}
PUT /bookindex/book/2
{
  "title": "Book of life",
  "chapters": [
    {
      "title": "epilogue",
      "length": 17
    },
    {
      "title": "toc",
      "length": 42
    }
  ]
}
现在我们在 Elasticsearch 中有了这些数据,我们可以使用inner_hits. 这种方法非常简单,但我更喜欢最后概述的方法。
# Inner hits query
POST /bookindex/book/_search
{
  "_source": false,
  "query": {
    "nested": {
      "path": "chapters",
      "query": {
        "match": {
          "chapters.title": "epilogue"
        }
      },
      "inner_hits": {}
    }
  }
}
嵌套查询返回文档,其中inner_hits每个命中都包含一个包含inner_hits所有匹配文档的对象,包括评分信息。你可以看到响应。
我对此类查询的首选方法是使用嵌套聚合和过滤子聚合,其中包含top_hits子聚合。查询如下所示:
# Nested and filter aggregation
POST /bookindex/book/_search
{
  "size": 0,
  "aggs": {
    "nested": {
      "nested": {
        "path": "chapters"
      },
      "aggs": {
        "filter": {
          "filter": {
            "match": { "chapters.title": "epilogue" }
          },
          "aggs": {
            "t": {
              "top_hits": {
                "size": 100
              }
            }
          }
        }
      }
    }
  }
}
top_hits子聚合是实际检索嵌套文档、支持from和size属性等的聚合。从文档中:
  如果top_hits聚合器包含在 anested或reverse_nested
  聚合器中,则返回嵌套命中。嵌套命中在某种意义上是隐藏的迷你文档,它们是常规文档的一部分,其中在映射中配置了嵌套字段类型。如果这些文档包含在 a or aggregatortop_hits
  中,则聚合器可以取消隐藏这些文档。阅读有关嵌套在嵌套类型映射中的更多信息。nestedreverse_nested
Elasticsearch的响应是(IMO)更漂亮(而且它似乎返回更快(尽管这不是科学观察))并且“更容易”解析。