Elasticsearch入門(二)

基礎概念

Elasticsearch有幾個核心概念,從一開始理解這些概念會對整個學習過程有莫大的幫助。css

接近實時(NRT)

Elasticsearch是一個接近實時的搜索平臺。這意味着,從索引一個文檔直到這個文檔可以被搜索到有一個輕微的延遲(一般是1秒)。node

集羣(cluster)

一個集羣就是由一個或多個節點組織在一塊兒,它們共同持有你整個的數據,並一塊兒提供索引和搜索功能。一個集羣由一個惟一的名字標識,這個名字默認就是 「elasticsearch」。這個名字是重要的,由於一個節點只能經過指定某個集羣的名字,來加入這個集羣。在產品環境中顯式地設定這個名字是一個好 習慣,可是使用默認值來進行測試/開發也是不錯的。git

節點(node)

一個節點是你集羣中的一個服務器,做爲集羣的一部分,它存儲你的數據,參與集羣的索引和搜索功能。和集羣相似,一個節點也是由一個名字來標識的,默認狀況 下,這個名字是一個隨機的漫威漫畫角色的名字,這個名字會在啓動的時候賦予節點。這個名字對於管理工做來講挺重要的,由於在這個管理過程當中,你會去肯定網 絡中的哪些服務器對應於Elasticsearch集羣中的哪些節點。github

一個節點能夠經過配置集羣名稱的方式來加入一個指定的集羣。默認狀況下,每一個節點都會被安排加入到一個叫作「elasticsearch」的集羣中,這意 味着,若是你在你的網絡中啓動了若干個節點,並假定它們可以相互發現彼此,它們將會自動地造成並加入到一個叫作「elasticsearch」的集羣中。shell

在一個集羣裏,只要你想,能夠擁有任意多個節點。並且,若是當前你的網絡中沒有運行任何Elasticsearch節點,這時啓動一個節點,會默認建立並加入一個叫作「elasticsearch」的集羣。數據庫

索引(index)相似於SQL中的數據庫

一個索引就是一個擁有幾分類似特徵的文檔的集合。好比說,你能夠有一個客戶數據的索引,另外一個產品目錄的索引,還有一個訂單數據的索引。一個索引由一個名 字來標識(必須所有是小寫字母的),而且當咱們要對對應於這個索引中的文檔進行索引、搜索、更新和刪除的時候,都要使用到這個名字。json

在一個集羣中,若是你想,能夠定義任意多的索引。bash

類型(type)相似於SQL中的表

在一個索引中,你能夠定義一種或多種類型。一個類型是你的索引的一個邏輯上的分類/分區,其語義徹底由你來定。一般,會爲具備一組共同字段的文檔定義一個 類型。好比說,咱們假設你運營一個博客平臺而且將你全部的數據存儲到一個索引中。在這個索引中,你能夠爲用戶數據定義一個類型,爲博客數據定義另外一個類 型,固然,也能夠爲評論數據定義另外一個類型。服務器

文檔(document)相似於SQL中的數據行字段

一個文檔是一個可被索引的基礎信息單元。好比,你能夠擁有某一個客戶的文檔,某一個產品的一個文檔,固然,也能夠擁有某個訂單的一個文檔。文檔以 JSON(Javascript Object Notation)格式來表示,而JSON是一個處處存在的互聯網數據交互格式。網絡

在一個index/type裏面,只要你想,你能夠存儲任意多的文檔。注意,儘管一個文檔,物理上存在於一個索引之中,文檔必須被索引/賦予一個索引的type。

分片和複製(shards & replicas)

一個索引能夠存儲超出單個結點硬件限制的大量數據。好比,一個具備10億文檔的索引佔據1TB的磁盤空間,而任一節點都沒有這樣大的磁盤空間;或者單個節點處理搜索請求,響應太慢。

爲了解決這個問題,Elasticsearch提供了將索引劃分紅多份的能力,這些份就叫作分片。當你建立一個索引的時候,你能夠指定你想要的分片的數量。每一個分片自己也是一個功能完善而且獨立的「索引」,這個「索引」能夠被放置到集羣中的任何節點上。

分片之因此重要,主要有兩方面的緣由:

  • 容許你水平分割/擴展你的內容容量
  • 容許你在分片(潛在地,位於多個節點上)之上進行分佈式的、並行的操做,進而提升性能/吞吐量

至於一個分片怎樣分佈,它的文檔怎樣聚合回搜索請求,是徹底由Elasticsearch管理的,對於做爲用戶的你來講,這些都是透明的。

在一個網絡/雲的環境裏,失敗隨時均可能發生,在某個分片/節點不知怎麼的就處於離線狀態,或者因爲任何緣由消失了,這種狀況下,有一個故障轉移機制是非 常有用而且是強烈推薦的。爲此目的,Elasticsearch容許你建立分片的一份或多份拷貝,這些拷貝叫作複製分片,或者直接叫複製。

複製之因此重要,有兩個主要緣由:

  • 在分片/節點失敗的狀況下,提供了高可用性。由於這個緣由,注意到複製分片從不與原/主要(original/primary)分片置於同一節點上是很是重要的。
  • 擴展你的搜索量/吞吐量,由於搜索能夠在全部的複製上並行運行

總之,每一個索引能夠被分紅多個分片。一個索引也能夠被複制0次(意思是沒有複製)或屢次。一旦複製了,每一個索引就有了主分片(做爲複製源的原來的分片)和 複製分片(主分片的拷貝)之別。分片和複製的數量能夠在索引建立的時候指定。在索引建立以後,你能夠在任什麼時候候動態地改變複製的數量,可是你過後不能改變 分片的數量。

默認狀況下,Elasticsearch中的每一個索引被分片5個主分片和1個複製,這意味着,若是你的集羣中至少有兩個節點,你的索引將會有5個主分片和另外5個複製分片(1個徹底拷貝),這樣的話每一個索引總共就有10個分片。

這些問題搞清楚以後,咱們就要進入好玩的部分了~

啓動

上一篇咱們已經安裝好程序,準備好了開啓咱們的節點和單節點集羣(Windows用戶應該運行elasticsearch.bat文件):

./elasticsearch

若是一切順利,你將看到大量的以下信息:

[INFO ][o.e.n.Node               ] [] initializing ...
...
[INFO ][o.e.n.Node               ] initialized
...
[INFO ][o.e.h.n.Netty4HttpServerTransport] [iJxoy-Y] publish_address {127.0.0.1:9200}, bound_addresses {[fe80::1]:9200}, {[::1]:9200}, {127.0.0.1:9200} [INFO ][o.e.n.Node ] [iJxoy-Y] started [INFO ][o.e.g.GatewayService ] [iJxoy-Y] recovered [0] indices into cluster_state 

不去涉及太多細節,咱們能夠看到,一叫作「iJxoy-Y」(你會見到一個不一樣的漫威漫畫角色)的節點啓動而且將本身選作單結點集羣的master。如今不用關心master是什麼東西。這裏重要的就是,咱們在一個集羣中開啓了一個節點。

正如先前提到的,咱們能夠覆蓋集羣或者節點的名字。咱們能夠在啓動Elasticsearch的時候經過命令行來指定,以下:

./elasticsearch --cluster.name my_cluster_name --node.name my_node_name

也要注意一下有Netty4HttpServerTransport標記的那一行,它提供了有關HTTP地址(127.0.0.1)和端口(9200)的信息,經過這個地址和端口咱們就能夠 訪問咱們的節點了。默認狀況下,Elasticsearch使用9200來提供對其REST API的訪問。若是有必要,這個端口是能夠配置的。

探索你的集羣

REST接口

如今咱們已經有一個正常運行的節點(和集羣)了,下一步就是要去理解怎樣與其通訊了。幸運的是,Elasticsearch提供了很是全面和強大的 REST API,利用這個REST API你能夠同你的集羣交互。下面是利用這個API,能夠作的幾件事情:

  • 檢查你的集羣、節點和索引的健康狀態、和各類統計信息
  • 管理你的集羣、節點、索引數據和元數據
  • 對你的索引進行CRUD(建立、讀取、更新和刪除)和搜索操做
  • 執行高級的查詢操做,像是分頁、排序、過濾、腳本編寫(scripting)、小平面刻畫(faceting)、聚合(aggregations)和許多其它操做

集羣健康

讓咱們以基本的健康檢查做爲開始,咱們能夠利用它來查看咱們集羣的狀態。此過程當中,咱們使用curl,固然,你也可使用任何能夠建立HTTP/REST 調用的工具。咱們假設咱們還在咱們啓動Elasticsearch的節點上並打開另一個shell窗口。

要檢查集羣健康,咱們將使用_cat API。須要事先記住的是,咱們的節點HTTP的端口是9200:

curl 'localhost:9200/_cat/health?v'

相應的響應是:

epoch timestamp cluster status node.total node.data shards pri relo init unassign 1394735289 14:28:09 elasticsearch green 1 1 0 0 0 0 0 

能夠看到,咱們集羣的名字是「elasticsearch」,正常運行,而且狀態是綠色。
當咱們詢問集羣狀態的時候,咱們要麼獲得綠色、黃色或紅色。綠色表明一切正常(集羣功能齊全),黃色意味着全部的數據都是可用的,可是某些複製沒有被分配 (集羣功能齊全),紅色則表明由於某些緣由,某些數據不可用。注意,即便是集羣狀態是紅色的,集羣仍然是部分可用的(它仍然會利用可用的分片來響應搜索請 求),可是可能你須要儘快修復它,由於你有丟失的數據。

也是從上面的響應中,咱們能夠看到,一共有一個節點,因爲裏面沒有數據,咱們有0個分片。注意,因爲咱們使用默認的集羣名字 (elasticsearch),而且因爲Elasticsearch默認使用網絡多播(multicast)發現其它節點,若是你在你的網絡中啓動了多 個節點,你就已經把她們加入到一個集羣中了。在這種情形下,你可能在上面的響應中看到多個節點。

咱們也能夠得到節集羣中的節點列表:

curl 'localhost:9200/_cat/nodes?v'

對應的響應是:

curl 'localhost:9200/_cat/nodes?v' ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name 127.0.0.1 17 100 24 2.62 mdi * iJxoy-Y 

這兒,咱們能夠看到咱們叫作「 iJxoy-Y」的節點,這個節點是咱們集羣中的惟一節點。

列出全部的索引

讓咱們看一下咱們的索引:

curl 'localhost:9200/_cat/indices?v'

響應是:

curl 'localhost:9200/_cat/indices?v' health index pri rep docs.count docs.deleted store.size pri.store.size 

這個結果意味着,在咱們的集羣中,咱們沒有任何索引。

建立一個索引

如今讓咱們建立一個叫作「customer」的索引,而後再列出全部的索引:

curl -XPUT 'localhost:9200/customer?pretty'
curl 'localhost:9200/_cat/indices?v'

第一個命令使用PUT建立了一個叫作「customer」的索引。咱們簡單地將pretty附加到調用的尾部,使其以美觀的形式打印出JSON響應(若是有的話)。
響應以下:

curl -XPUT 'localhost:9200/customer?pretty' { "acknowledged" : true } curl 'localhost:9200/_cat/indices?v' health index pri rep docs.count docs.deleted store.size pri.store.size yellow customer 5 1 0 0 495b 495b 

第二個命令的結果告知咱們,咱們如今有一個叫作customer的索引,而且它有5個主分片和1份複製(都是默認值),其中包含0個文檔。

你可能也注意到了這個customer索引有一個黃色健康標籤。回顧咱們以前的討論,黃色意味着某些複製沒有(或者還未)被分配。這個索引之因此這樣,是 由於Elasticsearch默認爲這個索引建立一份複製。因爲如今咱們只有一個節點在運行,那一份複製就分配不了了(爲了高可用),直到當另一個節 點加入到這個集羣后,才能分配。一旦那份複製在第二個節點上被複制,這個節點的健康狀態就會變成綠色。

索引並查詢一個文檔

如今讓咱們放一些東西到customer索引中。首先要知道的是,爲了索引一個文檔,咱們必須告訴Elasticsearch這個文檔要到這個索引的哪一個類型(type)下。

讓咱們將一個簡單的客戶文檔索引到customer索引、「external」類型中,這個文檔的ID是1,操做以下:

curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '
{
"name": "John Doe"
}'

響應以下:

{
  "_index" : "customer", "_type" : "external", "_id" : "1", "_version" : 1, "created" : true } 

從上面的響應中,咱們能夠看到,一個新的客戶文檔在customer索引和external類型中被成功建立。文檔也有一個內部id 1, 這個id是咱們在索引的時候指定的。

有一個關鍵點須要注意,Elasticsearch在你想將文檔索引到某個索引的時候,並不強制要求這個索引被顯式地建立。在前面這個例子中,若是customer索引不存在,Elasticsearch將會自動地建立這個索引。

如今,讓咱們把剛剛索引的文檔取出來:

curl -XGET 'localhost:9200/customer/external/1?pretty'

響應以下:

{
  "_index" : "customer", "_type" : "external", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "name": "John Doe" } } 

除了一個叫作found的字段來指明咱們找到了一個ID爲1的文檔,和另一個字段——_source——返回咱們前一步中索引的完整JSON文檔以外,其它的都沒有什麼特別之處。

刪除一個文檔

如今讓咱們刪除咱們剛剛建立的索引,並再次列出全部的索引:

curl -XDELETE 'localhost:9200/customer?pretty'
curl 'localhost:9200/_cat/indices?v'

響應以下:

{
  "acknowledged" : true } 

curl 'localhost:9200/_cat/indices?v'
health index pri rep docs.count docs.deleted store.size pri.store.size

這代表咱們成功地刪除了這個索引,如今咱們回到了集羣中空無全部的狀態。

在更進一步以前,咱們再細看一下一些咱們學過的API命令:

curl -XPUT 'localhost:9200/customer'
curl -XPUT 'localhost:9200/customer/external/1' -d '
{
"name": "John Doe"
}'
curl 'localhost:9200/customer/external/1'
curl -XDELETE 'localhost:9200/customer'

若是咱們仔細研究以上的命令,咱們能夠發現訪問Elasticsearch中數據的一個模式。這個模式能夠被總結爲:

curl - ://

這個REST訪問模式廣泛適用於全部的API命令,若是你能記住它,你就會爲掌握Elasticsearch開一個好頭。

修改你的數據

Elasticsearch提供了近乎實時的數據操做和搜索功能。默認狀況下,從你索引/更新/刪除你的數據動做開始到它出如今你的搜索結果中,大概會有1秒鐘的延遲。這和其它相似SQL的平臺不一樣,數據在一個事務完成以後就會當即可用。

索引/替換文檔

咱們先前看到,怎樣索引一個文檔。如今咱們再次調用那個命令:

curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '
{
"name": "John Doe"
}'

再次,以上的命令將會把這個文檔索引到customer索引、external類型中,其ID是1。若是咱們對一個不一樣(或相同)的文檔應用以上的命令,Elasticsearch將會用一個新的文檔來替換(從新索引)當前ID爲1的那個文檔。

curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '
{
"name": "Jane Doe"
}'

以上的命令將ID爲1的文檔的name字段的值從「John Doe」改爲了「Jane Doe」。若是咱們使用一個不一樣的ID,一個新的文檔將會被索引,當前已經在索引中的文檔不會受到影響。

curl -XPUT 'localhost:9200/customer/external/2?pretty' -d '
{
"name": "Jane Doe"
}'

以上的命令,將會索引一個ID爲2的新文檔。

在索引的時候,ID部分是可選的。若是不指定,Elasticsearch將產生一個隨機的ID來索引這個文檔。Elasticsearch生成的ID會做爲索引API調用的一部分被返回。

如下的例子展現了怎樣在沒有指定ID的狀況下來索引一個文檔:

curl -XPOST 'localhost:9200/customer/external?pretty' -d '
{
"name": "Jane Doe"
}'

注意,在上面的情形中,因爲咱們沒有指定一個ID,咱們使用的是POST而不是PUT。

更新文檔

除了能夠索引、替換文檔以外,咱們也能夠更新一個文檔。但要注意,Elasticsearch底層並不支持原地更新。在咱們想要作一次更新的時候,Elasticsearch先刪除舊文檔,而後在索引一個更新過的新文檔。

下面的例子展現了怎樣將咱們ID爲1的文檔的name字段改爲「Jane Doe」:

curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '
{
"doc": { "name": "Jane Doe" }
}'

下面的例子展現了怎樣將咱們ID爲1的文檔的name字段改爲「Jane Doe」的同時,給它加上age字段:

curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '
{
"doc": { "name": "Jane Doe", "age": 20 }
}'

更新也能夠經過使用簡單的腳原本進行。這個例子使用一個腳本將age加5:

curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '
{
"script" : "ctx._source.age += 5"
}'

在上面的例子中,ctx._source指向當前要被更新的文檔。

注意,在寫做本文時,更新操做只能一次應用在一個文檔上。未來,Elasticsearch將提供同時更新符合指定查詢條件的多個文檔的功能(相似於SQL的UPDATE-WHERE語句)。

刪除文檔

刪除文檔是至關直觀的。如下的例子展現了咱們怎樣刪除ID爲2的文檔:

curl -XDELETE 'localhost:9200/customer/external/2?pretty'

咱們也可以一次刪除符合某個查詢條件的多個文檔。如下的例子展現瞭如何刪除名字中包含「John」的全部的客戶:

curl -XDELETE 'localhost:9200/customer/external/_query?pretty' -d '
{
"query": { "match": { "name": "John" } }
}'

注意,以上的URI變成了/_query,以此來代表這是一個「查詢刪除」API,其中刪除查詢標準放在請求體中,可是咱們仍然使用DELETE。如今先不要擔憂查詢語法,咱們將會在本教程後面的部分中涉及。

批處理

除了可以對單個的文檔進行索引、更新和刪除以外,Elasticsearch也提供了以上操做的批量處理功能,這是經過使用_bulk API實現的。這個功能之因此重要,在於它提供了很是高效的機制來儘量快的完成多個操做,與此同時使用盡量少的網絡往返。

做爲一個快速的例子,如下調用在一次bulk操做中索引了兩個文檔(ID 1 - John Doe and ID 2 - Jane Doe):

curl -XPOST 'localhost:9200/customer/external/_bulk?pretty' -d '
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
'

如下例子在一個bulk操做中,首先更新第一個文檔(ID爲1),而後刪除第二個文檔(ID爲2):

curl -XPOST 'localhost:9200/customer/external/_bulk?pretty' -d '
{"update":{"_id":"1"}}
{"doc": { "name": "John Doe becomes Jane Doe" } }
{"delete":{"_id":"2"}}
'

注意上面的delete動做,因爲刪除動做只須要被刪除文檔的ID,因此並無對應的源文檔。

bulk API按順序執行這些動做。若是其中一個動做由於某些緣由失敗了,將會繼續處理它後面的動做。當bulk API返回時,它將提供每一個動做的狀態(按照一樣的順序),因此你可以看到某個動做成功與否。

探索你的數據

樣本數據集

如今咱們對於基本的東西已經有了一些感受,如今讓咱們嘗試使用一些更加貼近現實的數據集。我已經準備了一些假想的客戶的銀行帳戶信息的JSON文檔的樣本。文檔具備如下的模式(schema):

{
    "account_number": 0, "balance": 16623, "firstname": "Bradshaw", "lastname": "Mckenzie", "age": 29, "gender": "F", "address": "244 Columbus Place", "employer": "Euron", "email": "bradshawmckenzie@euron.com", "city": "Hobucken", "state": "CO" } 

我是在http://www.json-generator.com/ 上生成這些數據的。

載入樣本數據

你能夠下載這個樣本數據集。將其解壓到當前目錄下,以下,將其加載到咱們的集羣裏:

curl -XPOST 'localhost:9200/bank/account/_bulk?pretty' --data-binary @accounts.json
curl 'localhost:9200/_cat/indices?v'

響應是:

curl 'localhost:9200/_cat/indices?v' health status index uuid pri rep docs.count docs.deleted store.size pri.store.size yellow open bank Ys0tcL_aRoa2WfndamJmVw 5 1 1000 0 640.3kb 640.3kb 

這意味着咱們成功批量索引了1000個文檔到銀行索引中(account類型)。

搜索API

如今,讓咱們以一些簡單的搜索來開始。有兩種基本的方式來運行搜索:一種是在REST請求的URI中發送搜索參數,另外一種是將搜索參數發送到REST請求體中。請求體方法的表達能力更好,而且你可使用更加可讀的JSON格式來定義搜索。咱們將嘗試使用一次請求URI做爲例子,可是教程的後面部分,咱們將 僅僅使用請求體方法。

搜索的REST API能夠經過_search端點來訪問。下面這個例子返回bank索引中的全部的文檔:

curl 'localhost:9200/bank/_search?q=*&pretty'

咱們仔細研究一下這個查詢調用。咱們在bank索引中搜索(_search端點),而且q=*參數指示Elasticsearch去匹配這個索引中全部的文檔。pretty參數,和之前同樣,僅僅是告訴Elasticsearch返回美觀的JSON結果。

如下是響應(部分列出):

{
  "took" : 6, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1000, "max_score" : 1.0, "hits" : [ { "_index" : "bank", "_type" : "account", "_id" : "25", "_score" : 1.0, "_source" : { "account_number" : 25, "balance" : 40540, "firstname" : "Virginia", "lastname" : "Ayala", "age" : 39, "gender" : "F", "address" : "171 Putnam Avenue", "employer" : "Filodyne", "email" : "virginiaayala@filodyne.com", "city" : "Nicholson", "state" : "PA" } }, { "_index" : "bank", "_type" : "account", 

對於這個響應,咱們看到了如下的部分:

  • took —— Elasticsearch執行這個搜索的耗時,以毫秒爲單位
  • timed_out —— 指明這個搜索是否超時
  • _shards —— 指出多少個分片被搜索了,同時也指出了成功/失敗的被搜索的shards的數量
  • hits —— 搜索結果
  • hits.total —— 可以匹配咱們查詢標準的文檔的總數目
  • hits.hits —— 真正的搜索結果數據(默認只顯示前10個文檔)
  • _score和max_score —— 如今先忽略這些字段

使用請求體方法的等價搜索是:

curl -XPOST 'localhost:9200/bank/_search?pretty' -d '
{
"query": { "match_all": {} }
}'

這裏的不一樣之處在於,並非向URI中傳遞q=*,取而代之的是,咱們在_search API的請求體中POST了一個JSON格式請求體。咱們將在下一部分中討論這個JSON查詢。

有一點須要重點理解一下,一旦你取回了你的搜索結果,Elasticsearch就完成了使命,它不會維護任何服務器端的資源或者在你的結果中打開遊標。 這是和其它相似SQL的平臺的一個鮮明的對比, 在那些平臺上,你能夠在前面先獲取你查詢結果的一部分,而後若是你想獲取結果的剩餘部分,你必須繼續返回服務端去取,這個過程使用一種有狀態的服務器端遊標技術。

做者:山天大畜 連接:https://www.jianshu.com/p/cb539050295d 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
相關文章
相關標籤/搜索