嵌套聚合编辑

一种特殊的单桶聚合,可以对嵌套文档进行聚合。

例如,假设我们有一个产品索引,每个产品都包含经销商列表 - 每个经销商都有自己的产品价格。映射可能如下所示

response = client.indices.create(
  index: 'products',
  body: {
    mappings: {
      properties: {
        resellers: {
          type: 'nested',
          properties: {
            reseller: {
              type: 'keyword'
            },
            price: {
              type: 'double'
            }
          }
        }
      }
    }
  }
)
puts response
PUT /products
{
  "mappings": {
    "properties": {
      "resellers": { 
        "type": "nested",
        "properties": {
          "reseller": {
            "type": "keyword"
          },
          "price": {
            "type": "double"
          }
        }
      }
    }
  }
}

resellers 是一个包含嵌套文档的数组。

以下请求添加了一个包含两个经销商的产品

response = client.index(
  index: 'products',
  id: 0,
  refresh: true,
  body: {
    name: 'LED TV',
    resellers: [
      {
        reseller: 'companyA',
        price: 350
      },
      {
        reseller: 'companyB',
        price: 500
      }
    ]
  }
)
puts response
PUT /products/_doc/0?refresh
{
  "name": "LED TV", 
  "resellers": [
    {
      "reseller": "companyA",
      "price": 350
    },
    {
      "reseller": "companyB",
      "price": 500
    }
  ]
}

我们正在为 name 属性使用动态映射。

以下请求返回购买产品所需的最低价格

response = client.search(
  index: 'products',
  size: 0,
  body: {
    query: {
      match: {
        name: 'led tv'
      }
    },
    aggregations: {
      resellers: {
        nested: {
          path: 'resellers'
        },
        aggregations: {
          min_price: {
            min: {
              field: 'resellers.price'
            }
          }
        }
      }
    }
  }
)
puts response
GET /products/_search?size=0
{
  "query": {
    "match": {
      "name": "led tv"
    }
  },
  "aggs": {
    "resellers": {
      "nested": {
        "path": "resellers"
      },
      "aggs": {
        "min_price": {
          "min": {
            "field": "resellers.price"
          }
        }
      }
    }
  }
}

如您所见,嵌套聚合需要顶级文档中嵌套文档的 path。然后,您可以定义对这些嵌套文档的任何类型的聚合。

响应

{
  ...
  "aggregations": {
    "resellers": {
      "doc_count": 2,
      "min_price": {
        "value": 350.0
      }
    }
  }
}

您可以使用 filter 子聚合来返回特定经销商的结果。

response = client.search(
  index: 'products',
  size: 0,
  body: {
    query: {
      match: {
        name: 'led tv'
      }
    },
    aggregations: {
      resellers: {
        nested: {
          path: 'resellers'
        },
        aggregations: {
          filter_reseller: {
            filter: {
              bool: {
                filter: [
                  {
                    term: {
                      'resellers.reseller' => 'companyB'
                    }
                  }
                ]
              }
            },
            aggregations: {
              min_price: {
                min: {
                  field: 'resellers.price'
                }
              }
            }
          }
        }
      }
    }
  }
)
puts response
GET /products/_search?size=0
{
  "query": {
    "match": {
      "name": "led tv"
    }
  },
  "aggs": {
    "resellers": {
      "nested": {
        "path": "resellers"
      },
      "aggs": {
        "filter_reseller": {
          "filter": {
            "bool": {
              "filter": [
                {
                  "term": {
                    "resellers.reseller": "companyB"
                  }
                }
              ]
            }
          },
          "aggs": {
            "min_price": {
              "min": {
                "field": "resellers.price"
              }
            }
          }
        }
      }
    }
  }
}

搜索返回

{
  ...
  "aggregations": {
    "resellers": {
      "doc_count": 2,
      "filter_reseller": {
        "doc_count": 1,
        "min_price": {
          "value": 500.0
        }
      }
    }
  }
}