翻譯作品,水平有限笔宿,如有錯誤,煩請留言指正棱诱。原文請見 官網英文文檔
起步
Elasticsearch 是一個大規(guī)模開源的全文搜索和分析引擎泼橘,你可以用它來快速(接近實時)存儲、搜索和分析大量的數(shù)據迈勋。通常被用作基礎的引擎炬灭,或者有復雜的搜索功能和要求的應用的技術支撐。
這兒是一些Elasticsearch簡單的使用場景:
在線網站的數(shù)據存儲靡菇,允許你的客戶對你售賣的產品進行搜索的場景重归。這時米愿,你可以使用Elasticsearch存儲你的全部產品信息分類和庫存,然后提供搜索和自動填充建議提前。
你想做日志和事務數(shù)據的收集吗货,然后對它們進行分析和挖掘,期待找到某種趨勢狈网,或者進行統(tǒng)計宙搬、歸納和異常分析。在這種情況下拓哺,你可以使用logstash( Elasticsearch/Logstash/Kibana 棧的一部分)收集勇垛、匯總和解析數(shù)據,然后logstash將這些數(shù)據傳送到Elasticsearch中士鸥,一旦數(shù)據進入Elasticsearch中闲孤,你就可以使用搜索和聚合來挖掘任何你想要的信息。
價格預警平臺烤礁,允許精打細算的客戶指定特殊的規(guī)則讼积,比如我對某個特定的電子產品比較感興趣,在下個月任意一個供應商的價格下降到指定價格脚仔,然后提醒我勤众。在這種情況下,你可以把供貨商的價格推送到Elasticsearch中鲤脏,利用它的反向搜索(過濾)能力匹配用戶查詢的價格走勢们颜,最后將已經發(fā)現(xiàn)的匹配項發(fā)送給客戶。
你有分析或者商業(yè)智能的需求猎醇,在大量數(shù)據(數(shù)百萬或者數(shù)十億的記錄)中想做個快速的調查窥突、分析、可視化和詢問特殊問題硫嘶。在這種情況下阻问,你可以使用Elasticsearch存儲數(shù)據,使用kibana構建自定義的儀表盤來展示你關心的數(shù)據沦疾。此外则拷,你還可以使用Elasticsearch的聚合功能來做復雜的商業(yè)智能分析與數(shù)據查詢。
接下來的教程曹鸠,我將會引導你完成Elasticsearch的獲取煌茬、安裝和運行,然后稍微深入一點彻桃,介紹一些基本操作坛善,比如建立索引、搜索和修改你的數(shù)據。在教程的最后你應該對Elasticsearch有一個很好的認識眠屎,它是什么剔交,它是怎么工作的。無論是構建復雜的搜索程序還是從你的數(shù)據中挖掘情報改衩,在如何使用Elasticsearch方面岖常,希望你能受到啟發(fā)。
1 基本概念
這里有一些Elasticsearch的主要核心概念葫督,在開始的時候就理解了這些概念竭鞍,對于你的學習過程有非常大的幫助。
準實時
Elasticsearch是一個準實時的搜索平臺橄镜。意思是從你創(chuàng)建一個文檔的索引到這個索引可以被搜索只有很小延遲(通常是1秒)偎快。
集群
一個集群是一個或者多個節(jié)點(服務器)的集合,它們共同擁有所有的數(shù)據洽胶,并且提供跨節(jié)點的索引和搜索能力晒夹。一個集群由一個唯一的名字確定,默認情況下是“elasticsearch”姊氓,這個名字是很重要的丐怯,因為一個節(jié)點僅可能是一個集群的一部分,節(jié)點加入到哪個集群是根據這個名字來判斷的翔横。
一定不要在不同的環(huán)境使用相同的集群名稱读跷,否則你可能將節(jié)點加入到錯誤的集群中,例如你可以分別在開發(fā)環(huán)境棕孙、預備環(huán)境和生產環(huán)境使用logging-dev
, logging-stage
和 logging-prod
。
注意些膨,在一個集群中只有一個節(jié)點也是有效的和非常好的蟀俊。此外,你可以有多個獨立的集群订雾,如果它們的有各自唯一的集群名字肢预。
節(jié)點
一個節(jié)點是一臺服務器,也是一個集群的一部分洼哎,存儲你的數(shù)據烫映,參與提供集群的索引和搜索能力。就像集群一樣噩峦,節(jié)點也是由一個名字唯一確定的锭沟,這個名字默認是一個隨機的UUID,它是在節(jié)點啟動的時候分配的识补。如果你不想要默認的名字族淮,你可以隨意定義你的節(jié)點名稱。這個名字在集群的管理上顯得很重要,他可以讓你確定地知道在elasticsearch集群中的節(jié)點對應網絡中的哪一臺服務器祝辣。
一個節(jié)點可以通過配置集群名稱加入到任意的集群中贴妻,默認情況下,每個節(jié)點都被設置加入到一個名叫elasticsearch
的集群中蝙斜,這意味著名惩,如果你在一個網絡中(服務器之間能夠彼此互相發(fā)現(xiàn))啟動大量這樣的節(jié)點,它們將自動的形成一個集群孕荠,名叫elasticsearch
娩鹉。
在一個集群中你可以有任意多的節(jié)點。此外岛琼,如果在當前節(jié)點運行的網絡中沒有其他的 Elasticsearch 的節(jié)點底循,只啟動一個節(jié)點,它將會形成一個新的單節(jié)點集群槐瑞,名叫elasticsearch
熙涤。
索引
索引是具有相似特性的文檔的集合,例如困檩,你可以為客戶數(shù)據建立一個索引祠挫,你也可以為產品類數(shù)據建立索引,還有訂單數(shù)據也可以建立索引悼沿。一個索引都有一個特定的名字(必需為小寫)標識等舔,在對索引的文檔執(zhí)行索引、搜索糟趾、更新和刪除操作時慌植,該名稱用于指定索引。
在一個集群中义郑,你可以定義任意多的索引蝶柿。
類型
在一個索引中,你可以定義一個或者多個類型非驮,類型是索引的邏輯類/分區(qū)交汤,它的語義完全由你決定。一般來說劫笙,將一組具有公共字段的文檔定義為一種類型芙扎。例如,假設你在運行一個博客平臺填大,你的所有數(shù)據都存儲在一個索引中戒洼,在這個索引中你可能為用戶數(shù)據定義一個類型,博客數(shù)據定義另一個類型允华,注釋數(shù)據為另一個類型施逾。
文檔
文檔是可以被索引的信息的基本單位敷矫。例如,你可以為一個單獨的客戶數(shù)據建立一個文檔汉额,一個單獨的產品也可以建立一個文檔曹仗,還有一個訂單文檔。這些文檔是用JSON格式的數(shù)據來表示的蠕搜,這是一種在互聯(lián)網上無處不在的數(shù)據交互格式怎茫。
在一個索引/類型中,你可以存儲盡可能多的文檔妓灌。注意轨蛤,盡管一個文檔實際是存儲在索引中的,但是實際上你必須將文檔分配到一個索引中的一個類型虫埂。
分片&備份
一個索引可以存儲大量的數(shù)據祥山,這些數(shù)據可能超過單個節(jié)點硬盤限制,例如掉伏,一個存儲了十億文檔的索引占了1TB的磁盤空間缝呕,可能不太適合存儲在一個節(jié)點的硬盤上,或者說單個節(jié)點服務于搜索請求太慢了斧散。
為了解決這個問題供常,Elasticsearch提供了將索引細分為多塊的能力,這些塊被稱為“分片”鸡捐。在你創(chuàng)建索引的時候栈暇,可以簡單地定義所需數(shù)目的分片,每一個分片本身是一個功能全面的箍镜、獨立的“索引”源祈,它可以被托管在集群中的任意節(jié)點。
索引分片有兩個原因是非常重要的:
- 你可以水平拆分/縮放存儲數(shù)據卷色迂。
- 你可以分布式或者并行地執(zhí)行跨分片(可能存儲在多個節(jié)點上)的操作香缺,因此可以提高性能和吞吐量。
分片的分布機制和分片的文檔是如何聚集在一起實現(xiàn)一次用戶的搜索請求脚草,這些完全都是由Elasticsearch管理的赫悄,對用戶來說是透明的原献。
在網絡/云環(huán)境中隨時都有可能失敗馏慨,在一個分片/節(jié)點不知原因地掉線或者消失的情況下,故障轉移機制還是非常有用的姑隅,強烈推薦写隶。為此,Elasticsearch允許你為索引的分片創(chuàng)建一個或多個副本讲仰,這就是所謂的副本分片慕趴,或者簡稱為備份。
備份有兩個原因是非常重要的:
- 在分片或者節(jié)點故障的情況下,它提供了高可用性冕房。正因為這一點躏啰,注意一個副本分片從來不會被分配和主分片(copy的來源節(jié)點)在同一個節(jié)點上,這一點是很重要的耙册。
- 它能提高你的搜索數(shù)據量和吞吐量给僵,因為搜索可以并行地在多個副本上執(zhí)行。
總結一下详拙,一個索引能分成多個分片帝际,一個索引能被復制零(無備份)或多次。一旦復制了之后饶辙,每個索引都有主分片(拷貝的來源分片)和副分片(主分片的拷貝)蹲诀。一個索引的分片和副本的數(shù)量都可以在索引創(chuàng)建的時候定義,在索引創(chuàng)建之后弃揽,你可以隨時動態(tài)的改變副本的數(shù)量脯爪,但是你不能事后修改分片的數(shù)量。
默認情況下蹋宦,在Elasticsearch中的每個索引被分為5個主分片和1個副本披粟,這就意味著在你的集群中至少有兩個節(jié)點,你的索引將有5個主分片和另外5個副分片(一個完整的副本)冷冗,每個索引總共10個分片守屉。
注意,每一個Elasticsearch分片都是一個Lucene索引蒿辙,在一個單獨的Lucene索引中擁有的文檔數(shù)量是有最大值的拇泛,根據
LUCENE-5843
中介紹,這個限制是2,147,483,519 (= Integer.MAX_VALUE - 128)個文檔思灌。你可以使用api_cat/shards
來監(jiān)控分片的大小俺叭。
既然如此,我們就開始有趣的下一part吧泰偿。
2 安裝
Elasticsearch要求java 8 以上熄守,在寫該文檔時屑咳,建議你使用oracle的JDK版本1.8.0_131膀钠,關于java在各個平臺的安裝過程這里就不詳細介紹了,在oracle的官網上能夠找到oracle推薦的安裝文檔在刺,我只想說调塌,在你安裝Elasticsearch之前晋南,請檢查你的當前運行的java版本(根據需要安裝或升級java):
java -version
echo $JAVA_HOME
如果你已經安裝了java,我們就可以開始下載和運行Elasticsearch了羔砾。在 www.elastic.co/downloads
這個網址上可以下載到可用的二進制包负间,還有過去發(fā)行的其它版本的包偶妖。對于每一個發(fā)行版本,你都可以選擇zip
或者tar
壓縮包政溃,還有DEB
和RPM
包趾访。為了簡單起見,我們以tar包為例董虱。
讓我首先使用下面的命令下載Elasticsearch5.4.1版本的tar文件(windows用戶應該下載zip包):
curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.1.tar.gz
然后腹缩,使用下面的命令解壓它(windows用戶應該使用unzip來解壓zip包):
tar -xvf elasticsearch-5.4.1.tar.gz
解壓完成之后,將會在當前目錄產生大量的文件和文件夾空扎,然后我們進入到bin目錄下藏鹊,命令如下:
cd elasticsearch-5.4.1/bin
現(xiàn)在我們可以準備啟動這個節(jié)點和單節(jié)點集群了(windows用戶應該運行.bat文件):
./elasticsearch
如果一切順利的話,你將看到很多信息輸出转锈,像下面這樣:
[2016-09-16T14:17:51,251][INFO ][o.e.n.Node ] [] initializing ...
[2016-09-16T14:17:51,329][INFO ][o.e.e.NodeEnvironment ] [6-bjhwl] using [1] data paths, mounts [[/ (/dev/sda1)]], net usable_space [317.7gb], net total_space [453.6gb], spins? [no], types [ext4]
[2016-09-16T14:17:51,330][INFO ][o.e.e.NodeEnvironment ] [6-bjhwl] heap size [1.9gb], compressed ordinary object pointers [true]
[2016-09-16T14:17:51,333][INFO ][o.e.n.Node ] [6-bjhwl] node name [6-bjhwl] derived from node ID; set [node.name] to override
[2016-09-16T14:17:51,334][INFO ][o.e.n.Node ] [6-bjhwl] version[5.4.1], pid[21261], build[f5daa16/2016-09-16T09:12:24.346Z], OS[Linux/4.4.0-36-generic/amd64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_60/25.60-b23]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [aggs-matrix-stats]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [ingest-common]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [lang-expression]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [lang-groovy]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [lang-mustache]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [lang-painless]
[2016-09-16T14:17:51,967][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [percolator]
[2016-09-16T14:17:51,968][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [reindex]
[2016-09-16T14:17:51,968][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [transport-netty3]
[2016-09-16T14:17:51,968][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded module [transport-netty4]
[2016-09-16T14:17:51,968][INFO ][o.e.p.PluginsService ] [6-bjhwl] loaded plugin [mapper-murmur3]
[2016-09-16T14:17:53,521][INFO ][o.e.n.Node ] [6-bjhwl] initialized
[2016-09-16T14:17:53,521][INFO ][o.e.n.Node ] [6-bjhwl] starting ...
[2016-09-16T14:17:53,671][INFO ][o.e.t.TransportService ] [6-bjhwl] publish_address {192.168.8.112:9300}, bound_addresses {{192.168.8.112:9300}
[2016-09-16T14:17:53,676][WARN ][o.e.b.BootstrapCheck ] [6-bjhwl] max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
[2016-09-16T14:17:56,731][INFO ][o.e.h.HttpServer ] [6-bjhwl] publish_address {192.168.8.112:9200}, bound_addresses {[::1]:9200}, {192.168.8.112:9200}
[2016-09-16T14:17:56,732][INFO ][o.e.g.GatewayService ] [6-bjhwl] recovered [0] indices into cluster_state
[2016-09-16T14:17:56,748][INFO ][o.e.n.Node ] [6-bjhwl] started
不過分深入細節(jié)的話盘寡,我們可以看到名為6-bjhwl
(這是一組不同的字符,視你的情況而定)的節(jié)點已經啟動了撮慨,并且它自己被選舉為單節(jié)點的集群中的master節(jié)點竿痰。此刻你不用擔心master意味著什么,這里重要的事情是砌溺,我們已經在一個集群中啟動了一個節(jié)點影涉。
正如前面所說的,我們可以覆蓋集群和節(jié)點的名字规伐,這個可以在啟動Elasticsearch的命令中做到蟹倾,命令如下:
./elasticsearch -Ecluster.name=my_cluster_name -Enode.name=my_node_name
同時還要注意信息中的http地址(192.168.8.112)和端口(9200),這是節(jié)點的訪問入口猖闪。默認情況下鲜棠,Elasticsearch使用端口9200提供REST API的訪問,這個端口在必要的時候也是可以配置的培慌。
3 探索集群
REST API
現(xiàn)在我們已經啟動了我們的節(jié)點(和集群)豁陆,它們正在運行中,下一步我們需要理解怎樣和它交流吵护。幸運的是盒音,Elasticsearch提供了非常全面、強大的REST API馅而,你可以使用這些API接口與你的集群交互祥诽。下面這些事情都可以通過API來完成:
- 檢查你的集群、節(jié)點和索引的健康情況用爪、狀態(tài)和一些統(tǒng)計
- 管理你的集群原押、節(jié)點和索引數(shù)據胁镐、元數(shù)據
- 執(zhí)行CRUD(創(chuàng)建偎血、讀取诸衔、更新和刪除)操作和針對索引的搜索操作
- 執(zhí)行高級的搜索操作,例如分頁颇玷、排序笨农、過濾、腳本帖渠、聚合谒亦,還有很多其他的操作
集群健康
讓我們以基本的健康檢查開始,健康檢查可以讓我們了解集群的運行情況空郊。我們使用curl命令來調用這些API份招,你也可以使用任意其它的HTTP/REST調用工具。假設我們已經登錄了運行著Elasticsearch的同一個節(jié)點狞甚,并且打開了一個shell命令行窗口锁摔。
為了檢查集群的健康度,我們將使用_cat
API.哼审。你可以點擊"VIEW IN CONSOLE"在Kibana’s Console上執(zhí)行下面的命令谐腰,或者點擊 "COPY AS CURL" 之后粘貼到你的終端上使用curl
命令。
GET /_cat/health?v
然后涩盾,下面就是響應:
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1475247709 17:01:49 elasticsearch green 1 1 0 0 0 0 0 0 - 100.0%
我們可以從中看到十气,集群的名字叫“elasticsearch”,是綠色的狀態(tài)春霍。
無論什么時候我們檢查集群的健康狀況砸西,都是綠色、黃色址儒、紅色籍胯。綠色意味著一切都是好的(集群的所有功能都能正常使用);黃色意味著所有數(shù)據都是可用的离福,但是缺少一些分片(集群的所有功能都能正常使用)杖狼;紅色意味著不管什么原因一些數(shù)據是不可用的;注意妖爷,即使集群的狀態(tài)是紅色蝶涩,還是有部分功能是可用的(例如,它將繼續(xù)可以用來從可用的分片上搜索數(shù)據)絮识,但是你可能需要盡快修復它绿聘,因為你已經丟失了數(shù)據。
從上面的響應中我們還可以看出次舌,總共就只有一個節(jié)點熄攘,零個分片是因為里面沒有數(shù)據。注意我們使用的是默認的集群名字(Elasticsearch)彼念,Elasticsearch默認的使用單播網絡來發(fā)現(xiàn)同一臺機器上的其它節(jié)點挪圾,你也有可能意外地在一臺機器上啟動了多個節(jié)點浅萧,然后它們組成了一個集群。在這種情形下哲思,你可能在上面的響應中看到多個節(jié)點洼畅。
我們也可以查看集群中的所有節(jié)點,像下面這樣:
GET /_cat/nodes?v
然后棚赔,響應如下:
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1 10 5 5 4.46 mdi * PB2SGZY
這里我們可以看出帝簇,只有一個名叫“PB2SGZY”的節(jié)點,它是當前集群中的唯一的一個節(jié)點靠益。
列出所有索引
現(xiàn)在讓我們看一下我們的索引:
GET /_cat/indices?v
然后丧肴,響應如下:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
這僅僅意味著在我們的集群中沒有索引。
創(chuàng)建索引
現(xiàn)在讓我們創(chuàng)建一個名叫“customer”索引胧后,然后再次列出所有的索引:
PUT /customer?pretty
GET /_cat/indices?v
第一條命令使用動詞PUT創(chuàng)建了一個名叫“customer”的索引闪湾,在命令的結尾僅僅跟了一個pretty
,意思是任何響應都以JSON的形式打印出來绩卤。
然后途样,響應如下:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open customer 95SQ4TSUT7mWBT7VNHH67A 5 1 0 0 260b 260b
第二條命令的結果告訴我們,現(xiàn)在我們由一個名叫“customer”的索引濒憋,它有5個主分片和1個副本(默認)何暇,其中沒有任何文檔。
你可能還注意到customer索引有一個黃色的健康標記凛驮,回顧我們之前的討論裆站,黃色意味著一些分片沒有被分配。出現(xiàn)這種情況的原因是黔夭,Elasticsearch默認情況下會為這個索引創(chuàng)建一個副本宏胯,但是此刻集群中僅有一個節(jié)點,只有另一個節(jié)點加入到集群中時本姥,這個副本才可能被分配(高可用)肩袍。一旦副本被分配到第二個節(jié)點中,這個索引的健康狀態(tài)立馬就會變成綠色婚惫。
索引和查詢文檔
現(xiàn)在讓我們先在customer索引中放一些東西氛赐,還記得之前我們?yōu)槲臋n創(chuàng)建索引,必須告訴Elasticsearch文檔應該被放在索引中的什么類型下先舷。
讓我們將一個簡單的客戶文檔放進customer索引中艰管,external類型中,ID為1蒋川,就像下面這樣:
PUT /customer/external/1?pretty
{
"name": "John Doe"
}
然后牲芋,響應如下:
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"created" : true
}
從上面的響應中我們可以看出,一個新的客戶文檔被成功地創(chuàng)建在customer索引的external類型中,這個文檔還有一個內部id為1缸浦,在索引文檔時候它需要被指定夕冲。
特別需要注意的是,Elasticsearch沒有明確要求你在索引一個文檔之前首先創(chuàng)建一個索引餐济,就前面的例子而言,如果事先customer索引不存在胆剧,Elasticsearch會自動的創(chuàng)建它絮姆。
現(xiàn)在讓我們去檢索一下剛剛編入索引的那個文檔:
GET /customer/external/1?pretty
然后,響應如下:
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : { "name": "John Doe" }
}
除了其中的found
字段沒有什么特別的地方秩霍,說明我們找到了請求的ID為1的那個文檔篙悯,另一個字段是_source
,它返回了我們上一步中編入索引的完全的JSON格式的文檔铃绒。
刪除索引
現(xiàn)在讓我們刪除剛剛創(chuàng)建的索引鸽照,然后再次列出所有的索引:
DELETE /customer?pretty
GET /_cat/indices?v
然后,響應如下:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
這就是說索引已經被成功刪除颠悬,現(xiàn)在我們又回到了開始時集群中什么都沒有的狀態(tài)矮燎。
在繼續(xù)學習之前,讓我們再仔細看看我們學到的一些API命令:
PUT /customer
PUT /customer/external/1
{
"name": "John Doe"
}
GET /customer/external/1
DELETE /customer
如果我們仔細研究上面的命令赔癌,實際上我們可以看到一種如何從Elasticsearch中訪問數(shù)據的模式诞外,這種模式可以概括如下:
<REST Verb> /<Index>/<Type>/<ID>
這種REST訪問模式在所有的API命令中是普遍存在的,如果你能簡單地記住它灾票,在掌握Elasticsearch上峡谊,你有了一個良好的開端。
4 修改數(shù)據
Elasticsearch提供準實時的數(shù)據操作和搜索功能刊苍。默認情況下既们,從你創(chuàng)建索引/更新/刪除你的數(shù)據到展現(xiàn)出搜索結果應該是只有1秒的延遲(刷新間隔),這是與像SQL等其它平臺的重要區(qū)別正什,它們中的事務操作完成之后數(shù)據立即可用啥纸。
索引和替換文檔
我們前面已經知道了如何將一個單獨的文檔編入索引,讓我們回顧一下命令:
PUT /customer/external/1?pretty
{
"name": "John Doe"
}
同樣婴氮,上面的命令將一個指定的文檔編入到customer索引中脾拆,類型為external,ID為1. 如果我們使用不同(或者相同)的文檔再次執(zhí)行上面的命令莹妒,Elasticsearch將在現(xiàn)存的ID為1的上面替換(或者重建)一個新文檔:
PUT /customer/external/1?pretty
{
"name": "Jane Doe"
}
上面的命令改變了ID為1的文檔的名字名船,由 "John Doe" 改為 "Jane Doe"。另一方面旨怠,如果我們使用不同的ID渠驼,一個新的文檔將會被編入索引,而索引中已經存在的文檔保持不變鉴腻。
PUT /customer/external/2?pretty
{
"name": "Jane Doe"
}
上面的命令將一個ID為2的新文檔編入了索引迷扇。
當我們索引文檔的時候百揭,ID部分是可選的,如果你不指定的話蜓席,Elasticsearch將隨機生成一個ID器一,然后使用它去索引文檔。Elasticsearch實際生成的ID(或者是前面例子中我們明確指定的ID)將作為索引API調用的一部分厨内。
下面的例子展示了在不明確指定ID的情況下如何索引一個文檔:
POST /customer/external?pretty
{
"name": "Jane Doe"
}
注意祈秕,上面的例子中我們使用的是動詞POST
,而不是PUT雏胃,因為我們沒有指定ID请毛。
更新文檔
另外,除了可以索引和替換文檔之外瞭亮,我們還可以更新文檔方仿。需要注意的是,Elasticsearch背后并沒有真正的做更新操作统翩,無論我們什么時候做更新操作仙蚜,Elasticsearch都是刪除舊的文檔,然后將更新后的文檔一次性地作為一個新文檔編入索引厂汗。
下面的例子展示了鳍征,如何更新前面的文檔(ID為1),將它的name字段改為"Jane Doe":
POST /customer/external/1/_update?pretty
{
"doc": { "name": "Jane Doe" }
}
下面的例子展示了面徽,如何更新前面的文檔(ID為1)艳丛,將它的name字段改為"Jane Doe",同時增加一個新的字段age:
POST /customer/external/1/_update?pretty
{
"doc": { "name": "Jane Doe", "age": 20 }
}
更新操作也可以使用簡單的腳本趟紊,下面的例子使用腳本將age字段的值增加5:
POST /customer/external/1/_update?pretty
{
"script" : "ctx._source.age += 5"
}
在上面的例子中氮双,ctx._source
是指即將更新的當前文檔。
注意霎匈,在寫這篇文檔的時候戴差,更新操作還只能一次更新一個文檔。未來铛嘱,elasticsearch可能提供根據查詢條件更新多個文檔的能力(就像SQL UPDATE-WHERE
語句一樣)暖释。
刪除文檔
刪除文檔相對來說是比較簡單的,下面的例子展示了如何刪除ID為2的客戶文檔:
DELETE /customer/external/2?pretty
參見 Delete By Query API 刪除指定查詢條件的所有文檔墨吓。刪除整個索引比根據查詢API刪除該索引下的所有文檔更高效球匕。
批處理
我們除了能索引、更新和刪除單個文檔帖烘,Elasticsearch還提供了使用 _bulk
API批量執(zhí)行上面的任何操作亮曹。這個功能是很重要的,它提供了一種盡可能快并且盡量少的網絡切換條件下執(zhí)行多個操作的高效機制。
做一個快速示范照卦,下面是使用一個bulk操作將兩個文檔(ID 1 - John Doe and ID 2 - Jane Doe)編入索引的例子:
POST /customer/external/_bulk?pretty
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
下面的例子使用一個bulk操作更新第一個文檔(ID為1)式矫,然后刪除第二個文檔(ID為2):
POST /customer/external/_bulk?pretty
{"update":{"_id":"1"}}
{"doc": { "name": "John Doe becomes Jane Doe" } }
{"delete":{"_id":"2"}}
注意上面的刪除操作,在它的后面沒有指定對應的源文檔役耕,因為刪除操作僅需要被刪除文檔的ID采转。
多個操作中的一個失敗不會導致整個bulk操作的失敗,如果其中一個操作不管什么原因失敗了瞬痘,將會繼續(xù)執(zhí)行它后面剩下的操作故慈。在bulk操作的返回信息中將提供每個操作的執(zhí)行狀態(tài),因此你可以檢查某個指定的操作是否失敗了图云。
5 探索數(shù)據
樣本數(shù)據集
現(xiàn)在我們已經了解了一些基本知識惯悠,讓我們研究一下更真實的數(shù)據集邻邮。我已經準備好了一個虛構的JSON文檔示例竣况,它是一個客戶的銀行賬戶信息。每個文檔都有下面的模式:
{
"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"
}
處于好奇筒严,這個數(shù)據我是從這個 www.json-generator.com/
網站上生成的丹泉,因此請忽略其中的數(shù)值和語義,這些都是隨機生成的鸭蛙。
加載樣本數(shù)據集
你可以從這里(accounts.json)下載樣本數(shù)據集摹恨,將其解壓到當前目錄,然后使用下面的命令加載到集群中:
curl -H "Content-Type: application/json" -XPOST 'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json"
curl 'localhost:9200/_cat/indices?v'
然后娶视,響應如下:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open bank l7sSYV2cQXmu6_4rJWVIww 5 1 1000 0 128.6kb 128.6kb
這就意味著剛才成功地將1000個文檔編入bank索引(account 類型下面)晒哄。
搜索API
現(xiàn)在讓我們開始使用一些簡單的搜索,有兩個基本的方法執(zhí)行搜索:一個是通過 REST request URI 發(fā)送搜索參數(shù)肪获,另一個是通過 REST request body 發(fā)送搜索參數(shù)寝凌;Request body方式更有表現(xiàn)力,允許你使用可讀性比較好JSON格式定義你的搜索孝赫。我們嘗試一個Request URI的方式较木,但是教程的其他部分我們將只使用Request Body方式。
搜索的REST API可以通_search
端點來訪問青柄,下面是獲取bank索引下的所有文檔的例子:
GET /bank/_search?q=*&sort=account_number:asc&pretty
讓我們首先剖析一下這個搜索調用伐债,我們正在搜索bank索引(_search
端點),參數(shù)q=*
命令Elasticsearch匹配這個索引下的所有文檔致开,參數(shù)sort=account_number:asc
表明使用每個文檔的account_number
字段進行升序排序峰锁,另外參數(shù)pretty
告訴Elasticsearch返回美化后的JSON結果。
然后双戳,響應如下(展示部分):
{
"took" : 63,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1000,
"max_score" : null,
"hits" : [ {
"_index" : "bank",
"_type" : "account",
"_id" : "0",
"sort": [0],
"_score" : null,
"_source" : {"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"}
}, {
"_index" : "bank",
"_type" : "account",
"_id" : "1",
"sort": [1],
"_score" : null,
"_source" : {"account_number":1,"balance":39225,"firstname":"Amber","lastname":"Duke","age":32,"gender":"M","address":"880 Holmes Lane","employer":"Pyrami","email":"amberduke@pyrami.com","city":"Brogan","state":"IL"}
}, ...
]
}
}
對于響應祖今,我們看一下下面幾個部分:
-
took
Elasticsearch執(zhí)行搜索的耗時,以毫秒為單位; -
timed_out
告訴我們搜索是否超時千诬; -
_shards
告訴我們多少個分片被搜索到耍目,并且顯示搜索成功和失敗的分片數(shù); -
hits
搜索結果徐绑; -
hits.total
匹配搜索標準的文檔總數(shù)邪驮; -
hits.hits
搜索結果的實際陣列(默認前10個文檔); -
hits.sort
搜索結果中的排序key(如果按照分數(shù)排序傲茄,將會缺失)毅访; -
hits._score
和max_score
現(xiàn)在忽略這寫字段;
下面是一個代替上面全部搜索方法的Request Body方法:
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}
與上面的URI中的q=*
相比的不同點是盘榨,我們提交了一個JSON格式的查詢請求到_search
API喻粹。在下一個部分我們將討論JSON的查詢。
要明白一件重要的事草巡,Elasticsearch一旦返回搜索結果守呜,搜索請求就完全結束了,它不會保持任何服務端的資源山憨,也不會維持搜索結果中的游標查乒。這和其他平臺是完全不同的,例如SQL平臺郁竟,開始時可以獲取查詢結果前面的部分子集玛迄,如果你想獲取(或者通過分頁查詢)結果的其余部分棚亩,可以通過某種服務端游標繼續(xù)請求服務器蓖议。
介紹查詢語言
Elasticsearch提供了JSON格式的領域專用的語言,你可以使用它來執(zhí)行查詢讥蟆,具體參考 Query DSL勒虾。該查詢語言是很全面的,乍看一下可能很嚇人攻询,實際上學習它的最好的方法是從一些基本的例子開始从撼。
回到我們的最后一個例子,執(zhí)行這個查詢:
GET /bank/_search
{
"query": { "match_all": {} }
}
剖析一下上面的調用請求钧栖,query
部分告訴我們查詢的定義是什么低零,簡單的說,match_all
是我們想要執(zhí)行的查詢類型拯杠,match_all
查詢是搜索指定索引的全部文檔掏婶。
除了query
參數(shù)以外,我們還可以通過其它參數(shù)來干預搜索結果潭陪,在上一部分的例子中我們使用過sort
雄妥,這里我們使用一下size
:
GET /bank/_search
{
"query": { "match_all": {} },
"size": 1
}
注意最蕾,如果size
不指定的話,默認是10.
下面的例子是一個 match_all
的搜索老厌,然后返回從11到20的文檔:
GET /bank/_search
{
"query": { "match_all": {} },
"from": 10,
"size": 10
}
from
參數(shù)(0為基礎)指定從索引的哪個文檔開始瘟则,size
參數(shù)指定返回從from參數(shù)開始的多少個文檔。這個特性在實現(xiàn)搜索結果的分頁查詢時是很有用的枝秤。注意醋拧,如果from
不指定,默認是0.
下面的例子是一個match_all
的搜索淀弹,然后按照賬戶余額進行降序排列丹壕,然后返回前10(默認)個文檔。
GET /bank/_search
{
"query": { "match_all": {} },
"sort": { "balance": { "order": "desc" } }
}
搜索操作
現(xiàn)在我們已經看到了一些基本的搜索參數(shù)薇溃,讓我們更深入地挖掘一下Query DSL. 讓我們首先看一下返回的文檔的字段菌赖,默認情況下,作為所有搜索的一部分返回完整的JSON文檔沐序,這個被稱作資源(在搜索結果中的hits中的_source
字段)琉用。如果我們不想要返回的整個資源文檔,我們可以僅請求返回的資源中的部分字段薄啥。
下面的例子展示了如何搜索返回兩個字段 account_number
和 balance
(_source
內部):
GET /bank/_search
{
"query": { "match_all": {} },
"_source": ["account_number", "balance"]
}
注意辕羽,上面的例子僅僅是減少了_source
的字段逛尚,它仍然僅返回一個名叫_source
的字段垄惧,但是在它只包含account_number
和 balance
兩個字段。
如果你有SQL背景绰寞,這個在概念上有點類似于SQL SELECT FROM
的字段列表到逊。
現(xiàn)在讓我們把注意力轉到查詢部分,前面我們已經看到match_all
查詢是如何匹配所有文檔的滤钱,現(xiàn)在讓我們介紹一個新的查詢叫 match
query觉壶,可以認為它是基本字段的搜索查詢(例如,指定一個字段或者多個字段來完成一次搜索)件缸。
下面的例子是返回賬戶編號為20的文檔:
GET /bank/_search
{
"query": { "match": { "account_number": 20 } }
}
下面的例子是返回地址包含“mill”的所有賬戶:
GET /bank/_search
{
"query": { "match": { "address": "mill" } }
}
下面的例子是返回地址包含“mill”或者“l(fā)ane”的所有賬戶:
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
下面的例子是match
的一個變形(match_phrase
)铜靶,它返回地址中包含短語“mill lane”的所有賬戶:
GET /bank/_search
{
"query": { "match_phrase": { "address": "mill lane" } }
}
現(xiàn)在讓我介紹bool(ean) query。bool
查詢允許我們使用bool邏輯將小的查詢組合成大查詢他炊。
下面的例子是組合兩個match
查詢争剿,然后返回在地址中包含“mill” 和 “l(fā)ane”的所有賬戶:
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
在上面的例子中,bool must
分句指定所有查詢條件必須是“true”才算匹配的文檔痊末。
與此相反蚕苇,下面的例子組合兩個match
查詢,返回在地址中包含“mill” 或 “l(fā)ane”的所有賬戶:
GET /bank/_search
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
在上面的例子中凿叠,bool should
分句指定一個查詢列表涩笤,其中必須有一個是“true”的文檔才算被匹配嚼吞。
下面的例子組合兩個match
查詢,返回在地址中既不包含“mill” 也不包含 “l(fā)ane”的所有賬戶:
GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
在上面的例子中蹬碧,must_not
分句指定一個查詢列表舱禽,其中必須都不是“true”的文檔才算被匹配。
我們可以同時在一個bool
查詢中組合must
, should
和 must_not
分句恩沽。此外呢蔫,我們可以在任何bool
分句中組合bool
查詢,以便模擬任何復雜的多級bool邏輯飒筑。
下面的例子返回年齡是40歲但不住在ID(aho)的所有人的賬戶:
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
過濾操作
在前面的部分我們跳過了一個小細節(jié)所謂的文檔得分(也就是搜索結果中的_score
字段)片吊。得分是數(shù)值型的,它是文檔和我們指定的搜索查詢匹配程度的相對度量协屡。得分越高俏脊,文檔越相關跌穗;得分越低不跟,文檔越不相關。
但是查詢并不總是需要得分艇炎,尤其是它們僅被用作文檔集合的過濾器時补憾。Elasticsearch探測到這種情況會自動地優(yōu)化查詢的執(zhí)行漫萄,防止計算無用的得分。
在前面我們介紹的 bool query 也是支持filter
分句的盈匾,它允許使用查詢來限制其它分句匹配的文檔腾务,而不改變得分的計算。作為一個例子削饵,我們來介紹一下range
query 岩瘦,它允許我們使用一個值域來過濾文檔,這通常被用于數(shù)值型和日期型的過濾器窿撬。
下面的例子使用bool 查詢獲取余額在20000和30000之間的所有賬戶启昧,換句話說,我們是想找到余額大于等于20000并且小于等于30000的賬戶劈伴。
GET /bank/_search
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
}
}
}
仔細分析一下上面的例子密末,bool查詢包括一個match all
查詢(查詢的一部分)和一個range
查詢(過濾的一部分)。我們可以將其它任何查詢替換成查詢和過濾組成跛璧。在上面的例子中严里,range查詢是很有意義的,因為所有在范圍內的文檔都是相等的赡模,沒有哪個文檔比另外的文檔更相關田炭。
除了 match_all
, match
, bool
, and range
查詢之外,還有很多其它類型的查詢漓柑,我們不會在這里討論它們教硫。因為我們對它們的工作原理有了基本的理解叨吮,將這些知識應用于其它類型的查詢,學習和使用它們都不會太難瞬矩。
聚合操作
聚合提供了對數(shù)據進行分組茶鉴、提取統(tǒng)計結果的能力。想明白聚合的最簡單的方法是將其大致等同于SQL分組和SQL的聚合函數(shù)景用。在Elasticsearch中涵叮,可以執(zhí)行搜索獲取hits,同時也能在同一個響應中返回區(qū)別于hits的聚合結果伞插。從這一點來說割粮,它是很強大和高效的,你可以執(zhí)行查詢和多聚合操作媚污,并且這些操作結果一起返回舀瓢,使用這樣簡單的API避免了網絡的切換。
首先耗美,下面的例子是將所有賬戶按照州來分組京髓,然后返回按照數(shù)量的降序排列的前10個州(默認):
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}
在SQL中,上面的聚合在概念上類似于:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
然后商架,響應如下(部分展示):
{
"took": 29,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits" : {
"total" : 1000,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"group_by_state" : {
"doc_count_error_upper_bound": 20,
"sum_other_doc_count": 770,
"buckets" : [ {
"key" : "ID",
"doc_count" : 27
}, {
"key" : "TX",
"doc_count" : 27
}, {
"key" : "AL",
"doc_count" : 25
}, {
"key" : "MD",
"doc_count" : 25
}, {
"key" : "TN",
"doc_count" : 23
}, {
"key" : "MA",
"doc_count" : 21
}, {
"key" : "NC",
"doc_count" : 21
}, {
"key" : "ND",
"doc_count" : 21
}, {
"key" : "ME",
"doc_count" : 20
}, {
"key" : "MO",
"doc_count" : 20
} ]
}
}
}
我們可以看出在ID
(Idaho)州由27個賬戶堰怨,在TX
(Texas)州有個27個賬戶,在AL
(Alabama)州有25個賬戶蛇摸,等等备图。
注意上面我們設置size=0
是為了不展示搜索結果,因為我們僅想在響應中看到聚合結果皇型。
在前面的聚合操作的基礎上诬烹,下面的例子計算了每個州的賬戶余額平均值(同樣僅展示賬戶總數(shù)降序排列的前10個州):
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
請注意我們是如何將average_balance
聚合嵌套在group_by_state
聚合中的砸烦,這是所有聚合中常見的模式弃鸦,為了從數(shù)據中提取總結你需要的信息,可以嵌套聚合到任意其它的聚合之中幢痘。
在前面的聚合的基礎上唬格,現(xiàn)在讓我們按照余額的平均值進行降序排列:
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"average_balance": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
下面的例子演示了如何通過年齡組( 20-29, 30-39, 和 40-49)進行分組,然后按照性別分組颜说,最后獲得在每個年齡組每個性別中賬戶余額的平均值:
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_age": {
"range": {
"field": "age",
"ranges": [
{
"from": 20,
"to": 30
},
{
"from": 30,
"to": 40
},
{
"from": 40,
"to": 50
}
]
},
"aggs": {
"group_by_gender": {
"terms": {
"field": "gender.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
}
}
還有很多其它的聚合功能购岗,這里我們就不詳細一一介紹了,如果你想進一步學習聚合的操作门粪, aggregations reference guide 是一個不錯的參考文檔喊积。
6 結論
Elasticsearch是一個既簡單又復雜的產品。到目前為止玄妈,我們已經了解了它的基本原理乾吻,如何查看它的內部髓梅,如何使用一些REST API操作它。我希望這個教程讓你更好地理解了Elasticsearch是什么绎签,更重要是枯饿,激發(fā)你去進一步探索Elasticsearch的其余特性。
Elasticsearch的起步教程終于翻譯完了诡必,這個翻譯文檔只是入門級的介紹Elasticsearch奢方,希望能對你的學習有所幫助。