簡易 查詢 —query-string search— 對于用命令行進行即席查詢(ad-hoc)是非常有用的。然而,為了充分利用查詢的強大功能,你應(yīng)該使用 請求體 search
API, 之所以稱之為請求體查詢(Full-Body Search),因為大部分參數(shù)是通過 Http 請求體而非查詢字符串來傳遞的。
請求體查詢 —下文簡稱 查詢—不僅可以處理自身的查詢請求,還允許你對結(jié)果進行片段強調(diào)(高亮)、對所有或部分結(jié)果進行聚合分析,同時還可以給出 你是不是想找 的建議,這些建議可以引導(dǎo)使用者快速找到他想要的結(jié)果。
空查詢
讓我們以最簡單的 search API 的形式開啟我們的旅程,空查詢將返回所有索引庫(indices)中的所有文檔:
GET /_search
{}
只用一個查詢字符串,你就可以在一個、多個或者 _all 索引庫(indices)中查詢:
GET /index_2014*/_search
{}
同時你可以使用 from 和 size 參數(shù)來分頁:
GET /_search
{
"from": 30,
"size": 10
}
一個帶請求體的 GET 請求?
某些特定語言(特別是 JavaScript)的 HTTP 庫是不允許 GET 請求帶有請求體的。事實上,一些使用者對于 GET 請求可以帶請求體感到非常的吃驚。
而事實是這個RFC文檔 RFC 7231— 一個專門負(fù)責(zé)處理 HTTP 語義和內(nèi)容的文檔?—?并沒有規(guī)定一個帶有請求體的 GET 請求應(yīng)該如何處理!結(jié)果是,一些 HTTP 服務(wù)器允許這樣子,而有一些?—?特別是一些用于緩存和代理的服務(wù)器?—?則不允許。
對于一個查詢請求,Elasticsearch 的工程師偏向于使用 GET 方式,因為他們覺得它比 POST 能更好的描述信息檢索(retrieving information)的行為。然而,因為帶請求體的 GET 請求并不被廣泛支持,所以 search API同時支持 POST 請求:
POST /_search
{
"from": 30,
"size": 10
}
類似的規(guī)則可以應(yīng)用于任何需要帶請求體的 GET API。
我們將在聚合 聚合 章節(jié)深入介紹聚合(aggregations),而現(xiàn)在,我們將聚焦在查詢。
相對于使用晦澀難懂的查詢字符串的方式,一個帶請求體的查詢允許我們使用 查詢領(lǐng)域特定語言(query domain-specific language) 或者 Query DSL 來寫查詢語句。
查詢表達式
查詢表達式(Query DSL)是一種非常靈活又富有表現(xiàn)力的 查詢語言。 Elasticsearch 使用它可以以簡單的 JSON 接口來展現(xiàn) Lucene 功能的絕大部分。在你的應(yīng)用中,你應(yīng)該用它來編寫你的查詢語句。它可以使你的查詢語句更靈活、更精確、易讀和易調(diào)試。
要使用這種查詢表達式,只需將查詢語句傳遞給 query 參數(shù):
GET /_search
{
"query": YOUR_QUERY_HERE
}
空查詢(empty search) —{}— 在功能上等價于使用 match_all 查詢, 正如其名字一樣,匹配所有文檔:
GET /_search
{
"query": {
"match_all": {}
}
}
查詢語句的結(jié)構(gòu)
一個查詢語句的典型結(jié)構(gòu):
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
如果是針對某個字段,那么它的結(jié)構(gòu)如下:
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
舉個例子,你可以使用 match 查詢語句 來查詢 tweet 字段中包含 elasticsearch 的 tweet:
{
"match": {
"tweet": "elasticsearch"
}
}
完整的查詢請求如下:
GET /_search
{
"query": {
"match": {
"tweet": "elasticsearch"
}
}
}
合并查詢語句
查詢語句(Query clauses) 就像一些簡單的組合塊,這些組合塊可以彼此之間合并組成更復(fù)雜的查詢。這些語句可以是如下形式:
- 葉子語句(Leaf clauses) (就像 match 語句) 被用于將查詢字符串和一個字段(或者多個字段)對比。
- 復(fù)合(Compound) 語句 主要用于 合并其它查詢語句。 比如,一個 bool 語句 允許在你需要的時候組合其它語句,無論是 must 匹配、 must_not 匹配還是 should 匹配,同時它可以包含不評分的過濾器(filters):
{
"bool": {
"must": { "match": { "tweet": "elasticsearch" }},
"must_not": { "match": { "name": "mary" }},
"should": { "match": { "tweet": "full text" }},
"filter": { "range": { "age" : { "gt" : 30 }} }
}
}
一條復(fù)合語句可以合并 任何 其它查詢語句,包括復(fù)合語句,了解這一點是很重要的。這就意味著,復(fù)合語句之間可以互相嵌套,可以表達非常復(fù)雜的邏輯。
例如,以下查詢是為了找出信件正文包含 business opportunity 的星標(biāo)郵件,或者在收件箱正文包含 business opportunity 的非垃圾郵件:
{
"bool": {
"must": { "match": { "email": "business opportunity" }},
"should": [
{ "match": { "starred": true }},
{ "bool": {
"must": { "match": { "folder": "inbox" }},
"must_not": { "match": { "spam": true }}
}}
],
"minimum_should_match": 1
}
}
到目前為止,你不必太在意這個例子的細(xì)節(jié),我們會在后面詳細(xì)解釋。最重要的是你要理解到,一條復(fù)合語句可以將多條語句?—?葉子語句和其它復(fù)合語句?—?合并成一個單一的查詢語句。
查詢與過濾
Elasticsearch 使用的查詢語言(DSL)擁有一套查詢組件,這些組件可以以無限組合的方式進行搭配。這套組件可以在以下兩種情況下使用:過濾情況(filtering context)和查詢情況(query context)。
當(dāng)使用于 過濾情況 時,查詢被設(shè)置成一個“不評分”或者“過濾”查詢。即,這個查詢只是簡單的問一個問題:“這篇文檔是否匹配?”?;卮鹨彩欠浅5暮唵?,yes 或者 no ,二者必居其一。
- created 時間是否在 2013 與 2014 這個區(qū)間?
- status 字段是否包含 published 這個單詞?
- lat_lon 字段表示的位置是否在指定點的 10km 范圍內(nèi)?
當(dāng)使用于 查詢情況 時,查詢就變成了一個“評分”的查詢。和不評分的查詢類似,也要去判斷這個文檔是否匹配,同時它還需要判斷這個文檔匹配的有 多好(匹配程度如何)。 此查詢的典型用法是用于查找以下文檔:
- 查找與 full text search 這個詞語最佳匹配的文檔
- 包含 run 這個詞,也能匹配 runs 、 running 、 jog 或者 sprint
- 包含 quick 、 brown 和 fox 這幾個詞 — 詞之間離的越近,文檔相關(guān)性越高
- 標(biāo)有 lucene 、 search 或者 java 標(biāo)簽 — 標(biāo)簽越多,相關(guān)性越高
一個評分查詢計算每一個文檔與此查詢的 相關(guān)程度,同時將這個相關(guān)程度分配給表示相關(guān)性的字段 _score,并且按照相關(guān)性對匹配到的文檔進行排序。這種相關(guān)性的概念是非常適合全文搜索的情況,因為全文搜索幾乎沒有完全 “正確” 的答案。
自 Elasticsearch 問世以來,查詢與過濾(queries and filters)就獨自成為 Elasticsearch 的組件。但從 Elasticsearch 2.0 開始,過濾(filters)已經(jīng)從技術(shù)上被排除了,同時所有的查詢(queries)擁有變成不評分查詢的能力。
然而,為了明確和簡單,我們用 “filter” 這個詞表示不評分、只過濾情況下的查詢。你可以把 “filter” 、 “filtering query” 和 “non-scoring query” 這幾個詞視為相同的。
相似的,如果單獨地不加任何修飾詞地使用 “query” 這個詞,我們指的是 “scoring query” 。
性能差異
過濾查詢(Filtering queries)只是簡單的檢查包含或者排除,這就使得計算起來非??臁?紤]到至少有一個過濾查詢(filtering query)的結(jié)果是 “稀少的”(很少匹配的文檔),并且經(jīng)常使用不評分查詢(non-scoring queries),結(jié)果會被緩存到內(nèi)存中以便快速讀取,所以有各種各樣的手段來優(yōu)化查詢結(jié)果。
相反,評分查詢(scoring queries)不僅僅要找出匹配的文檔,還要計算每個匹配文檔的相關(guān)性,計算相關(guān)性使得它們比不評分查詢費力的多。同時,查詢結(jié)果并不緩存。
多虧倒排索引(inverted index),一個簡單的評分查詢在匹配少量文檔時可能與一個涵蓋百萬文檔的filter表現(xiàn)的一樣好,甚至?xí)谩5窃谝话闱闆r下,一個filter 會比一個評分的query性能更優(yōu)異,并且每次都表現(xiàn)的很穩(wěn)定。
過濾(filtering)的目標(biāo)是減少那些需要通過評分查詢(scoring queries)進行檢查的文檔。
如何選擇查詢與過濾
通常的規(guī)則是,使用查詢(query)語句來進行 全文 搜索或者其它任何需要影響 相關(guān)性得分 的搜索。除此以外的情況都使用過濾(filters)。
最重要的查詢
雖然 Elasticsearch 自帶了很多的查詢,但經(jīng)常用到的也就那么幾個。我們將在 深入搜索 章節(jié)詳細(xì)討論那些查詢的細(xì)節(jié),接下來我們對最重要的幾個查詢進行簡單介紹。
match_all 查詢
match_all 查詢簡單的匹配所有文檔。在沒有指定查詢方式時,它是默認(rèn)的查詢:
{ "match_all": {}}
它經(jīng)常與 filter 結(jié)合使用—?例如,檢索收件箱里的所有郵件。所有郵件被認(rèn)為具有相同的相關(guān)性,所以都將獲得分值為 1 的中性 _score。
match 查詢
無論你在任何字段上進行的是全文搜索還是精確查詢,match 查詢是你可用的標(biāo)準(zhǔn)查詢。
如果你在一個全文字段上使用 match 查詢,在執(zhí)行查詢前,它將用正確的分析器去分析查詢字符串:
{ "match": { "tweet": "About Search" }}
如果在一個精確值的字段上使用它,例如數(shù)字、日期、布爾或者一個 not_analyzed 字符串字段,那么它將會精確匹配給定的值:
{ "match": { "age": 26 }}
{ "match": { "date": "2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "tag": "full_text" }}
對于精確值的查詢,你可能需要使用 filter 語句來取代 query,因為 filter 將會被緩存。接下來,我們將看到一些關(guān)于 filter 的例子。
不像我們在 輕量 搜索 章節(jié)介紹的字符串查詢(query-string search), match 查詢不使用類似 +user_id:2 +tweet:search 的查詢語法。它只是去查找給定的單詞。這就意味著將查詢字段暴露給你的用戶是安全的;你需要控制那些允許被查詢字段,不易于拋出語法異常。
multi_match 查詢
multi_match 查詢可以在多個字段上執(zhí)行相同的 match 查詢:
{
"multi_match": {
"query": "full text search",
"fields": [ "title", "body" ]
}
}
range 查詢
range 查詢找出那些落在指定區(qū)間內(nèi)的數(shù)字或者時間:
{
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}
被允許的操作符如下:
- gt——大于
- gte——大于等于
- lt——小于
- lte——小于等于
term 查詢
term 查詢被用于精確值匹配,這些精確值可能是數(shù)字、時間、布爾或者那些 not_analyzed 的字符串:
{ "term": { "age": 26 }}
{ "term": { "date": "2014-09-01" }}
{ "term": { "public": true }}
{ "term": { "tag": "full_text" }}
term 查詢對于輸入的文本不 分析 ,所以它將給定的值進行精確查詢。
terms 查詢
terms 查詢和 term 查詢一樣,但它允許你指定多值進行匹配。如果這個字段包含了指定值中的任何一個值,那么這個文檔滿足條件:
{ "terms": { "tag": [ "search", "full_text", "nosql" ] }}
和 term 查詢一樣,terms 查詢對于輸入的文本不分析。它查詢那些精確匹配的值(包括在大小寫、重音、空格等方面的差異)。
exists 查詢和 missing 查詢
exists 查詢和 missing 查詢被用于查找那些指定字段中有值 (exists) 或無值 (missing) 的文檔。這與SQL中的 IS_NULL (missing) 和 NOT IS_NULL (exists) 在本質(zhì)上具有共性:
{
"exists": {
"field": "title"
}
}
這些查詢經(jīng)常用于某個字段有值的情況和某個字段缺值的情況。
組合多查詢
現(xiàn)實的查詢需求從來都沒有那么簡單;它們需要在多個字段上查詢多種多樣的文本,并且根據(jù)一系列的標(biāo)準(zhǔn)來過濾。為了構(gòu)建類似的高級查詢,你需要一種能夠?qū)⒍嗖樵兘M合成單一查詢的查詢方法。
你可以用 bool 查詢來實現(xiàn)你的需求。這種查詢將多查詢組合在一起,成為用戶自己想要的布爾查詢。它接收以下參數(shù):
must
- 文檔 必須 匹配這些條件才能被包含進來。
must_not - 文檔 必須不 匹配這些條件才能被包含進來。
should - 如果滿足這些語句中的任意語句,將增加 _score ,否則,無任何影響。它們主要用于修正每個文檔的相關(guān)性得分。
filter - 必須 匹配,但它以不評分、過濾模式來進行。這些語句對評分沒有貢獻,只是根據(jù)過濾標(biāo)準(zhǔn)來排除或包含文檔。
由于這是我們看到的第一個包含多個查詢的查詢,所以有必要討論一下相關(guān)性得分是如何組合的。每一個子查詢都獨自地計算文檔的相關(guān)性得分。一旦他們的得分被計算出來, bool 查詢就將這些得分進行合并并且返回一個代表整個布爾操作的得分。
下面的查詢用于查找 title 字段匹配 how to make millions 并且不被標(biāo)識為 spam 的文檔。那些被標(biāo)識為 starred 或在2014之后的文檔,將比另外那些文檔擁有更高的排名。如果 兩者 都滿足,那么它排名將更高:
{
"bool": {
"must": { "match": { "title": "how to make millions" }},
"must_not": { "match": { "tag": "spam" }},
"should": [
{ "match": { "tag": "starred" }},
{ "range": { "date": { "gte": "2014-01-01" }}}
]
}
}
如果沒有 must 語句,那么至少需要能夠匹配其中的一條 should 語句。但,如果存在至少一條 must 語句,則對 should 語句的匹配沒有要求。
增加帶過濾器(filtering)的查詢
如果我們不想因為文檔的時間而影響得分,可以用 filter 語句來重寫前面的例子:
{
"bool": {
"must": { "match": { "title": "how to make millions" }},
"must_not": { "match": { "tag": "spam" }},
"should": [
{ "match": { "tag": "starred" }}
],
"filter": {
"range": { "date": { "gte": "2014-01-01" }}
}
}
}
range 查詢已經(jīng)從 should 語句中移到 filter 語句
通過將 range 查詢移到 filter 語句中,我們將它轉(zhuǎn)成不評分的查詢,將不再影響文檔的相關(guān)性排名。由于它現(xiàn)在是一個不評分的查詢,可以使用各種對 filter 查詢有效的優(yōu)化手段來提升性能。
所有查詢都可以借鑒這種方式。將查詢移到 bool 查詢的 filter 語句中,這樣它就自動的轉(zhuǎn)成一個不評分的 filter 了。
如果你需要通過多個不同的標(biāo)準(zhǔn)來過濾你的文檔,bool 查詢本身也可以被用做不評分的查詢。簡單地將它放置到 filter 語句中并在內(nèi)部構(gòu)建布爾邏輯:
{
"bool": {
"must": { "match": { "title": "how to make millions" }},
"must_not": { "match": { "tag": "spam" }},
"should": [
{ "match": { "tag": "starred" }}
],
"filter": {
"bool": {
"must": [
{ "range": { "date": { "gte": "2014-01-01" }}},
{ "range": { "price": { "lte": 29.99 }}}
],
"must_not": [
{ "term": { "category": "ebooks" }}
]
}
}
}
}
將 bool 查詢包裹在 filter 語句中,我們可以在過濾標(biāo)準(zhǔn)中增加布爾邏輯
constant_score 查詢
盡管沒有 bool 查詢使用這么頻繁,constant_score 查詢也是你工具箱里有用的查詢工具。它將一個不變的常量評分應(yīng)用于所有匹配的文檔。它被經(jīng)常用于你只需要執(zhí)行一個 filter 而沒有其它查詢(例如,評分查詢)的情況下。
可以使用它來取代只有 filter 語句的 bool 查詢。在性能上是完全相同的,但對于提高查詢簡潔性和清晰度有很大幫助。
{
"constant_score": {
"filter": {
"term": { "category": "ebooks" }
}
}
}
term 查詢被放置在 constant_score 中,轉(zhuǎn)成不評分的 filter。這種方式可以用來取代只有 filter 語句的 bool 查詢。
驗證查詢
查詢可以變得非常的復(fù)雜,尤其和不同的分析器與不同的字段映射結(jié)合時,理解起來就有點困難了。不過 validate-query API 可以用來驗證查詢是否合法。
GET /gb/_validate/query
{
"query": {
"tweet" : {
"match" : "really powerful"
}
}
}
以上 validate 請求的應(yīng)答告訴我們這個查詢是不合法的:
{
"valid": false
}
理解錯誤信息
為了找出 查詢不合法的原因,可以將 explain 參數(shù) 加到查詢字符串中:
GET /gb/_validate/query?explain
{
"query": {
"tweet" : {
"match" : "really powerful"
}
}
}
explain 參數(shù)可以提供更多關(guān)于查詢不合法的信息。
很明顯,我們將查詢類型(match)與字段名稱 (tweet)搞混了:
{
"valid": false,
"error": "org.elasticsearch.common.ParsingException: unknown query [tweet]; org.elasticsearch.xcontent.NamedObjectNotFoundException: [3:17] unknown field [tweet]"
}
理解查詢語句
對于合法查詢,使用 explain 參數(shù)將返回可讀的描述,這對準(zhǔn)確理解 Elasticsearch 是如何解析你的 query 是非常有用的:
GET /_validate/query?explain
{
"query": {
"match" : {
"tweet" : "really powerful"
}
}
}
我們查詢的每一個 index 都會返回對應(yīng)的 explanation ,因為每一個 index 都有自己的映射和分析器:
{
"valid" : true,
"_shards" : { ... },
"explanations" : [ {
"index" : "us",
"valid" : true,
"explanation" : "tweet:really tweet:powerful"
}, {
"index" : "gb",
"valid" : true,
"explanation" : "tweet:realli tweet:power"
} ]
}
從 explanation 中可以看出,匹配 really powerful 的 match 查詢被重寫為兩個針對 tweet 字段的 single-term 查詢,一個single-term查詢對應(yīng)查詢字符串分出來的一個term。文章來源:http://www.zghlxwxcb.cn/news/detail-847004.html
當(dāng)然,對于索引 us ,這兩個 term 分別是 really 和 powerful ,而對于索引 gb ,term 則分別是 realli 和 power 。之所以出現(xiàn)這個情況,是由于我們將索引 gb 中 tweet 字段的分析器修改為 english 分析器。文章來源地址http://www.zghlxwxcb.cn/news/detail-847004.html
到了這里,關(guān)于使用阿里云試用Elasticsearch學(xué)習(xí):1.5 基礎(chǔ)入門——請求體查詢的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!