ElasticSearch是一個高度可擴展的開源搜索引擎並使用REST API,因此您值得擁有。 在本教程中,將介紹開始使用ElasticSearch的一些主要概念。html
ElasticSearch能夠從elasticsearch.org下載對應的文件格式,如ZIP
和TAR.GZ
。下載並提取一個運行它的軟件包以後不會容易得多,須要提早安裝Java運行時環境。java
在本文章中,所使用的環境是Windows,因此這裏只介紹在Windows上運行ElasticSearch,可從命令窗口運行位於bin
文件夾中的elasticsearch.bat
。這將會啓動ElasticSearch在控制檯的前臺運行,這意味着咱們可在控制檯中看到運行信息或一些錯誤信息,並可使用CTRL + C中止或關閉它。node
當前版本是: elasticsearch-5.2.0 下載連接: http://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.0.zipweb
把下載好的文件 elasticsearch-5.2.0.zip
解壓到 D:\software\elasticsearch-5.2.0
,其目錄結構以下所示 - chrome
啓動 ElasticSearch -shell
Microsoft Windows [版本 10.0.10586] (c) 2015 Microsoft Corporation。保留全部權利。 C:\Users\Administrator>d: D:\>cd software\elasticsearch-5.2.0 D:\software\elasticsearch-5.2.0>cd bin D:\software\elasticsearch-5.2.0\bin>elasticsearch.bat [2017-01-28T14:10:32,177][INFO ][o.e.n.Node ] [] initializing ... [2017-01-28T14:10:32,670][INFO ][o.e.e.NodeEnvironment ] [SnafGWM] using [1] data paths, mounts [[Software (D:)]], net usable_space [61.6gb], net total_space [139gb], spins? [unknown], types [NTFS] [2017-01-28T14:10:32,686][INFO ][o.e.e.NodeEnvironment ] [SnafGWM] heap size [1.9gb], compressed ordinary object pointers [true] [2017-01-28T14:10:32,686][INFO ][o.e.n.Node ] node name [SnafGWM] derived from node ID [SnafGWMWRzmfwTKP6VJClA]; set [node.name] to override [2017-01-28T14:10:32,717][INFO ][o.e.n.Node ] version[5.2.0], pid[9724], build[24e05b9/2017-01-24T19:52:35.800Z], OS[Windows 10/10.0/amd64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_65/25.65-b01] [2017-01-28T14:10:35,271][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [aggs-matrix-stats] [2017-01-28T14:10:35,271][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [ingest-common] [2017-01-28T14:10:35,271][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [lang-expression] [2017-01-28T14:10:35,271][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [lang-groovy] [2017-01-28T14:10:35,271][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [lang-mustache] [2017-01-28T14:10:35,287][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [lang-painless] [2017-01-28T14:10:35,287][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [percolator] [2017-01-28T14:10:35,288][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [reindex] [2017-01-28T14:10:35,290][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [transport-netty3] [2017-01-28T14:10:35,291][INFO ][o.e.p.PluginsService ] [SnafGWM] loaded module [transport-netty4] [2017-01-28T14:10:35,292][INFO ][o.e.p.PluginsService ] [SnafGWM] no plugins loaded [2017-01-28T14:10:41,394][INFO ][o.e.n.Node ] initialized [2017-01-28T14:10:41,397][INFO ][o.e.n.Node ] [SnafGWM] starting ... [2017-01-28T14:10:42,657][INFO ][o.e.t.TransportService ] [SnafGWM] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}, {[::1]:9300} [2017-01-28T14:10:46,439][INFO ][o.e.c.s.ClusterService ] [SnafGWM] new_master {SnafGWM}{SnafGWMWRzmfwTKP6VJClA}{vG5mFSENST6eo-yl_O8HuA}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined) [2017-01-28T14:10:48,628][INFO ][o.e.h.HttpServer ] [SnafGWM] publish_address {127.0.0.1:9200}, bound_addresses {127.0.0.1:9200}, {[::1]:9200} [2017-01-28T14:10:48,628][INFO ][o.e.n.Node ] [SnafGWM] started [2017-01-28T14:10:48,928][INFO ][o.e.g.GatewayService ] [SnafGWM] recovered [0] indices into cluster_state
在啓動過程當中,ElasticSearch的實例運行會佔用大量的內存,因此在這一過程當中,電腦會變得比較慢,須要耐心等待,啓動加載完成後電腦就能夠正常使用了。數據庫
若是您沒有安裝Java運行時或沒有正確配置,應該不會看到像上面的輸出,而是一個消息說「JAVA_HOME環境變量必須設置!" 要解決這個問題,首先下載並安裝Java,其次,確保已正確配置
JAVA_HOME
環境變量(或參考 - Java JDK安裝和配置)。express
當ElasticSearch的實例並運行,您可使用localhost:9200
,基於JSON的REST API與ElasticSearch進行通訊。使用任何HTTP客戶端來通訊。在ElasticSearch本身的文檔中,全部示例都使用curl。 可是,當使用API時也可以使用圖形客戶端(如Fiddler或RESTClient),這樣操做起更方便直觀一些。json
更方便的是Chrome插件Sense。 Sense提供了一個專門用於使用ElasticSearch的REST API的簡單用戶界面。 它還具備許多方便的功能,例如:ElasticSearch的查詢語法的自動完成功能以及curl格式的複製和粘貼請求,從而能夠方便地在文檔中運行示例。數組
咱們將在本教程中使用sense來執行curl請求,建議安裝Sense並使用它學習後續文章內容。
安裝完成後,在Chrome的右上角找到Sense的圖標。 第一次單擊它運行Sense時,會爲您準備一個很是簡單的示例請求。以下圖所示 -
上述請求將執行最簡單的搜索查詢,匹配服務器上全部索引中的全部文檔。針對ElasticSearch運行,Sense提供的最簡單的查詢,在響應結果的數據中並無查詢到任何數據,由於沒有任何索引。以下所示 -
{ "took": 1, "timed_out": false, "_shards": { "total": 0, "successful": 0, "failed": 0 }, "hits": { "total": 0, "max_score": 0, "hits": [] } }
下一步咱們來學習添加一些數據和索引,來修復這個問題。
想要使用ElasticSearch,用於搜索第一步就是使用一些數據填充來索引,CRUD表「建立」或者「索引」。咱們還將學習如何更新,讀取和刪除文檔。
在ElasticSearch索引中,對應於CRUD中的「建立」和「更新」 - 若是對具備給定類型的文檔進行索引,而且要插入原先不存在的ID。 若是具備相同類型和ID的文檔已存在,則會被覆蓋。
要索引第一個JSON對象,咱們對REST API建立一個PUT請求到一個由索引名稱,類型名稱和ID組成的URL。 也就是:http://localhost:9200/<index>/<type>/[<id>]
。
索引和類型是必需的,而id
部分是可選的。若是不指定ID
,ElasticSearch會爲咱們生成一個ID
。 可是,若是不指定id,應該使用HTTP的POST
而不是PUT
請求。
索引名稱是任意的。若是服務器上沒有此名稱的索引,則將使用默認配置來建立一個索引。
至於類型名稱,它也是任意的。 它有幾個用途,包括:
如今咱們來索引一些內容! 能夠把任何東西放到索引中,只要它能夠表示爲單個JSON對象。 在本教程中,使用索引和搜索電影的一個示例。這是一個經典的電影對象信息:
{ "title": "The Godfather", "director": "Francis Ford Coppola", "year": 1972 }
要建立一個索引,這裏使用索引的名稱爲「movies」,類型名稱(「movie」)和id(「1」),並按照上述模式使用JSON對象在正文中進行請求。
curl -XPUT "http://localhost:9200/movies/movie/1" -d' { "title": "The Godfather", "director": "Francis Ford Coppola", "year": 1972 }'
可使用curl來執行它,也可使用Sense。這裏使用Sense,能夠本身填充URL,方法和請求正文,或者您以複製上述curl示例,將光標置於Sense中的正文字段中寫入上面的Json對象,而後按點擊綠色小箭頭來執行建立索引操做。以下圖所示 -
執行請求後,能夠看到接收到來自ElasticSearch響應的JSON對象。以下所示 -
{ "_index": "movies", "_type": "movie", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true }
響應對象包含有關索引操做的信息,例如它是否成功(「ok」)和文檔ID,若是不指定則ElasticSearch會本身生成一個。
若是運行Sense提供的默認搜索請求(可使用Sense中的「歷史記錄」按鈕訪問,由於確實已執行它)過了,就會看到返回有數據的結果。
{ "took": 146, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 1, "hits": [ { "_index": "movies", "_type": "movie", "_id": "1", "_score": 1, "_source": { "title": "The Godfather", "director": "Francis Ford Coppola", "year": 1972 } } ] } }
在上面返回結果中,看到的是搜索結果而不是錯誤或是空的結果。
如今,在索引中有了一部電影信息,接下來來了解如何更新它,添加一個類型列表。要作到這一點,只需使用相同的ID索引它。使用與以前徹底相同的索引請求,但類型擴展了JSON對象。
curl -XPUT "http://localhost:9200/movies/movie/1" -d' { "title": "The Godfather", "director": "Francis Ford Coppola", "year": 1972, "genres": ["Crime", "Drama"] }'
ElasticSearch的響應結果與前面的大致上同樣,但有一點區別,結果對象中的_version
屬性的值爲2
,而不是1
。響應結果以下 -
{ "_index": "movies", "_type": "movie", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false }
版本號(_version
)可用於跟蹤文檔已編入索引的次數。它的主要目的是容許樂觀的併發控制,由於能夠在索引請求中提供一個版本,若是提供的版本高於索引中的版本,ElasticSearch將只覆蓋文檔內容,ID值不變,版本號自動添加。
上面已經學習了索引新文檔以及更新存在的文檔。還看到了一個簡單搜索請求的示例。若是隻是想檢索一個具備已知ID的索引,一個方法是搜索索引中的文檔。另外一個簡單而快速的方法是經過ID
,使用GET
來檢索它。
簡單的作法是向同一個URL發出一個GET請求,URL的ID部分是強制性的。經過ID從ElasticSearch中檢索文檔可發出URL的GET請求:http://localhost:9200/<index>/<type>/<id>
。
使用如下請求嘗試獲取電影信息:
curl -XGET "http://localhost:9200/movies/movie/1" -d''
執行結果以下所示 -
正以下圖所看到的,結果對象包含與索引時所看到的相似的元數據,如索引,類型和版本信息。 最後最重要的是,它有一個名稱爲「_source
」的屬性,它包含實際獲取的文檔信息。
關於GET沒有什麼可說的,由於它很簡單,繼續最後刪除操做。
爲了經過ID從索引中刪除單個指定的文檔,使用與獲取索引文檔相同的URL,只是這裏將HTTP方法更改成DELETE
。
curl -XDELETE "http://localhost:9200/movies/movie/1" -d''
響應對象包含元數據方面的一些常見數據字段,以及名爲「_found
」的屬性,表示文檔確實已找到而且操做成功。
在執行
DELETE
調用後切換回GET
,能夠驗證文檔是否確實已刪除。
在前面,已經介紹了在ElasticSearch索引中處理數據的基礎知識,如今是時候進行核心功能的學習了。考慮到以前咱們刪除索引中的全部文檔,因此,在進行搜索學習以前,須要一些添加一些示例數據。使用如下這些請求和數據對象來建立索引。
curl -XPUT "http://localhost:9200/movies/movie/1" -d' { "title": "The Godfather", "director": "Francis Ford Coppola", "year": 1972, "genres": ["Crime", "Drama"] }' curl -XPUT "http://localhost:9200/movies/movie/2" -d' { "title": "Lawrence of Arabia", "director": "David Lean", "year": 1962, "genres": ["Adventure", "Biography", "Drama"] }' curl -XPUT "http://localhost:9200/movies/movie/3" -d' { "title": "To Kill a Mockingbird", "director": "Robert Mulligan", "year": 1962, "genres": ["Crime", "Drama", "Mystery"] }' curl -XPUT "http://localhost:9200/movies/movie/4" -d' { "title": "Apocalypse Now", "director": "Francis Ford Coppola", "year": 1979, "genres": ["Drama", "War"] }' curl -XPUT "http://localhost:9200/movies/movie/5" -d' { "title": "Kill Bill: Vol. 1", "director": "Quentin Tarantino", "year": 2003, "genres": ["Action", "Crime", "Thriller"] }' curl -XPUT "http://localhost:9200/movies/movie/6" -d' { "title": "The Assassination of Jesse James by the Coward Robert Ford", "director": "Andrew Dominik", "year": 2007, "genres": ["Biography", "Crime", "Drama"] }'
值得指出的是,ElasticSearch具備和端點(_bulk
)用於用單個請求索引多個文檔,可是這超出了本教程的範圍,這裏只保持簡單,使用六個單獨的請求學習。
如今已經把一些電影信息放入了索引,能夠經過搜索看看是否可找到它們。 爲了使用ElasticSearch進行搜索,咱們使用_search
端點,可選擇使用索引和類型。也就是說,按照如下模式向URL發出請求:<index>/<type>/_search
。其中,index
和type
都是可選的。
換句話說,爲了搜索電影,能夠對如下任一URL進行POST請求:
由於咱們只有一個單一的索引和單一的類型,因此怎麼使用都不會有什麼問題。爲了簡潔起見使用第一個URL。
若是隻是發送一個請求到上面的URL,咱們會獲得全部的電影信息。爲了建立更有用的搜索請求,還須要向請求正文中提供查詢。 請求正文是一個JSON對象,除了其它屬性之外,它還要包含一個名稱爲「query
」的屬性,這就可以使用ElasticSearch的查詢DSL。
{ "query": { //Query DSL here } }
你可能想知道查詢DSL是什麼。它是ElasticSearch本身基於JSON的域特定語言,能夠在其中表達查詢和過濾器。想象ElasticSearch它像關係數據庫的SQL。這裏是ElasticSearch本身的文檔解釋它的一部分(英文好本身擼吧):
Think of the Query DSL as an AST of queries. Certain queries can contain other queries (like the bool query), other can contain filters (like the constant_score), and some can contain both a query and a filter (like the filtered). Each of those can contain any query of the list of queries or any filter from the list of filters, resulting in the ability to build quite complex (and interesting) queries. see more: http://www.elasticsearch.org/guide/reference/query-dsl/
查詢DSL具備一長列不一樣類型的查詢可使用。 對於「普通」自由文本搜索,最有可能想使用一個名稱爲「查詢字符串查詢」。
查詢字符串查詢是一個高級查詢,有不少不一樣的選項,ElasticSearch將解析和轉換爲更簡單的查詢樹。若是忽略了全部的可選參數,而且只須要給它一個字符串用於搜索,它能夠很容易使用。
如今嘗試在兩部電影的標題中搜索有「kill」這個詞的電影信息:
curl -XPOST "http://localhost:9200/_search" -d' { "query": { "query_string": { "query": "kill" } } }'
執行上面的請求並查看結果,以下所示 -
正如預期的,獲得兩個命中結果,每一個電影的標題中都帶有「kill」單詞。再看看另外一種狀況,在特定字段中搜索。
在前面的例子中,使用了一個很是簡單的查詢,一個只有一個屬性「query
」的查詢字符串查詢。 如前所述,查詢字符串查詢有一些能夠指定設置,若是不使用,它將會使用默認的設置值。
這樣的設置稱爲「fields」,可用於指定要搜索的字段列表。若是不使用「fields」字段,ElasticSearch查詢將默認自動生成的名爲「_all
」的特殊字段,來基於全部文檔中的各個字段匹配搜索。
爲了作到這一點,修改之前的搜索請求正文,以便查詢字符串查詢有一個fields
屬性用來要搜索的字段數組:
curl -XPOST "http://localhost:9200/_search" -d' { "query": { "query_string": { "query": "ford", "fields": ["title"] } } }'
執行上面查詢它,看看會有什麼結果(應該只匹配到 1
行數據):
正如預期的獲得一個命中,電影的標題中的單詞「ford
」。如今,從查詢中移除fields
屬性,應該能匹配到 3
行數據:
前面已經介紹了幾個簡單的自由文本搜索查詢。如今來看看另外一個示例,搜索「drama
」,不明確指定字段,以下查詢 -
curl -XPOST "http://localhost:9200/_search" -d' { "query": { "query_string": { "query": "drama" } } }'
由於在索引中有五部電影在_all
字段(從類別字段)中包含單詞「drama
」,因此獲得了上述查詢的5
個命中。 如今,想象一下,若是咱們想限制這些命中爲只是1962
年發佈的電影。要作到這點,須要應用一個過濾器,要求「year
」字段等於1962
。
要添加過濾器,修改搜索請求正文,以便當前的頂級查詢(查詢字符串查詢)包含在過濾的查詢中:
{ "query": { "filtered": { "query": { "query_string": { "query": "drama" } }, "filter": { //Filter to apply to the query } } } }
過濾的查詢是具備兩個屬性(query
和filter
)的查詢。執行時,它使用過濾器過濾查詢的結果。要完成這樣的查詢還須要添加一個過濾器,要求year
字段的值爲1962
。
ElasticSearch查詢DSL有各類各樣的過濾器可供選擇。對於這個簡單的狀況,某個字段應該匹配一個特定的值,一個條件過濾器就能很好地完成工做。
"filter": { "term": { "year": 1962 } }
完整的搜索請求以下所示:
curl -XPOST "http://localhost:9200/_search" -d' { "query": { "filtered": { "query": { "query_string": { "query": "drama" } }, "filter": { "term": { "year": 1962 } } } } }'
當執行上面請求,只獲得兩個命中,這個兩個命中的數據的 year
字段的值都是等於 1962
。
在上面的示例中,使用過濾器限制查詢字符串查詢的結果。若是想要作的是應用一個過濾器呢? 也就是說,咱們但願全部電影符合必定的標準。
在這種狀況下,咱們仍然在搜索請求正文中使用「query
」屬性。可是,咱們不能只是添加一個過濾器,須要將它包裝在某種查詢中。
一個解決方案是修改當前的搜索請求,替換查詢字符串 query
過濾查詢中的match_all
查詢,這是一個查詢,只是匹配一切。相似下面這個:
curl -XPOST "http://localhost:9200/_search" -d' { "query": { "filtered": { "query": { "match_all": { } }, "filter": { "term": { "year": 1962 } } } } }'
另外一個更簡單的方法是使用常數分數查詢:
curl -XPOST "http://localhost:9200/_search" -d' { "query": { "constant_score": { "filter": { "term": { "year": 1962 } } } } }'