FT.AGGREGATE
FT.AGGREGATE index query [VERBATIM] [LOAD count field [field ...]] [TIMEOUT timeout] [ GROUPBY nargs property [property ...] [ REDUCE function nargs arg [arg ...] [AS name] [ REDUCE function nargs arg [arg ...] [AS name] ...]] ...]] [ SORTBY nargs [ property ASC | DESC [ property ASC | DESC ...]] [MAX num] [WITHCOUNT] [ APPLY expression AS name [ APPLY expression AS name ...]] [ LIMIT offset num] [FILTER filter] [ WITHCURSOR [COUNT read_size] [MAXIDLE idle_time]] [ PARAMS nargs name value [ name value ...]] [ADDSCORES] [DIALECT dialect]
- Available in:
- Redis Stack / Search 1.1.0
- Time complexity:
- O(1)
在索引上运行搜索查询,并对结果执行聚合转换,从中提取统计信息等
必需的参数
index
是执行查询的索引名称。您必须首先使用FT.CREATE
创建索引。
query
是检索文档的基本过滤查询。它遵循与搜索查询完全相同的语法,包括过滤器、联合、非、可选等。
可选参数
VERBATIM
如果设置,不会尝试使用词干提取进行查询扩展,而是逐字搜索查询词。
LOAD {nargs} {identifier} AS {property} …
从源文档加载文档属性。
identifier
是哈希和JSON的属性名称,或者是JSON的JSON路径表达式。property
是结果中使用的可选名称。如果未提供,则使用identifier
。应避免这种情况。- 如果使用
*
作为nargs
,则加载文档中的所有属性。
聚合所需的属性应存储为SORTABLE
,这样它们可以在聚合管道中以极低的延迟使用。LOAD
会显著降低聚合查询的性能,因为每个处理的记录都需要对Redis键执行相当于HMGET
的操作,当在数百万个键上执行时,会导致高处理时间。
GROUPBY {nargs} {property}
根据一个或多个属性对管道中的结果进行分组。每个组应至少有一个reducer,这是一个处理组条目的函数,可以计数或执行多个聚合操作(见下文)。
REDUCE {func} {nargs} {arg} … [AS {name}]
使用归约函数将每个组中的匹配结果减少为单个记录。例如,COUNT
计算组中的记录数。归约器可以使用 AS {name}
可选参数来指定自己的属性名称。如果未给出名称,结果名称将是归约函数和组属性的名称。例如,如果未通过属性 @foo
给 COUNT_DISTINCT
指定名称,结果名称将是 count_distinct(@foo)
。
查看支持的GROUPBY reducers了解更多详情。
SORTBY {nargs} {property} {ASC|DESC} [MAX {num}]
使用属性列表对管道进行排序,直到SORTBY
为止。
- 默认情况下,排序是升序的,但可以为每个属性添加
ASC
或DESC
。 nargs
是排序参数的数量,包括ASC
和DESC
,例如,SORTBY 4 @foo ASC @bar DESC
。MAX
用于优化排序,通过仅对前n个最大元素进行排序。虽然它与LIMIT
无关,但在常见查询中,通常只需要SORTBY … MAX
。
SORTBY
所需的属性应存储为SORTABLE
,以便以极低的延迟可用。
排序优化: 在不同场景下对DIALECT 4
的排序操作进行了性能优化:
- 跳过排序器 - 当没有任何排序时应用。查询在达到
LIMIT
请求的结果后可以返回。 - 部分范围 - 当在数字字段上有
SORTBY
子句,且没有过滤器或通过相同的数字字段进行过滤时,查询会在足够大的范围内迭代,以满足LIMIT
请求的结果。 - 混合模式 - 当在数字字段上应用
SORTBY
子句并且存在另一个非数字过滤器时使用。一些结果将被过滤,初始范围可能不够大。然后迭代器会重新调整范围,并进行额外的迭代以收集LIMIT
所请求的结果。 - 无优化 - 如果按分数或非数字字段排序,除了检索所有结果并比较它们的值之外,没有其他选择。
计数行为: 可选的 WITHCOUNT
参数返回带有排序的查询结果的准确计数。此操作会处理所有结果以获取准确的计数,性能不如优化选项(DIALECT 4
上的默认行为)。
APPLY {expr} AS {name}
对一项或多项属性应用一对一转换,并将结果作为新属性存储在管道中,或使用此转换替换任何属性。
expr
是一个表达式,可用于对数值属性执行算术运算,或根据属性类型应用于属性的函数(见下文),或它们的任何组合。例如,APPLY "sqrt(@foo)/log(@bar) + 5" AS baz
会为管道中的每条记录动态评估此表达式,并将结果存储为名为 baz
的新属性,该属性可以在管道中的后续 APPLY
/SORTBY
/GROUPBY
/REDUCE
操作中引用。
详情请参见APPLY表达式。
LIMIT {offset} {num}
限制返回结果的数量,仅返回从索引offset
(从零开始)开始的num
个结果。如果你只对限制排序操作的输出感兴趣,使用SORTBY … MAX
会更高效。
如果在查询期间键过期,尝试load
键的值将返回一个空数组。
然而,limit 可以用于在不排序的情况下限制结果,或者用于分页显示由 SORTBY MAX
确定的前 n 个最大结果。例如,获取前 100 个结果中的第 50-100 个结果,最有效的表达方式是 SORTBY 1 @foo MAX 100 LIMIT 50 50
。从 SORTBY
中移除 MAX
会导致管道对所有记录进行排序,然后对第 50-100 个结果进行分页。
FILTER {expr}
使用与每个结果中的值相关的谓词表达式过滤结果。 它们在查询后应用,并与管道的当前状态相关。
WITHCURSOR {COUNT} {read_size} [MAXIDLE {idle_time}]
使用比LIMIT
更快的替代方案扫描部分结果。
有关更多详细信息,请参阅Cursor API。
TIMEOUT {milliseconds}
如果设置,将覆盖模块的超时参数。
PARAMS {nargs} {name} {value}
定义一个或多个值参数。每个参数都有一个名称和一个值。
你可以在query
中通过$
后跟参数名称来引用参数,例如$user
。搜索查询中每个对参数名称的引用都会被相应的参数值替换。例如,使用参数定义PARAMS 4 lon 29.69465 lat 34.95126
,表达式@loc:[$lon $lat 10 km]
会被计算为@loc:[29.69465 34.95126 10 km]
。你不能在查询字符串中引用不允许具体值的地方的参数,例如字段名称中的@loc
。要使用PARAMS
,请将DIALECT
设置为2
或大于2
。
ADDSCORES
ADDSCORES
选项将全文评分值暴露给聚合管道。
您可以在管道中使用 @__score
,如下例所示:
FT.AGGREGATE idx 'hello' ADDSCORES SORTBY 2 @__score DESC
DIALECT {dialect_version}
选择执行查询时所使用的方言版本。如果未指定,查询将在模块初始加载期间或通过FT.CONFIG SET
命令设置的默认方言版本下执行。
返回
FT.AGGREGATE 返回一个数组回复,其中每一行都是一个数组回复,代表一个单一的聚合结果。
位置 1
的 整数回复 不代表有效值。
返回多个值
参见返回多个值在FT.SEARCH
中
DIALECT
可以在FT.AGGREGATE命令中作为参数指定。如果未指定,则使用DEFAULT_DIALECT
,可以通过FT.CONFIG SET
或在加载redisearch
模块时作为参数传递来设置。
例如,使用以下文档和索引:
127.0.0.1:6379> JSON.SET doc:1 $ '[{"arr": [1, 2, 3]}, {"val": "hello"}, {"val": "world"}]'
OK
127.0.0.1:6379> FT.CREATE idx ON JSON PREFIX 1 doc: SCHEMA $..arr AS arr NUMERIC $..val AS val TEXT
OK
注意不同的回复,有和没有DIALECT 3
的情况:
127.0.0.1:6379> FT.AGGREGATE idx * LOAD 2 arr val
1) (integer) 1
2) 1) "arr"
2) "[1,2,3]"
3) "val"
4) "hello"
127.0.0.1:6379> FT.AGGREGATE idx * LOAD 2 arr val DIALECT 3
1) (integer) 1
2) 1) "arr"
2) "[[1,2,3]]"
3) "val"
4) "[\"hello\",\"world\"]"
复杂性
非确定性的。取决于执行的查询和聚合操作,但通常与返回的结果数量成线性关系。
示例
Sort page visits by day
查找访问页面 about.html
的访问记录,按访问日期分组,计算访问次数,并按日期排序。
FT.AGGREGATE idx "@url:\"about.html\""
APPLY "day(@timestamp)" AS day
GROUPBY 2 @day @country
REDUCE count 0 AS num_visits
SORTBY 4 @day
Find most books ever published
找出一年内出版最多的书籍。
FT.AGGREGATE books-idx *
GROUPBY 1 @published_year
REDUCE COUNT 0 AS num_published
GROUPBY 0
REDUCE MAX 1 @num_published AS max_books_published_per_year
Reduce all results
最后一个例子使用了GROUPBY 0
。使用GROUPBY 0
可以在聚合管道的最后一步对所有结果应用REDUCE
函数——这适用于初始查询和后续的GROUPBY
操作。
搜索经度-73.982254和纬度40.753181附近10公里内的图书馆,然后用它们的位置与这些坐标之间的距离进行标注。
FT.AGGREGATE libraries-idx "@location:[-73.982254 40.753181 10 km]"
LOAD 1 @location
APPLY "geodistance(@location, -73.982254, 40.753181)"
在这里,请注意必须使用LOAD
来预加载@location
属性,因为它是一个GEO属性。
接下来,按用户(actor)统计GitHub事件,以生成最活跃的用户。
127.0.0.1:6379> FT.AGGREGATE gh "*" GROUPBY 1 @actor REDUCE COUNT 0 AS num SORTBY 2 @num DESC MAX 10
1) (integer) 284784
2) 1) "actor"
2) "lombiqbot"
3) "num"
4) "22197"
3) 1) "actor"
2) "codepipeline-test"
3) "num"
4) "17746"
4) 1) "actor"
2) "direwolf-github"
3) "num"
4) "10683"
5) 1) "actor"
2) "ogate"
3) "num"
4) "6449"
6) 1) "actor"
2) "openlocalizationtest"
3) "num"
4) "4759"
7) 1) "actor"
2) "digimatic"
3) "num"
4) "3809"
8) 1) "actor"
2) "gugod"
3) "num"
4) "3512"
9) 1) "actor"
2) "xdzou"
3) "num"
4) "3216"
[10](10)) 1) "actor"
2) "opstest"
3) "num"
4) "2863"
11) 1) "actor"
2) "jikker"
3) "num"
4) "2794"
(0.59s)