Kibana頂部的那個(gè)輸入框你知道怎么用嗎?

用過 Kibana 的同學(xué)應(yīng)該都注意過其頂部的搜索框,像下圖這樣。

image

這個(gè)輸入框接受符合 query string 語法的查詢語句。在日常開發(fā)中我們常用的都是 elastic query dsl(domain specific language),都是 json 格式的,像下面這個(gè)簡單的查詢語句。

{
    "query":{
        "match":{
            "name":"elastic"
        }
    }
}

這個(gè)查詢?nèi)绻?query string 來表示的話,如下所示:

name:elastic

看起來是不是簡潔了很多呢?對(duì)于 kibana 這種 UI 界面,輸入越是簡單,越是接近自然語言,對(duì)于用戶也就越是友好,所以 kibana 的搜索框默認(rèn)選擇了 query string 的搜索語法。雖然 query string 展示起來簡潔了很多,但是要用好卻沒有那么簡單,如果不好好閱讀官方文檔并做實(shí)驗(yàn),那你會(huì)吃不少苦頭。下面我就來幫大家掃清障礙。

注解:

如果非要用 query dsl 的話,kibana 也是支持的,你只需要把 query 中的內(nèi)容放到搜索框中就可以了,比如上面的查詢語句,你只要放下面的內(nèi)容就可以查詢了。

{    
    "match":{    
        "name":"elastic"
    }
}

由來

elasticsearchquery string 其實(shí)就是 lucenequery languageelasticsearch 本身就是構(gòu)建于 lucene 之上的,它支持 lucenequery language 也是很簡單的事情。那這個(gè) query language 是怎么來的呢?根據(jù) lucene 文檔中介紹,雖然 lucene 已經(jīng)提供了構(gòu)建查詢條件的 API,但對(duì)于人類直接使用而言不夠友好和自然,所以 lucene 提供了這樣一種接近自然語言的查詢語言,方便人工輸入和記憶查詢條件。lucene 不鼓勵(lì)在代碼中直接使用 query language,因?yàn)樗€要經(jīng)過一層 query parser 的轉(zhuǎn)換,有性能損耗,另外 query language 也只覆蓋了一部分查詢 API,并不完備。

基本概念

這里先講解兩個(gè)術(shù)語: single termphrase。前者是指單個(gè)詞(分詞后的最小單位),后者指短語。舉例來說,wordsun 這些都是 single term,而用雙引號(hào)包裹起來 “word sun“ 就成了 phrase 。所以這兩者的區(qū)別在于 phrase 是由 term 組成的,包裹在雙引號(hào)中。而 phrase 中的詞在匹配是有順序要求的,這也就是 elasticsearchmatch querymatch phrase query 的區(qū)別之一。

接下來再看一個(gè)術(shù)語:field,也就是字段。我們?cè)谑褂?query dsl 來寫搜索條件時(shí),都會(huì)指明是要在哪一個(gè) field 上做匹配。同理,在 query string 中也可以做到只匹配指定的 field,用法是將 字段名稱: 放到查詢內(nèi)容前面即可,比如 name:tom。當(dāng)不指定 field 時(shí),會(huì)使用默認(rèn)的 field,默認(rèn)配置為 _all字段,這個(gè)是可以自己指定的(index.query.default_field)。關(guān)于 _all 字段,可以簡單理解為所有文檔字段的拼接結(jié)果,這里就不展開講了。比如下面這個(gè)查詢語句就是查詢 nametom 的所有文檔。

name:tom

如果不寫 name: ,只寫 tom,那么相當(dāng)于執(zhí)行 _all:tom 這個(gè)查詢。

另外* field* 是有作用域的,只對(duì)緊跟其后的 term 生效。

name:"Tom Lee"

上面這是一個(gè) phrase 查詢,查詢匹配 Tom Lee 的所有文檔。

name:Tom Lee

上面這個(gè)查詢實(shí)際等效于

name:Tom OR _all:Lee

這也是在實(shí)際使用中很多人容易踩坑的地方,使用的過程中要切記,否則查詢出的結(jié)果肯定不會(huì)如你預(yù)期的那樣。

如果你想對(duì)一個(gè) field 指定復(fù)雜的查詢條件,那么可以使用括號(hào)將查詢條件包起來用(field grouping)。比如下面的這個(gè)語句:

name:(tom lee)

等價(jià)于

name:(tom OR lee)

查詢 nametom 或者 lee的所有文檔。

另外括號(hào)不僅可以作用在 field 上,還可以作用在外層的邏輯處理中。比如下面這種查詢組合也是支持的(大家先忽略還沒有講到的操作符)。

(name:tom && age:10)||city:(shanghai beijing)

有心的讀者可能會(huì)發(fā)現(xiàn)為什么 && 的語句還要加括號(hào)呢,它的優(yōu)先級(jí)不是比 || 高嗎?我 也是這么認(rèn)為的,但動(dòng)手測試后發(fā)現(xiàn)貌似 lucene 沒有實(shí)現(xiàn)這個(gè)優(yōu)先級(jí)的解析,所以大家使用的時(shí)候注意括號(hào)的使用。

下面再講一下布爾操作符,大家對(duì)這個(gè)應(yīng)該很熟悉了,比如 ANDORNOT等。這里要注意的一點(diǎn)是:query string 中的布爾操作符必須大寫。如果小寫,比如 andornotquery解析器會(huì)把他們當(dāng)做普通 term 解析。比如下面這個(gè)語句:

name:tom and age:10

上面的查詢實(shí)際對(duì)應(yīng)下面的語句:

name:tom OR _all:and OR age:10

愛思考的同學(xué)看到上面的解釋應(yīng)該就有疑問了。

“這個(gè) OR 是從哪里來的呢?”

這個(gè) OR 是默認(rèn)的布爾操作符,當(dāng)多個(gè)查詢條件之間沒有指定布爾關(guān)系時(shí),就會(huì)使用 OR

另外可以用 &&||* 分別代替 ANDOR,使得查詢語句更簡潔易懂。

NOT 就是非操作,簡寫符號(hào)為 !。用法如下:

name:(tom NOT lee)

查詢 nametom,但不是 lee 的所有文檔。

除去 ANDORNOTquery string 還支持 +-,分別對(duì)應(yīng) mustmust not 的含義。

name:(tom +lee -alfred)

上面的語句查詢 name 中 含有 lee,不含有 alfred,但可能含有 tom 的所有文檔。

大家可以想一下如果用 ANDORNOT 來重寫上面的語句是什么樣子呢?

name:((lee && !alfred) || (tom && lee && !alfred))

你是不是發(fā)現(xiàn) +- 的好處了?

查詢功能

講完基礎(chǔ)概念,我們?cè)賮砜纯?query string 支持的幾個(gè)查詢功能。

范圍查詢 range search

數(shù)字、日期類型等都是可以指定范圍的,對(duì)于這類可以使用范圍查詢,閉區(qū)間用[],開區(qū)間用{}。舉幾個(gè)例子大家一看就明白了。

age:[1 TO 10] 意為 1<=age<=10
age:[1 TO 10} 意為 1<=age<10
age:[1 TO ] 意為 age>=1
age:[* TO 10] 意為 age<=10

日期也是一樣的用法,只要將數(shù)字替換為 2017-01-01 即可。

如果你覺得這樣寫太麻煩了,那可以使用簡略寫法,如下:

age:(>=1 && <=10) 或者 age:(+>=1 +<=10)
age:(>=1 && <10) 或者 age:(+>=1 +<10)
age:>=1
age:<=10

通配符查詢 wildcard search

大家對(duì)于通配符應(yīng)該都不陌生,有 ? 和 * 兩個(gè),前者代表一個(gè)字符,后者代表0或多個(gè)字符。

name:t?m
name:tom*
name:t*m

上面的使用方式都可以,但是不能把 ? 和 *** 放在最前面,因?yàn)檫@會(huì)導(dǎo)致 elasticsearch 將所有的分詞都比對(duì)一遍,效率低下。

通配符查詢的效率很低,也會(huì)占用較多的內(nèi)存(因?yàn)橐阉蟹蠗l件的分詞進(jìn)行比對(duì)),建議大家謹(jǐn)慎使用。

正則查詢 regular expressionsearch

正則查詢?nèi)缤置嬉饬x所講的,支持正則表達(dá)式進(jìn)行匹配。

name:/[mb]oat/

但這里并不支持所有的正則語法,使用的時(shí)候要注意查看官方文檔說明。另外正則查詢的內(nèi)存壓力也很大,要謹(jǐn)慎使用。

模糊查詢 fuzzy search

所謂模糊查詢是指允許搜索和匹配的詞(term)之間有差異,比如搜索 surprize,可以匹配到surprise

name:roam~

上面的語句會(huì)匹配到 foamroams,波浪號(hào)后面可以指定一個(gè) 0~2 的浮點(diǎn)值,用以表示模糊度,我在實(shí)際使用中用的不多,就不展開來講了。

近似度查詢 proximity search

所謂近似度查詢是指在一個(gè)短語(phrase)中,詞(term)與詞之間距離的匹配。

name:"tom lee"~2

匹配時(shí)允許 tomlee 之間有 2 個(gè)詞的距離,筆者用的也不多,所以不班門弄斧了。

提升查詢權(quán)重 boosting term

查詢時(shí)如果想改變某個(gè)查詢條件的權(quán)重,可以使用 ^ 來實(shí)現(xiàn)。

name:(tom^4 lee)

上面的查詢表示,當(dāng) name 中包含 tom 時(shí),其權(quán)重是 lee 的4倍,這就意味著相應(yīng)得分也會(huì)高,排序也會(huì)靠前。

特殊字符過濾

query string 本身已經(jīng)占據(jù)了一些關(guān)鍵字,如下

+ - && || ! ( ) { } [ ] ^ " ~ * ? : \ /

當(dāng)遇到這些關(guān)鍵詞時(shí),需要使用 \ 做轉(zhuǎn)義,比如如果你要搜索 (1+1):2,那么查詢條件需要寫成\(1\+1\)\:2

總結(jié)

至此,query string就講完了,大家可以去愉快地和 kibana 玩耍了,遇到問題時(shí)歡迎和筆者我討論哦~

參考文檔

  1. https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax

  2. https://www.timroes.de/2016/05/29/elasticsearch-kibana-queries-in-depth-tutorial/

  3. http://lucene.apache.org/core/6_4_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package.description

  4. http://www.lucenetutorial.com/lucene-query-syntax.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容