Elasticsearch 教程--搜索

搜索 – 基本工具

到目前爲止,咱們已經學習了Elasticsearch的分佈式NOSQL文檔存儲,咱們能夠直接把JSON文檔扔到Elasticsearch中,而後直接經過ID來進行調取。可是Elasticsearch真正的強大之處在於將混亂變得有意義——將大數據變成大量的信息。html

這也是咱們使用JSON文檔而不是無規則數據的緣由。Elasticsearch不只僅只是存儲文檔,同時它還索引了這些文檔以便搜索。文檔中每個字段都被索引而且能夠被查詢。不只如此,在一個查詢中,Elasticsearch可使用全部索引,而且以驚人的速度返回結果。這是傳統數據庫永遠也不能企及的。git

這個搜索能夠是:github

  • 相似於年齡性別加入日期等結構化數據,相似於在SQL中進行查詢。
  • 全文搜索,查找整個文檔中匹配關鍵字的內容,並根據相關性
  • 或者結合二者。

雖然不少搜索操做是安裝好Elasticsearch就能夠用的,可是想發揮它的潛力,你須要明白如下內容:shell

名字 說明
映射 (Mapping) 每一個字段中的數據如何被解釋
統計 (Analysis) 可搜索的全文是如何被處理的
查詢 (Query DSL) Elasticsearch使用的靈活強的查詢語言

上述的每個內容都是一個大的主題,咱們將會在以後的《深刻搜索》中詳細探討它們。 本章中咱們將針對先去介紹它們三個的基本概念 —— 已經足夠能幫助你理解搜索是如何運做的了。數據庫

咱們將向你介紹searchAPI的簡單實用方式。數組


測試數據

咱們本章使用的文檔能夠在下面的git中找到:https://gist.github.com/clintongormley/8579281服務器

你能夠下載而後導入到你的shell中以方便你的學習使用。網絡

5.1 空白搜索

空白搜索

搜索API最經常使用的一種形式就是空白搜索,也就是不加任何查詢條件的,只是返回集羣中全部文檔的搜索。app

GET /_search

返回內容以下(有刪減):elasticsearch

{
   "hits" : { "total" : 14, "hits" : [ { "_index": "us", "_type": "tweet", "_id": "7", "_score": 1, "_source": { "date": "2014-09-17", "name": "John Smith", "tweet": "The Query DSL is really powerful and flexible", "user_id": 2 } }, ... 9 個結果被隱藏 ... ], "max_score" : 1 }, "took" : 4, "_shards" : { "failed" : 0, "successful" : 10, "total" : 10 }, "timed_out" : false } 

hits

返回內容中最重要的內容就是hits,它指明瞭匹配查詢的文檔的總數hits數組裏則會包含前十個匹配文檔——也就是搜索結果。

hits數組中的每一條結果都包含了文檔的_index_type以及_id信息,以及_source字段。這也就意味着你能夠直接從搜索結果中獲取到整個文檔的內容。這與其餘搜索引擎只返回給你文檔編號,還須要本身去獲取文檔是大相徑庭的。

每個元素還擁有一個_score字段。這個是相關性評分,這個數值表示當前文檔與查詢的匹配程度。一般來講,搜索結果會先返回最匹配的文檔,也就是說它們會按照_score由高至低進行排列。在這個例子中,咱們並無聲明任何查詢,所以_score就都會返回1

max_score數值會顯示全部匹配文檔中的_score的最大值。

took

took數值告訴咱們執行此次搜索請求所耗費的時間有多少毫秒。

shards

_shards告訴了咱們參與查詢分片的總數,以及有多少successfulfailed。一般狀況下咱們是不會獲得失敗的反饋,可是有的時候它會發生。若是咱們的服務器忽然出現了重大事故,而後咱們丟失了同一個分片中主從兩個版本的數據。在查詢請求中,沒法提供可用的備份。這種狀況下,Elasticsearch就會返回`failed提示,可是它還會繼續返回剩下的內容。

timeout

timed_out數值告訴了咱們查詢是否超時。一般,搜索請求不會超時。若是相比完整的結果你更須要的是快速的響應時間,這是你能夠指定timeout值,例如10"10ms"(10毫秒)或者"1s"(1秒鐘):

GET /_search?timeout=10ms

Elasticsearch會盡量地返回你指定時間內它所查到的內容。


Timeout並非終止者

這裏應該強調一下timeout並不會終止查詢,它只是會在你指定的時間內返回當時已經查詢到的數據,而後關閉鏈接。在後臺,其餘的查詢可能會依舊繼續,儘管查詢結果已經被返回了。

使用超時是由於你要保障你的品質,並非由於你須要終止你的查詢。

5.2 多索引多類型

多索引,多類型

你是否注意到了《空白搜索》一章節的文檔中包含了不少不一樣的類型 —— usertweet,它們也分別來自usgb這兩個不一樣的索引?

當咱們沒有特別指定一個索引或者類型的時候,咱們將會搜索整個集羣中的全部文檔。Elasticsearch會把搜索請求轉發給集羣中的每個主從分片,而後按照結果的相關性獲得前十名,並將它們返回給咱們。

然而,每每咱們只須要在某一個特定的索引的幾個類型中進行搜索。咱們能夠經過在URL中定義它來實現這個功能:

URL 說明
/_search 搜索全部的索引和類型
/gb/_search 搜索索引gb中的全部類型
/gb,us/_search 搜索索引gb以及us中的全部類型
/g*,u*/_search 搜索全部以gu開頭的索引中的全部類型
/gb/user/_search 搜索索引gb中類型user內的全部文檔
/gb,us/user,tweet/_search 搜索索引gb和 索引us中類型user以及類型tweet內的全部文檔
/_all/user,tweet/_search 搜索全部索引中類型爲user以及tweet內的全部文檔

當你在一個索引中搜索的時候,Elasticsearch或將你的搜索請求轉發給相應索引中的全部主從分片,而後收集每個分片的結果。在多個索引中搜索也是相同的流程,只不過是增長了一些參與分片。


重要提示

搜索一個擁有五個主分片的索引與搜索五個都只擁有一個主分片是徹底同樣的。


在後面,你將會了解到如何利用這一點,來根據你的須要靈活打造系統。

5.3 分頁

分頁

在《空白搜索》一節中,搜索結果告訴咱們在集羣中共有14個文檔匹配咱們的(空白)查詢。可是在hits數組中只有10個文檔。咱們怎樣才能看到其餘的呢?

與SQL使用LIMIT來控制單「頁」數量相似,Elasticsearch使用的是from以及size兩個參數:

參數 說明
size 每次返回多少個結果,默認值爲10
from 忽略最初的幾條結果,默認值爲0

假設每頁顯示5條結果,那麼1至3頁的請求就是:

GET /_search?size=5 GET /_search?size=5&from=5 GET /_search?size=5&from=10 

小心不要一次請求過多或者頁碼過大的結果。它們會在返回前排序。一個請求會通過多個分片。每一個分片都會生成本身的排序結果。而後再進行集中整理,以確保最終結果的正確性。


分佈式系統中的大頁碼頁面

爲了說明白爲何頁碼過大的請求會產生問題,咱們就先預想一下咱們在搜索一個擁有5個主分片的索引。當咱們請求第一頁搜索的時候,每一個分片產生本身前十名,而後將它們返回給請求節點,而後這個節點會將50條結果從新排序以產生最終的前十名。

如今想一想一下咱們想得到第1,000頁,也就是第10,001到第10,010條結果,與以前同理,每個分片都會先產生本身的前10,010名,而後請求節點統一處理這50,050條結果,而後再丟棄掉其中的50,040條!

如今你應該明白了,在分佈式系統中,大頁碼請求所消耗的系統資源是呈指數式增加的。這也是爲何網絡搜索引擎不會提供超過1,000條搜索結果的緣由。


TIP

在《重索引》一章中,咱們將詳細探討如何才能高效地獲取大量數據。

5.4 查詢語句

精簡 搜索

搜索的API分爲兩種:其一是經過參數來傳遞查詢的「精簡版」查詢語句(query string),還有一種是經過JSON來傳達豐富的查詢的完整版請求體(request body),這種搜索語言被稱爲查詢DSL。

查詢語句在行命令中運行點對點查詢的時候很是實用。好比我想要查詢全部tweet類型中,全部tweet字段爲"elasticsearch"的文檔:

GET /_all/tweet/_search?q=tweet:elasticsearch

下一個查詢是想要尋找name字段爲"john"tweet字段爲"mary"的文檔,實際的查詢就是:

+name:john +tweet:mary

可是通過百分號編碼(percent encoding)處理後,會讓它看起來稍顯神祕:

GET /_search?q=%2Bname%3Ajohn+%2Btweet%3Amary 

前綴"+"表示必需要知足咱們的查詢匹配條件,而前綴"-"則表示絕對不能匹配條件。沒有+或者-的表示可選條件。匹配的越多,文檔的相關性就越大。

字段_all

下面這條簡單的搜索將會返回全部包含"mary"字符的文檔:

GET /_search?q=mary

在以前的例子中,咱們搜索tweet或者name中的文字。然而,搜索的結果顯示"mary"在三個不一樣的字段中:

    • 用戶的名字爲"Mary"
    • 6個"Mary"發送的推文
    • 1個"@mary"

那麼Elasticsearch是如何找到三個不一樣字段中的內容呢?

當咱們在索引一個文檔的時候,Elasticsearch會將全部字段的數值都彙總到一個大的字符串中,並將它索引成一個特殊的字段_all

{
    "tweet": "However did I manage before Elasticsearch?", "date": "2014-09-14", "name": "Mary Jones", "user_id": 1 } 

就好像咱們已經添加了一個叫作_all的字段:

"However did I manage before Elasticsearch? 2014-09-14 Mary Jones 1" 

除非指定了字段名,否則查詢語句就會搜索字段_all

TIP: 在你剛開始建立程序的時候你可能會常用_all這個字段。可是慢慢的,你可能就會在請求中指定字段。當字段_all已經沒有使用價值的時候,那就能夠將它關掉。以後的《字段all》一節中將會有介紹

更加複雜的查詢

再實現一個查詢:

    • 字段name包含"mary""john"
    • date大於2014-09-10
    • _all字段中包含"aggregations""geo"
+name:(mary john) +date:>2014-09-10 +(aggregations geo) 

最終處理完的語句可讀性可能不好:

?q=%2Bname%3A(mary+john)+%2Bdate%3A%3E2014-09-10+%2B(aggregations+geo)

正如你所看到的,這個簡明查詢語句是出奇的強大。在查詢語句語法中,有關於它詳細的介紹。藉助它咱們就能夠在開發的時候提升不少效率。

不過,你也會發現簡潔帶來的易讀性差和難以調試,以及它的脆弱:當其中出現-:/ 或者 "時,它就會返回錯誤提示。

最後要提一句,任何用戶均可以經過查詢語句來訪問臃腫的查詢,或許會獲得一些私人的信息,或許會經過大量的運算將你的集羣壓垮!


TIP

出於以上緣由,咱們不建議你將查詢語句直接暴露給用戶,除非是你信任的能夠訪問數據與集羣的權限用戶。


與此同時,在生產環境中,咱們常常會使用到查詢語句。在瞭解更多關於搜索的知識前,咱們先來看一下它是怎樣運做的。

相關文章
相關標籤/搜索