Elasticsearch 使用 Java 開發並使用 Lucene 做爲其核心來實現全部索引和搜索的功能,它的目的是經過簡單的 RESTful API 來隱藏 Lucene 的複雜性,從而讓全文搜索變得簡單。node
特色:數據庫
Elasticsearch 在安裝以前要安裝 Java ,而後從官網中下載 Elasticsearch 的壓縮包,在本地的自定義的目錄下進行解壓便可。另外有一個 Elasticsearch 的管理和監控工具 Marvel ,它包含了一個叫作 Sense 的交互式控制檯,使用戶方便的經過瀏覽器直接與 Elasticsearch 進行交互。這個不是必需要安裝的。數組
若是是用 Java 開發語言,那能夠直接使用 Java API,Elasticsearch 爲 Java 用戶提供了兩種內置客戶端:節點客戶端和傳輸客戶端瀏覽器
以 JSON 爲數據交互格式的 RESTful API ,全部程序語言均可以使用 RESTful API ,經過默認的 9200 端口的與Elasticsearch 進行通訊。向 Elasticsearch 發出的請求的組成部分與其它普通的HTTP請求是同樣的:服務器
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
VERB HTTP方法:GET, POST, PUT, HEAD, DELETE
PROTOCOL http或者https協議(只有在Elasticsearch前面有https代理的時候可用)
HOST Elasticsearch集羣中的任何一個節點的主機名,若是是在本地的節點,那麼就叫localhost
PORT Elasticsearch HTTP服務所在的端口,默認爲9200
PATH API路徑(例如_count將返回集羣中文檔的數量),PATH能夠包含多個組件,例如_cluster/stats或者_nodes/stats/jvm
QUERY_STRING 一些可選的查詢請求參數,例如?pretty參數將使請求返回更加美觀易讀的JSON數據
BODY 一個JSON格式的請求主體(若是請求須要的話)
複製代碼
舉例:數據結構
curl -XGET 'http://localhost:9200/_count?pretty' -d '
{
"query": {
"match_all": {}
}
}
'
複製代碼
Elasticsearch 是面向文檔 (document oriented) 的,這意味着它能夠存儲整個對象或文檔 (document) 。然而它不只僅是存儲,還會索引 (index) 每一個文檔的內容使之能夠被搜索。在 Elasticsearch 中,你能夠對文檔(而非成行成列的數據)進行索引、搜索、排序、過濾。這種理解數據的方式與以往徹底不一樣,這也是 Elasticsearch 可以執行復雜的全文搜索的緣由之一。負載均衡
ELasticsearch 使用 JSON ,做爲文檔序列化格式。JSON 如今已經被大多語言所支持,並且已經成爲NoSQL領域的標準格式。它簡潔、簡單且容易閱讀。curl
JSON 文檔來表示一個用戶對象:
{
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith",
"info": {
"bio": "Eco-warrior and defender of the weak",
"age": 25,
"interests": [ "dolphins", "whales" ]
},
"join_date": "2014/05/01"
}
複製代碼
在 Elasticsearch 中,文檔歸屬於一種類型 (type) ,而這些類型存在於索引 (index) 中,咱們能夠畫一些簡單的對比圖來類比傳統關係型數據庫:jvm
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch 集羣能夠包含多個索引 (indices) (數據庫),每個索引能夠包含多個類型 (types)(表),每個類型包含多個文檔 (documents)(行),而後每一個文檔包含多個字段 (Fields)(列)。
複製代碼
「索引」的含義:分佈式
索引 (index) 這個詞在 Elasticsearch 中有着不一樣的含義,因此有必要在此作一下區分:
索引(名詞): 如上文所述,一個索引 (index) 就像是傳統關係數據庫中的數據庫,它是相關文檔存儲的地方,index的複數是 indices 或 indexes。
索引(動詞): 「索引一個文檔」表示把一個文檔存儲到索引(名詞)裏,以便它能夠被檢索或者查詢。這很像SQL中的 INSERT 關鍵字,差異是,若是文檔已經存在,新的文檔將覆蓋舊的文檔。
倒排索引:傳統數據庫爲特定列增長一個索引,例如 B-Tree 索引來加速檢索。Elasticsearch 和 Lucene 使用一種叫作倒排索引 (inverted index) 的數據結構來達到相同目的。
複製代碼
增長一個員工信息具體操做案例:
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
其中 megacorp 是索引名,employee 是類型名, 1 是員工 ID。
複製代碼
而後能夠繼續試着添加若干個員工:
PUT /megacorp/employee/2
{
"first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ]
}
PUT /megacorp/employee/3
{
"first_name" : "Douglas",
"last_name" : "Fir",
"age" : 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}
複製代碼
執行 HTTP 的 GET 請求並指出文檔的「地址」——索引、類型和 ID 既可:
GET /megacorp/employee/1
複製代碼
根據這三部分信息,咱們就能夠返回原始 JSON 文檔,響應的內容中包含一些文檔的元信息。John Smith 的原始 JSON 文檔包含在 _source 字段中。
{
"_index" : "megacorp",
"_type" : "employee",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
}
複製代碼
經過 HTTP 方法 GET 來檢索文檔,一樣的,咱們可使用 DELETE 方法刪除文檔,使用 HEAD 方法檢查某文檔是否存在。若是想更新已存在的文檔,咱們只需再 PUT 一次。
嘗試一個最簡單的搜索所有員工的請求,與上一個命令不一樣指出是在結尾使用關鍵字 _search 來取代原來的文檔 ID 。響應內容的 hits 數組中包含了咱們全部的三個文檔。默認狀況下搜索會返回前 10 個結果:
GET /megacorp/employee/_search
{
"took": 6,
"timed_out": false,
"_shards": { ... },
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "megacorp",
"_type": "employee",
"_id": "3",
"_score": 1,
"_source": {
"first_name": "Douglas",
"last_name": "Fir",
"age": 35,
"about": "I like to build cabinets",
"interests": [ "forestry" ]
}
},
{
"_index": "megacorp",
"_type": "employee",
"_id": "1",
"_score": 1,
"_source": {
"first_name": "John",
"last_name": "Smith",
"age": 25,
"about": "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
},
{
"_index": "megacorp",
"_type": "employee",
"_id": "2",
"_score": 1,
"_source": {
"first_name": "Jane",
"last_name": "Smith",
"age": 32,
"about": "I like to collect rock albums",
"interests": [ "music" ]
}
}
]
}
}
複製代碼
若是要搜索姓氏中包含 「Smith」 的員工。能夠在命令行中使用輕量級的搜索方法。這種方法常被稱做查詢字符串 (query string) 搜索,由於咱們像傳遞 URL 參數同樣去傳遞查詢語句:
GET /megacorp/employee/_search?q=last_name:Smith
複製代碼
請求中依舊使用 _search 關鍵字,而後將查詢語句傳遞給參數 q= 。這樣就能夠獲得全部姓氏爲 Smith 的結果。
查詢字符串搜索便於經過命令行完成特定的搜索,可是它也有侷限性(參閱簡單搜索章節)。Elasticsearch 提供豐富且靈活的查詢語言叫作 DS L查詢 (Query DSL) ,它容許你構建更加複雜、強大的查詢。
DSL (Domain Specific Language 特定領域語言) 以 JSON 請求體的形式出現。咱們能夠這樣表示以前關於 Smith 的查詢:
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
複製代碼
返回的結果和以前查詢的結果同樣,可是這裏不使用查詢字符串 (query string) 作爲參數,而是使用請求體代替。這個請求體使用 JSON 表示,其中使用了 match 語句。
若是須要結合更復雜條件進行搜索,則須要添加過濾器,以下:
GET /megacorp/employee/_search
{
"query" : {
"filtered" : {
"filter" : {
"range" : {
"age" : { "gt" : 30 } <1>
}
},
"query" : {
"match" : {
"last_name" : "smith" <2>
}
}
}
}
}
複製代碼
<1> 這部分查詢屬於區間過濾器 (range filter) ,它用於查找全部年齡大於 30 歲的數據—— gt 爲 "greater than" 的縮寫。
<2> 這部分查詢與以前的 match 語句(query)一致。
結果中只顯示了一個員工:
{
...
"hits": {
"total": 1,
"max_score": 0.30685282,
"hits": [
{
...
"_source": {
"first_name": "Jane",
"last_name": "Smith",
"age": 32,
"about": "I like to collect rock albums",
"interests": [ "music" ]
}
}
]
}
}
複製代碼
到目前爲止搜索都很簡單:搜索特定的名字,經過年齡篩選。接下來可使用一種更高級的搜索,全文搜索——一種傳統數據庫很難實現的功能。搜索全部喜歡 「rock climbing」 的員工:
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"about" : "rock climbing"
}
}
}
複製代碼
獲得兩個匹配的結果文檔:
{
...
"hits": {
"total": 2,
"max_score": 0.16273327,
"hits": [
{
...
"_score": 0.16273327, <1>
"_source": {
"first_name": "John",
"last_name": "Smith",
"age": 25,
"about": "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
},
{
...
"_score": 0.016878016, <2>
"_source": {
"first_name": "Jane",
"last_name": "Smith",
"age": 32,
"about": "I like to collect rock albums",
"interests": [ "music" ]
}
}
]
}
}
複製代碼
默認狀況下,Elasticsearch 根據結果相關性評分來對結果集進行排序,所謂的「結果相關性評分」就是文檔與查詢條件的匹配程度。排名第一的 John Smith 的 about 字段明確的寫到 「rock climbing」 。可是爲何 Jane Smith 也會出如今結果裏呢?緣由是 「rock」 在她的 abuot 字段中被說起了。由於只有 「rock」 被說起而 「climbing」 沒有,因此她的 _score 要低於 John 。 這個例子很好的解釋了 Elasticsearch 如何在各類文本字段中進行全文搜索,而且返回相關性最大的結果集。相關性 (relevance) 的概念在 Elasticsearch 中很是重要,而這個概念在傳統關係型數據庫中是不可想象的,由於傳統數據庫對記錄的查詢只有匹配或者不匹配。
目前咱們能夠在字段中搜索單獨的一個詞,可是有時候你想要確切的匹配若干個單詞或者短語 (phrases) 。例如咱們想要查詢同時包含 "rock" 和 "climbing" (而且是相鄰的)的員工記錄。 要作到這個,咱們只要將 match 查詢變動爲 match_phrase 查詢便可:
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
複製代碼
毫無疑問,該查詢返回John Smith的文檔。
不少應用喜歡從每一個搜索結果中高亮 (highlight) 匹配到的關鍵字。在 Elasticsearch 中高亮片斷是很是容易的。在語句上增長highlight參數:
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}
複製代碼
最後運行會獲得相同的結果,可是在返回結果中會有一個新的部分叫作 highlight ,這裏包含了來自 about 字段中的文本。
{
...
"hits": {
"total": 1,
"max_score": 0.23013961,
"hits": [
{
...
"_score": 0.23013961,
"_source": {
"first_name": "John",
"last_name": "Smith",
"age": 25,
"about": "I love to go rock climbing",
"interests": [ "sports", "music" ]
},
"highlight": {
"about": [
"I love to go <em>rock</em> <em>climbing</em>" <1>
]
}
}
複製代碼
Elasticsearch 有一個功能叫作聚合 (aggregations) ,它容許你在數據上生成複雜的分析統計。它很像 SQL 中的 GROUP BY 可是功能更強大。舉例找全部職員中最大的共同點(興趣愛好)是什麼:
GET /megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
複製代碼
運行結果:
{
...
"hits": { ... },
"aggregations": {
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "forestry",
"doc_count": 1
},
{
"key": "sports",
"doc_count": 1
}
]
}
}
}
複製代碼
咱們能夠看到兩個職員對音樂有興趣,一個喜歡林學,一個喜歡運動。這些數據並無被預先計算好,它們是實時的從匹配查詢語句的文檔中動態計算生成的。若是咱們想知道全部姓 "Smith" 的人最大的共同點(興趣愛好),咱們只須要增長合適的語句既可:
GET /megacorp/employee/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}
複製代碼
all_interests 聚合已經變成只包含和查詢語句相匹配的文檔了:
...
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2
},
{
"key": "sports",
"doc_count": 1
}
]
}
複製代碼
聚合也容許分級彙總。例如讓咱們統計每種興趣下職員的平均年齡:
GET /megacorp/employee/_search
{
"aggs" : {
"all_interests" : {
"terms" : { "field" : "interests" },
"aggs" : {
"avg_age" : {
"avg" : { "field" : "age" }
}
}
}
}
}
複製代碼
雖然此次返回的聚合結果有些複雜,但任然很容易理解:
...
"all_interests": {
"buckets": [
{
"key": "music",
"doc_count": 2,
"avg_age": {
"value": 28.5
}
},
{
"key": "forestry",
"doc_count": 1,
"avg_age": {
"value": 35
}
},
{
"key": "sports",
"doc_count": 1,
"avg_age": {
"value": 25
}
}
]
}
複製代碼
能夠看出經過這個特性能夠完成至關複雜的聚合工做,你能夠處理任何類型的數據。
Elasticsearch 在分佈式概念上作了很大程度上的透明化,用戶不須要知道任何關於分佈式系統、分片、集羣發現或者其餘大量的分佈式概念。既能夠運行在你的筆記本上,也能夠運行在擁有100個節點的集羣上,其工做方式是同樣的。
Elasticsearch 致力於隱藏分佈式系統的複雜性。如下這些操做都是在底層自動完成的:
將你的文檔分區到不一樣的容器或者分片 (shards) 中,它們能夠存在於一個或多個節點中。
將分片均勻的分配到各個節點,對索引和搜索作負載均衡。
冗餘每個分片,防止硬件故障形成的數據丟失。
將集羣中任意一個節點上的請求路由到相應數據所在的節點。
不管是增長節點,仍是移除節點,分片均可以作到無縫的擴展和遷移。複製代碼