本章到目前为止,对于数字,只介绍如何处理精确值查询。实际上,对数字范围进行过滤有时会更有用。例如,我们可能想要查找所有价格大于 $20 且小于 $40 美元的产品。
在 SQL 中,范围查询可以表示为:
SELECT document
FROM products
WHERE price BETWEEN 20 AND 40
Elasticsearch 有 range
查询,不出所料地,可以用它来查找处于某个范围内的文档:
"range" : {
"price" : {
"gte" : 20,
"lte" : 40
}
}
range
查询可同时提供包含(inclusive)和不包含(exclusive)这两种范围表达式,可供组合的选项如下:
-
gt
:>
大于(greater than) -
lt
:<
小于(less than) -
gte
:>=
大于或等于(greater than or equal to) -
lte
:⇐
小于或等于(less than or equal to)
GET /my_store/products/_search
{
"query" : {
"constant_score" : {
"filter" : {
"range" : {
"price" : {
"gte" : 20,
"lt" : 40
}
}
}
}
}
}
如果想要范围无界(比方说 >20 ),只须省略其中一边的限制:
"range" : {
"price" : {
"gt" : 20
}
}
range
查询同样可以应用在日期字段上:
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-07 00:00:00"
}
}
当使用它处理日期字段时, range
查询支持对 日期计算(date math) 进行操作,比方说,如果我们想查找时间戳在过去一小时内的所有文档:
"range" : {
"timestamp" : {
"gt" : "now-1h"
}
}
这个过滤器会一直查找时间戳在过去一个小时内的所有文档,让过滤器作为一个时间 滑动窗口(sliding window) 来过滤文档。
日期计算还可以被应用到某个具体的时间,并非只能是一个像 now 这样的占位符。只要在某个日期后加上一个双管符号 (||
) 并紧跟一个日期数学表达式就能做到:
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-01 00:00:00||+1M" (1)
}
}
-
早于 2014 年 1 月 1 日加 1 月(2014 年 2 月 1 日 零时)
日期计算是 日历相关(calendar aware) 的,所以它不仅知道每月的具体天数,还知道某年的总天数(闰年)等信息。更详细的内容可以参考: {ref}/mapping-date-format.html[时间格式参考文档] 。
range
查询同样可以处理字符串字段,字符串范围可采用 字典顺序(lexicographically) 或字母顺序(alphabetically)。例如,下面这些字符串是采用字典序(lexicographically)排序的:
-
5, 50, 6, B, C, a, ab, abb, abc, b
Note
|
在倒排索引中的词项就是采取字典顺序(lexicographically)排列的,这也是字符串范围可以使用这个顺序来确定的原因。 |
如果我们想查找从 a
到 b
(不包含)的字符串,同样可以使用 range
查询语法:
"range" : {
"title" : {
"gte" : "a",
"lt" : "b"
}
}
数字和日期字段的索引方式使高效地范围计算成为可能。但字符串却并非如此,要想对其使用范围过滤,Elasticsearch 实际上是在为范围内的每个词项都执行 term
过滤器,这会比日期或数字的范围过滤慢许多。
字符串范围在过滤 低基数(low cardinality) 字段(即只有少量唯一词项)时可以正常工作,但是唯一词项越多,字符串范围的计算会越慢。