查询语法
学习如何使用查询语法
基本语法
您可以使用这些规则使用简单语法进行复杂的查询
-
确切的短语用引号括起来,例如
"hello world"
。 -
多词短语是标记列表,例如
foo bar baz
,并隐含术语的交集(AND)。 -
OR
并集用管道 (|
) 字符表示,例如hello|hallo|shalom|hola
。注意:
请考虑示例
hello world | "goodbye" moon
中解析器行为的差异- 在 DIALECT 1 中,此查询被解释为搜索
(hello world | "goodbye") moon
。 - 在 DIALECT 2 或更高版本中,此查询被解释为搜索
hello world
**或**"goodbye" moon
。
- 在 DIALECT 1 中,此查询被解释为搜索
-
NOT
表达式或子查询的否定用减号 (-
) 表示,例如hello -world
。还支持纯负查询,例如-foo
和-@title:(foo|bar)
。注意:
考虑一个带有否定的简单查询
-hello world
- 在 DIALECT 1 中,此查询被解释为“在任何不包含
hello
**且** 不包含world
的字段中查找值”。等效于-(hello world)
或-hello -world
。 - 在 DIALECT 2 或更高版本中,此查询被解释为
as -hello
**和**world
(仅否定hello
)。 - 在 DIALECT 2 或更高版本中,要实现 DIALECT 1 的默认行为,请将您的查询更新为
-(hello world)
。
- 在 DIALECT 1 中,此查询被解释为“在任何不包含
-
前缀/中缀/后缀匹配(所有以术语开头/包含/结尾的术语)用星号
*
表示。出于性能原因,强制执行最小术语长度。默认值为 2,但可配置。 -
在 DIALECT 2 或更高版本中,通配符模式匹配表示为
"w'foo*bar?'"
。请注意使用双引号来包含 *w* 模式。 -
返回索引中所有结果的特殊通配符查询只是星号
*
。这不能与其他选项结合使用。 -
从 v2.6.1 开始,
DIALECT 3
从多值属性返回 JSON 而不是标量。 -
使用语法
hello @field:world
选择特定字段。 -
使用语法
@field:[{min} {max}]
对数值字段进行数值范围匹配。 -
使用语法
@field:[{lon} {lat} {radius} {m|km|mi|ft}]
对地理字段进行 Georadius 匹配。 -
从 2.6 开始,使用语法
@field:[VECTOR_RANGE {radius} $query_vec]
对向量字段进行范围查询,其中query_vec
作为查询参数给出。 -
从 v2.4 开始,使用语法
{filter_query}=>[KNN {num} @field $query_vec]
对向量字段进行带有或不带有预过滤的 k 近邻 (KNN) 查询。 -
使用语法
@field:{tag | tag | ...}
对标签字段进行过滤。有关标签的完整文档,请参见 标签。 -
可选术语或子句:
foo ~bar
表示 bar 是可选的,但包含bar
的文档排名更高。 -
术语的模糊匹配:
%hello%
表示与之具有 1 的莱文斯坦距离的所有术语。使用多对 '%' 括号,最多三层,以增加莱文斯坦距离。 -
查询中的表达式可以用括号括起来以消除歧义,例如
(hello|hella) (world|werld)
。 -
查询属性可以应用于单个子句,例如
(foo bar) => { $weight: 2.0; $slop: 1; $inorder: false; }
。 -
可以将上述组合组合在一起,例如
hello (world|foo) "bar baz" bbbb
。
纯负查询
从 v0.19.3 开始,可以有一个仅包含否定表达式的查询。例如 -hello
或 -(@title:(foo|bar))
。结果是所有不包含查询术语的文档。
字段修饰符
您可以在查询中指定字段修饰符,而不仅仅是使用 INFIELDS
全局关键字。
要指定查询匹配的字段,请在每个表达式或子表达式之前添加 @
符号、字段名称和 :
(冒号)符号。
如果字段修饰符在多个单词或表达式之前,它仅应用于使用 DIALECT 1 的相邻表达式。使用 DIALECT 2 或更高版本,您可以将查询扩展到其他字段。
考虑这个简单的查询:@name:James Brown
。这里,字段修饰符 @name
后面跟着两个词:James
和 Brown
。
- 在 DIALECT 1 中,此查询将被解释为“在
@name
字段中查找James Brown
”。 - 在 DIALECT 2 或更高版本中,此查询将被解释为“在
@name
字段中查找James
**和** 在 **任何** 文本字段中查找Brown
。换句话说,它将被解释为(@name:James) Brown
。 - 在 DIALECT 2 或更高版本中,要实现 DIALECT 1 的默认行为,请将您的查询更新为
@name:(James Brown)
。
如果字段修饰符在括号中的表达式之前,它仅应用于括号内的表达式。该表达式应该对指定的字段有效,否则将被跳过。
要对多个字段进行复杂的过滤,您可以组合多个修饰符。例如,如果您有一个包含汽车型号的索引,包括车辆类别、原产国和发动机类型,您可以使用以下查询搜索在韩国制造的具有混合动力或柴油发动机的 SUV
FT.SEARCH cars "@country:korea @engine:(diesel|hybrid) @class:suv"
您可以对同一术语或分组术语应用多个修饰符
FT.SEARCH idx "@title|body:(hello world) @url|image:mydomain"
现在,您搜索在正文或标题中同时包含 "hello"
和 "world"
,并且在其 url
或 image
字段中包含 mydomain
术语的文档。
查询中的数字过滤器
如果模式中的字段定义为 NUMERIC,则可以在 Redis 请求中使用 FILTER 参数或通过在查询中指定过滤规则来使用它进行过滤。语法为 @field:[{min} {max}]
,例如 @price:[100 200]
。
关于数字谓词的一些说明
-
可以将数字谓词指定为整个查询,而使用
FILTER
参数则不可能做到这一点。 -
可以在同一查询中对多个数字过滤器进行交集或并集运算,无论是针对同一字段还是不同字段。
-
-inf
、inf
和+inf
是范围内可接受的数字。因此,*大于 100* 表示为[(100 inf]
。 -
数字过滤器是包含的。独占最小值或最大值用
(
放在数字前表示,例如[(100 (200]
。 -
可以通过在过滤器前添加
-
符号来否定数字过滤器。例如,返回价格与 100 不同的结果表示为:@title:foo -@price:[100 100]
。
标签过滤器
从 v0.91 开始,您可以使用一种称为 标签字段 的特殊字段类型,它具有更简单的 标记化 并在索引中进行编码。您无法使用一般的无字段搜索访问这些字段中的值。相反,您使用特殊的语法
@field:{ tag | tag | ...}
示例
@cities:{ New York | Los Angeles | Barcelona }
标签可以包含多个单词或包含除字段分隔符 (默认情况下为 ,
) 之外的其他标点符号。标签中的以下字符应使用反斜杠 (\
) 进行转义:$
、{
、}
、\
和 |
。
DIALECT 2
或更高版本,您可以在 tag
查询中使用空格,即使包含停用词也是如此。请注意,同一个子句中的多个标签会创建一个包含任一标签的文档的并集。要创建包含所有标签的文档的交集,您应该多次重复标签过滤器。例如
# Return all documents containing all three cities as tags
@cities:{ New York } @cities:{Los Angeles} @cities:{ Barcelona }
# Now, return all documents containing either city
@cities:{ New York | Los Angeles | Barcelona }
标签子句可以组合成任何子句,用作否定表达式、可选表达式等等。
地理过滤器
从 v0.21 开始,可以使用语法 @field:[{lon} {lat} {radius} {m|km|mi|ft}]
将地理半径查询直接添加到查询语言中。这会将结果过滤到距以米、公里、英里或英尺定义的经纬度点的给定半径范围内。有关更多详细信息,请参见 Redis 自身的 GEORADIUS
命令。
半径过滤器可以像数字过滤器一样添加到查询中。例如,在企业数据库中,查找旧金山附近的中国餐馆(半径 5 公里内)将表示为:chinese restaurant @location:[-122.41 37.77 5 km]
。
多边形搜索
地理空间数据库对于管理和分析各种行业中的基于位置的数据至关重要。它们帮助组织做出数据驱动的决策、优化运营并更有效地实现其战略目标。多边形搜索扩展了 Redis 的地理空间搜索功能,能够根据 GEOSHAPE
属性中的值进行查询。该值必须遵循 "众所周知的文本" (WKT) 几何表示。支持两种此类几何
POINT
,例如POINT(2 4)
。POLYGON
,例如POLYGON((2 2, 2 8, 6 11, 10 8, 10 2, 2 2))
。
有一种名为 GEOSHAPE
的新的模式字段类型,可以将其指定为以下两种方式之一
FLAT
针对笛卡尔 X Y 坐标SPHERICAL
针对地理经度和纬度坐标。这是默认坐标系。
最后,有一个新的 FT.SEARCH
语法,它允许您查询包含或位于给定地理形状内的多边形。
@field:[{WITHIN|CONTAINS} $geometry] PARAMS 2 geometry {geometry}
以下是一个使用两个堆叠的多边形来表示一个包含在房屋内的盒子为例。
首先,使用 FLAT
GEOSHAPE
创建一个索引,表示二维 X Y 坐标系。
FT.CREATE polygon_idx PREFIX 1 shape: SCHEMA g GEOSHAPE FLAT t TEXT
接下来,创建表示图像中几何图形的数据结构。
HSET shape:1 t "this is my house" g "POLYGON((2 2, 2 8, 6 11, 10 8, 10 2, 2 2))"
HSET shape:2 t "this is a square in my house" g "POLYGON((4 4, 4 6, 6 6, 6 4, 4 4))"
最后,使用 FT.SEARCH
查询几何图形。请注意使用 DIALECT 3
,这是必需的。以下是一些示例。
搜索包含指定点的多边形
FT.SEARCH polygon_idx "@g:[CONTAINS $point]" PARAMS 2 point 'POINT(8 8)' DIALECT 3
1) (integer) 1
2) "shape:1"
3) 1) "t"
2) "this is my house"
3) "g"
4) "POLYGON((2 2, 2 8, 6 11, 10 8, 10 2, 2 2))"
搜索包含在指定多边形内的几何图形
FT.SEARCH polygon_idx "@g:[WITHIN $poly]" PARAMS 2 poly 'POLYGON((0 0, 0 100, 100 100, 100 0, 0 0))' DIALECT 3
1) (integer) 2
2) "shape:2"
3) 1) "t"
2) "this is a square in my house"
3) "g"
4) "POLYGON((4 4, 4 6, 6 6, 6 4, 4 4))"
4) "shape:1"
5) 1) "t"
2) "this is my house"
3) "g"
4) "POLYGON((2 2, 2 8, 6 11, 10 8, 10 2, 2 2))"
搜索未包含在索引几何图形中的多边形
FT.SEARCH polygon_idx "@g:[CONTAINS $poly]" PARAMS 2 poly 'POLYGON((14 4, 14 6, 16 6, 16 4, 14 4))' DIALECT 3
1) (integer) 0
搜索已知包含在几何图形(盒子)内的多边形
FT.SEARCH polygon_idx "@g:[CONTAINS $poly]" PARAMS 2 poly 'POLYGON((4 4, 4 6, 6 6, 6 4, 4 4))' DIALECT 3
1) (integer) 2
2) "shape:1"
3) 1) "t"
2) "this is my house"
3) "g"
4) "POLYGON((2 2, 2 8, 6 11, 10 8, 10 2, 2 2))"
4) "shape:2"
5) 1) "t"
2) "this is a square in my house"
3) "g"
4) "POLYGON((4 4, 4 6, 6 6, 6 4, 4 4))"
请注意,房屋和盒子形状都已返回。
有关更多示例,请参阅 FT.CREATE
和 FT.SEARCH
命令页面。
向量搜索
您可以通过以下方式将向量相似度查询直接添加到查询语言中:
-
使用 范围 查询,语法为
@vector:[VECTOR_RANGE {radius} $query_vec]
,这会将结果过滤到给定查询向量给定半径范围内。距离度量来自索引模式中 @vector 字段的定义,例如余弦或 L2(截至 v2.6.1)。 -
在 @vector 字段上运行 k 最近邻 (KNN) 查询。基本语法是
"*=>[ KNN {num|$num} @vector $query_vec ]"
。也可以在过滤后的结果上运行混合查询。混合查询允许用户指定 KNN 查询中所有结果必须满足的过滤条件。过滤条件可以包括任何类型的字段(即,在向量和其他值(例如 TEXT、PHONETIC、NUMERIC、GEO 等)上创建的索引)。混合查询的通用语法是{some filter query}=>[ KNN {num|$num} @vector $query_vec]
,其中=>
将过滤查询与向量 KNN 查询分开。
示例
-
返回 10 个最近的邻居实体,其中
query_vec
最接近存储在@vector_field
中的向量*=>[KNN 10 @vector_field $query_vec]
-
在 2020 年至 2022 年之间发布的实体中,返回 10 个最近的邻居实体,其中
query_vec
最接近存储在@vector_field
中的向量@published_year:[2020 2022]=>[KNN 10 @vector_field $query_vec]
-
返回所有实体,其中存储在其 @vector_field 下的向量与
query_vec
之间的距离最多为 0.5,以 @vector_field 距离度量表示@vector_field:[VECTOR_RANGE 0.5 $query_vec]
截至 v2.4,KNN 向量搜索最多可以在查询中使用一次,而截至 v2.6,向量范围过滤器可以在查询中使用多次。有关向量相似度语法的更多信息,请参阅 查询向量字段 和 向量搜索示例 部分。
前缀匹配
当索引更新时,Redis 会维护一个包含索引中所有术语的字典。这可以用来匹配所有以给定前缀开头的术语。选择前缀匹配是通过将 *
附加到前缀标记来完成的。例如
hel* world
将扩展为涵盖 (hello|help|helm|...) world
。
关于前缀搜索的一些注意事项
-
由于前缀可以扩展为许多术语,因此请谨慎使用它们。扩展将创建所有后缀的并集操作。
-
作为防止选择过多术语的保护措施,从而阻止单线程的 Redis,前缀匹配有两个限制
-
前缀限制为 2 个或更多个字母。您可以使用模块命令行上的
MINPREFIX
设置来更改此数字。 -
最小词干长度为 4 个或更多个字母。您可以使用模块命令行上的
MINSTEMLEN
设置来更改此数字。 -
扩展限制为 200 个或更少的术语。您可以使用模块命令行上的
MAXEXPANSIONS
设置来更改此数字。
-
前缀匹配完全支持 Unicode 且不区分大小写。
-
目前,没有基于后缀流行度的排序或偏差。
中缀/后缀匹配
截至 v2.6.0,字典可用于中缀(包含)或后缀查询,方法是将 *
附加到标记。例如
*sun* *ing
这些查询是 CPU 密集型的,因为它们需要遍历整个字典。
使用后缀树
后缀树维护一个匹配后缀的术语列表。如果您使用 WITHSUFFIXTRIE
关键字将后缀树添加到字段,则可以创建更高效的中缀和后缀查询,因为它消除了遍历整个字典的必要性。但是,并集上的迭代不会改变。
后缀查询创建从后缀项节点的术语列表的并集。中缀查询使用后缀项作为树的前缀,并创建所有匹配节点的所有术语的并集。
通配符匹配
截至 v2.6.0,您可以使用这些参数使用字典进行通配符匹配查询。
?
- 匹配任何单个字符*
- 匹配重复零次或多次的任何字符- ' 和 \ - 用于转义;其他特殊字符将被忽略
语法的示例是 "w'foo*bar?'"
。
使用后缀树
后缀树维护一个匹配后缀的术语列表。如果您使用 WITHSUFFIXTRIE
关键字将后缀树添加到字段,则可以创建更高效的通配符匹配查询,因为它消除了遍历整个字典的必要性。但是,并集上的迭代不会改变。
使用后缀树,通配符模式在每个 *
字符处被分成标记。使用启发式方法选择术语最少的标记,并使用通配符模式匹配每个术语。
模糊匹配
截至 v1.2.0,索引中所有术语的字典也可以用来执行 模糊匹配。模糊匹配基于 莱文斯坦距离 (LD) 执行。对术语执行模糊匹配是通过用 '%' 括起术语来完成的,例如
%hello% world
这会对 hello
执行模糊匹配,适用于所有 LD 为 1 的术语。
截至 v1.4.0,模糊匹配的 LD 可以通过周围 '%' 字符的数量来设置,因此 %%hello%%
将对 'hello' 执行模糊匹配,适用于所有 LD 为 2 的术语。
模糊匹配的最大 LD 为 3。
通配符查询
截至 v1.1.0,您可以使用特殊查询检索索引中的所有文档。这主要用于聚合引擎。您可以通过仅指定单个星号作为查询字符串来调用它,换句话说,FT.SEARCH myIndex *
。
您不能将它与任何其他过滤器、字段修饰符或查询中的任何内容组合在一起。从技术上讲,可以在查询字符串之外使用已弃用的 FILTER
和 GEOFILTER
请求参数与通配符结合使用,但这会使通配符毫无意义,只会降低性能。
查询属性
截至 v1.2.0,您可以将特定查询修改属性应用于查询的特定子句。
语法是 (foo bar) => { $attribute: value; $attribute:value; ...}
(foo bar) => { $weight: 2.0; $slop: 1; $inorder: true; }
~(bar baz) => { $weight: 0.5; }
支持的属性是
- $weight:确定子查询或标记在结果的整体排名中的权重(默认值:1.0)。
- $slop:确定查询子句中允许的最大间隙(术语之间的空格)(默认值:0)。
- $inorder:查询子句中的术语是否必须按照查询中的顺序出现。这通常与
$slop
一起设置(默认值:false)。 - $phonetic:是否执行语音匹配(默认值:true)。注意:将此属性设置为 true 用于未作为
PHONETIC
创建的字段将产生错误。
截至 v2.6.1,查询属性语法支持以下附加属性
- $yield_distance_as:指定距离字段名称,用于以后排序和/或返回,用于产生某些距离度量的子句。目前仅支持向量查询(KNN 和范围)。
- 向量查询参数:以键值对格式传递 向量查询 的可选参数。
一些查询示例
-
简单短语查询 -
hello
ANDworld
hello world
-
精确短语查询 -
hello
FOLLOWED BYworld
"hello world"
-
并集 - 包含
hello
ORworld
的文档hello|world
-
非 - 包含
hello
BUT NOTworld
的文档hello -world
-
并集的交集
(hello|halo) (world|werld)
-
并集的否定
hello -(world|werld)
-
短语内的并集
(barack|barrack) obama
-
包含更多匹配项的可选术语优先于包含更多匹配项的术语
obama ~barack ~michelle
-
一个字段中的精确短语,另一个字段中的一个词
@title:"barack obama" @job:president
-
组合 AND、OR 与字段说明符
@title:"hello world" @body:(foo bar) @category:(articles|biographies)
-
前缀/中缀/后缀查询
hello worl* hel* *worl hello -*worl*
-
通配符匹配查询
"w'foo??bar??baz'" "w'???????'" "w'hello*world'"
-
数值过滤 - 命名为
tv
的产品,价格范围为 200 到 500@name:tv @price:[200 500]
-
数值过滤 - 年龄大于 18 的用户
@age:[(18 +inf]
将常见的 SQL 谓词映射到搜索和查询
SQL 条件 | 搜索和查询等效项 | 注释 |
---|---|---|
WHERE x='foo' AND y='bar' | @x:foo @y:bar | 为了减少歧义,请使用 (@x:foo) (@y:bar) |
WHERE x='foo' AND y!='bar' | @x:foo -@y:bar | |
WHERE x='foo' OR y='bar' | (@x:foo)|(@y:bar) | |
WHERE x IN ('foo', 'bar','hello world') | @x:(foo|bar|"hello world") | 引号表示精确短语 |
WHERE y='foo' AND x NOT IN ('foo','bar') | @y:foo (-@x:foo) (-@x:bar) | |
WHERE x NOT IN ('foo','bar') | -@x:(foo|bar) | |
WHERE num BETWEEN 10 AND 20 | @num:[10 20] | |
WHERE num >= 10 | @num:[10 +inf] | |
WHERE num > 10 | @num:[(10 +inf] | |
WHERE num < 10 | @num:[-inf (10] | |
WHERE num <= 10 | @num:[-inf 10] | |
WHERE num < 10 OR num > 20 | @num:[-inf (10] | @num:[(20 +inf] | |
WHERE name LIKE 'john%' | @name:john* |
技术说明
查询解析器使用 Lemon 解析器生成器和基于 Ragel 的词法分析器构建。您可以在 此 git 仓库 中看到 DIALECT 2
语法定义。
您还可以看到 DEFAULT_DIALECT 配置参数。