Elasticsearch结构化查询
查找准确值
term用于数字
term主要用在处理数字,布尔值,日期和文本
GET /my_store/products/_search
{
"query" : {
"filtered" : { <>
"query" : {
"match_all" : {} <>
},
"filter" : {
"term" : { <>
"price" :
}
}
}
}
}
- filtered 查询同时接受 query 与 filter
- match_all 用来匹配所有文档,这是默认行为,所以在以后的例子中我们将省略掉 query 部分
- 这是我们上面见过的 term 过滤器,注意它在 filter 分句中的位置
term用于文本
内部过滤操作
组合过滤
布尔过滤器
bool 过滤器由三部分组成:
{
"bool" : {
"must" : [],
"should" : [],
"must_not" : [],
}
}
must:所有分句都必须匹配,跟AND相同
must_not:所有分句都必须不匹配,跟NOT相同
should:至少有一个分句匹配,与OR相同
SELECT product
FROM products
WHERE (price = OR productID = "XHDK-A-1293-#fJ3")
AND (price != )
# 转换成DSL
GET /my_store/products/_search
{
"query" : {
"filtered" : { <>
"filter" : {
"bool" : {
"should" : [
{ "term" : {"price" : }}, <>
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}} <>
],
"must_not" : {
"term" : {"price" : } <>
}
}
}
}
}
}
嵌套布尔过滤器
虽然 bool 是一个组合过滤器而且接受子过滤器,需明白它自己仍然只是一个过滤器。这意味着你可以在 bool 过滤器中嵌套 bool 过滤器,让你实现更复杂的布尔逻辑
SELECT document
FROM products
WHERE productID = "KDKE-B-9947-#kL5"
OR ( productID = "JODL-X-1937-#pV7"
AND price = )
# 转化为DSL
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"productID" : "KDKE-B-9947-#kL5"}}, <>
{ "bool" : { <>
"must" : [
{ "term" : {"productID" : "JODL-X-1937-#pV7"}}, <>
{ "term" : {"price" : }} <>
]
}}
]
}
}
}
}
}
查询多个准确值
比起使用多个 term 过滤器,你可以用一个 terms 过滤器。terms 过滤器是 term 过滤器的复数版本
# 寻找 20 或 30 元的文档
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"terms" : {
"price" : [, ]
}
}
}
}
}
term/terms:包含,而不是相等
term和terms都是包含操作,而不是相等操作
实例:过滤器{ “term” : { “tags” : “search” } }将匹配下面两个文档:
{ "tags" : ["search"] }
{ "tags" : ["search", "open_source"] }
工作原理:
term过滤器检查倒排索引中具有短语的文档,然后组成一个字节集,在我们简单实例中,我们有下面的倒排索引:
token | docsIDs |
---|---|
open_source | 2 |
search | 1,2 |
当执行 term 过滤器来查询 search 时,它直接在倒排索引中匹配值并找出相关的 ID。如你所见,文档 1 和文档 2 都包含 search,所以他们都作为结果集返回。
提示: 倒排索引的特性让完全匹配一个字段变得非常困难。你将如何确定一个文档只能包含你请求的短语?你将在索引中找出这个短语,解出所有相关文档 ID,然后扫描 索引中每一行来确定文档是否包含其他值。
由此可见,这将变得非常低效和开销巨大。因此,term 和 terms 是 必须包含 操作,而不是 必须相等。
范围
range 过滤器既能包含也能排除范围,通过下面的选项:
- gt: > 大于
- lt: < 小于
- gte: >= 大于或等于
- lte: <= 小于或等于
SELECT document
FROM products
WHERE price BETWEEN AND
# 转化为DSL
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"range" : {
"price" : {
"gte" : ,
"lt" :
}
}
}
}
}
}
日期范围
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-07 00:00:00"
}
}
当用于日期字段时,range 过滤器支持日期数学操作。例如,我们想找到所有最近一个小时的文档:
"range" : {
"timestamp" : {
"gt" : "now-1h"
}
}
这个过滤器将始终能找出所有时间戳大于当前时间减 1 小时的文档,让这个过滤器像移窗一样通过你的文档。
日期计算也能用于实际的日期,而不是仅仅是一个像 now 一样的占位符。只要在日期后加上双竖线 ||,就能使用日期数学表达式了。
# 早于 2014 年 1 月 1 号加一个月
"range" : {
"timestamp" : {
"gt" : "2014-01-01 00:00:00",
"lt" : "2014-01-01 00:00:00||+1M" <>
}
}
字符串范围
range 过滤器也可以用于字符串。字符串范围根据字典或字母顺序来计算。例如,这些值按照字典顺序排序:
* 5, 50, 6, B, C, a, ab, abb, abc, b
假如我们想让范围从 a 开始而不包含 b,我们可以用类似的 range 过滤器语法:
"range" : {
"title" : {
"gte" : "a",
"lt" : "b"
}
}
当心基数:
数字和日期字段的索引方式让他们在计算范围时十分高效。但对于字符串来说却不是这样。为了在字符串上执行范围操作,Elasticsearch 会在这个范围内的每个短语执行 term 操作。这比日期或数字的范围操作慢得多。
字符串范围适用于一个基数较小的字段,一个唯一短语个数较少的字段。你的唯一短语数越多,搜索就越慢。