ES結構化查詢
Elasticsearch結構化查詢
查詢準確值
term用於數字
term主要用在處理數字,布林值,日期和文字
GET /my_store/products/_search
{
"query" : {
"filtered" : { <1>
"query" : {
"match_all" : {} <2>
},
"filter" : {
"term" : { <3>
"price" : 20
}
}
}
}
}
- 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 = 20 OR productID = "XHDK-A-1293-#fJ3")
AND (price != 30)
# 轉換成DSL
GET /my_store/products/_search
{
"query" : {
"filtered" : { <1>
"filter" : {
"bool" : {
"should" : [
{ "term" : {"price" : 20}}, <2>
{ "term" : {"productID" : "XHDK-A-1293-#fJ3"}} <2>
],
"must_not" : {
"term" : {"price" : 30} <3>
}
}
}
}
}
}
巢狀布林過濾器
雖然 bool 是一個組合過濾器而且接受子過濾器,需明白它自己仍然只是一個過濾器。這意味著你可以在 bool 過濾器中巢狀 bool 過濾器,讓你實現更復雜的布林邏輯
SELECT document
FROM products
WHERE productID = "KDKE-B-9947-#kL5"
OR ( productID = "JODL-X-1937-#pV7"
AND price = 30 )
# 轉化為DSL
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"bool" : {
"should" : [
{ "term" : {"productID" : "KDKE-B-9947-#kL5"}}, <1>
{ "bool" : { <1>
"must" : [
{ "term" : {"productID" : "JODL-X-1937-#pV7"}}, <2>
{ "term" : {"price" : 30}} <2>
]
}}
]
}
}
}
}
}
查詢多個準確值
比起使用多個 term 過濾器,你可以用一個 terms 過濾器。terms 過濾器是 term 過濾器的複數版本
# 尋找 20 或 30 元的文件
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"terms" : {
"price" : [20, 30]
}
}
}
}
}
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 20 AND 40
# 轉化為DSL
GET /my_store/products/_search
{
"query" : {
"filtered" : {
"filter" : {
"range" : {
"price" : {
"gte" : 20,
"lt" : 40
}
}
}
}
}
}
日期範圍
"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" <1>
}
}
字串範圍
range 過濾器也可以用於字串。字串範圍根據字典或字母順序來計算。例如,這些值按照字典順序排序:
* 5, 50, 6, B, C, a, ab, abb, abc, b
假如我們想讓範圍從 a 開始而不包含 b,我們可以用類似的 range 過濾器語法:
"range" : {
"title" : {
"gte" : "a",
"lt" : "b"
}
}
當心基數:
數字和日期欄位的索引方式讓他們在計算範圍時十分高效。但對於字串來說卻不是這樣。為了在字串上執行範圍操作,Elasticsearch 會在這個範圍內的每個短語執行 term 操作。這比日期或數字的範圍操作慢得多。
字串範圍適用於一個基數較小的欄位,一個唯一短語個數較少的欄位。你的唯一短語數越多,搜尋就越慢。