聚合查询

通过聚合查询,您可以执行以下操作:

  • 应用简单的映射函数
  • 基于字段值对数据进行分组
  • 对分组的数据应用聚合函数

本文章解释了FT.AGGREGATE命令的基本用法。有关详细信息,请参阅命令规范聚合参考文档

本文中的示例使用以下字段的架构:

字段名称 字段类型
condition TAG
price NUMERIC

简单映射

APPLY子句允许您对返回的结果集应用一个简单的映射函数,该结果集是基于查询表达式返回的。

  1. FT.AGGREGATE index "query_expr" LOAD n "field_1" .. "field_n" APPLY "function_expr" AS "result_field"

以下是查询语法的详细解释:

  1. 查询表达式:您可以使用与FT.SEARCH命令相同的查询表达式。您可以将query_expr替换为本查询主题中解释的任何表达式。向量搜索查询是一个例外,您不能将向量搜索与聚合查询结合使用。
  2. 加载字段:如果字段值尚未加载到聚合管道中,您可以通过LOAD子句强制它们的存在。此子句接受字段数量(n),后跟字段名称("field_1" .. "field_n")。
  3. 映射函数:此映射函数作用于字段值。具体字段在函数表达式中作为@field_name引用,结果将作为result_field返回。

以下示例演示了如何为新自行车计算折扣价格:

  1. FT.AGGREGATE idx:bicycle "@condition:{new}" LOAD 2 "__key" "price" APPLY "@price - (@price * 0.1)" AS "discounted"

字段 __key 是一个内建字段。

这个查询的输出是:

  1. 1) "1"
  2. 2) 1) "__key"
  3. 1) "bicycle:0"
  4. 2) "price"
  5. 3) "270"
  6. 4) "discounted"
  7. 5) "243"
  8. 3) 1) "__key"
  9. 1) "bicycle:5"
  10. 2) "price"
  11. 3) "810"
  12. 4) "discounted"
  13. 5) "729"
  14. 4) 1) "__key"
  15. 1) "bicycle:6"
  16. 2) "price"
  17. 3) "2300"
  18. 4) "discounted"
  19. 5) "2070"
  20. ...

使用聚合进行分组

之前的示例没有进行分组。你可以根据一个或多个标准进行分组和聚合,方法如下:

  1. FT.AGGREGATE index "query_expr" ... GROUPBY n "field_1" .. "field_n" REDUCE AGG_FUNC m "@field_param_1" .. "@field_param_m" AS "aggregated_result_field"

以下是对额外构造的解释:

  1. 分组:你可以根据一个或多个字段进行分组。每个字段值的有序序列定义了一个组。也可以根据之前 APPLY ... AS 结果的值进行分组。
  2. 聚合:你必须用一个支持的聚合函数(例如,SUMCOUNT)替换 AGG_FUNC。支持的函数完整列表可以在 聚合参考文档 中找到。用你选择的值替换 aggregated_result_field

以下查询展示了如何根据字段 condition 进行分组,并根据之前推导的 price_category 应用减少。表达式 @price<1000 会使得一个自行车如果价格低于1000美元,则属于价格类别 1,否则属于价格类别 0。输出是按价格类别分组的可承受自行车数量。

  1. FT.AGGREGATE idx:bicycle "*" LOAD 1 price APPLY "@price<1000" AS price_category GROUPBY 1 @condition REDUCE SUM 1 "@price_category" AS "num_affordable"
  1. 1) "3"
  2. 2) 1) "condition"
  3. 1) "refurbished"
  4. 2) "num_affordable"
  5. 3) "1"
  6. 3) 1) "condition"
  7. 1) "used"
  8. 2) "num_affordable"
  9. 3) "1"
  10. 4) 1) "condition"
  11. 1) "new"
  12. 2) "num_affordable"
  13. 3) "3"

注意:

你也可以使用 FT.AGGREGATE 创建更复杂的聚合管道。可以在一个 GROUPBY 子句下应用多个聚合函数。此外,你还可以链式分组,并混合额外的映射步骤(例如,GROUPBY ... REDUCE ... APPLY ... GROUPBY ... REDUCE)。

无分组聚合

你不能在 GROUPBY 子句外使用聚合函数,但你可以构建管道,使聚合发生在跨越所有文档的单一组上。如果你的文档没有共享一个公共属性,你可以通过额外的 APPLY 步骤来添加它。

以下是一个示例,首先为每个文档添加一个类型属性 bicycle,然后统计所有具有该类型的文档数量:

  1. FT.AGGREGATE idx:bicycle "*" APPLY "'bicycle'" AS type GROUPBY 1 @type REDUCE COUNT 0 AS num_total

结果为:

  1. 1) "1"
  2. 2) 1) "type"
  3. 1) "bicycle"
  4. 2) "num_total"
  5. 3) "10"

无聚合的分组

有时需要在不应用数学聚合函数的情况下对数据进行分组。如果你需要一个分组后的值列表,那么 TOLIST 函数非常有用。

以下示例展示了如何按 condition 对所有自行车进行分组:

  1. FT.AGGREGATE idx:bicycle "*" LOAD 1 "__key" GROUPBY 1 "@condition" REDUCE TOLIST 1 "__key" AS bicycles

结果为:

  1. 1) "3"
  2. 2) 1) "condition"
  3. 1) "refurbished"
  4. 2) "bicycles"
  5. 3) 1) "bicycle:9"
  6. 3) 1) "condition"
  7. 1) "used"
  8. 2) "bicycles"
  9. 3) 1) "bicycle:1"
  10. 1) "bicycle:2"
  11. 2) "bicycle:3"
  12. 3) "bicycle:4"
  13. 4) 1) "condition"
  14. 1) "new"
  15. 2) "bicycles"
  16. 3) 1) "bicycle:0"
  17. 1) "bicycle:5"
  18. 2) "bicycle:6"
  19. 3) "bicycle:8"
  20. 4) "bicycle:7"