目錄
1 和elasticsearch交互
-
1.1 格式
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
-
1.2 查詢實例
# 計算集羣中文檔數量 curl -XGET 'http://localhost:9200/_count?pretty' # 返回http請求頭部信息 curl -i -XGET 'http://localhost:9200/_count?pretty' # 集羣健康狀態 Yellow:副本分片異常 Red:主分片異常 curl -i -XGET "http://localhost:9200/_cluster/health"
2 面向文檔
elasticsearch是 面向文檔 的,存儲整個對象或文檔、索引每個文檔內容,使之可以被檢索.
elasticsearch使用Json作爲文檔的序列化格式.
3 簡單示例瞭解elasticsearch如何工作
-
3.1 索引員工文檔
elasticsearch中"索引"含義:
名稱 說明 索引(名詞) 一個"索引"類似關係型數據庫的一個"數據庫",存儲關係型文檔地方. 索引(動詞) 索引一個文檔就是存儲一個文檔到一個"索引"中以便被檢索和查詢. 類似於SQL語句的INSERT語句. 倒排索引 創建索引
PUT /megacorp/employee/1 curl -X PUT "localhost:9200/megacorp/employee/1?pretty" -H 'Content-Type: application/json' -d '' { "first_name" : "John", "last_name" : "Smith", "age" : 25, "about" : "I love to go rock climbing", "interests": [ "sports", "music" ] } PUT /megacorp/employee/2 curl -X PUT "localhost:9200/megacorp/employee/1?pretty" -H 'Content-Type: application/json' -d '' { "first_name" : "Jane", "last_name" : "Smith", "age" : 32, "about" : "I like to collect rock albums", "interests": [ "music" ] } PUT /megacorp/employee/3 curl -X PUT "localhost:9200/megacorp/employee/1?pretty" -H 'Content-Type: application/json' -d '' { "first_name" : "Douglas", "last_name" : "Fir", "age" : 35, "about": "I like to build cabinets", "interests": [ "forestry" ] }
-
3.2 查詢(ad-hoc)
GET /megacorp/employee/1 curl -X GET "localhost:9200/megacorp/employee/1?pretty"
# 返回所有文檔信息 GET /megacorp/employee/_search curl -X GET "localhost:9200/megacorp/employee/_search?pretty" # 添加查詢字符串搜索 GET /megacorp/employee/_search?q=last_name:Smith curl -X GET "localhost:9200/megacorp/employee/_search?q=last_name:Smith&pretty"
GET /megacorp/employee/_search curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d '' { "query" : { "match" : { "last_name" : "Smith" } } }
GET /megacorp/employee/_search curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d '' { "query" : { "bool": { # 布爾表達式 "must": { "match" : { "last_name" : "Smith" } }, "filter": { "range" : { # range 過濾器 "age" : { "gt" : 30 } } } } } }
elasticsearch默認按照相關性得分排序,即每個文檔跟查詢的匹配程度.
對於搜索到任何一個字符串的查詢都會被返回.GET /megacorp/employee/_search curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d '' { "query" : { "match" : { "about" : "rock climbing" } } }
精確匹配一系列單詞或者短語.
只會返回包含短語"rock climbing"的文檔.GET /megacorp/employee/_search curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d '' { "query" : { "match_phrase" : { "about" : "rock climbing" } }, "highlight": { # 高亮搜索,搜索結果"about"字段會被html修飾 "fields" : { "about" : {} } } }
-
3.3 查詢(請求體查詢)
查詢表達式(Query DSL)是一種非常靈活又富有表現力的 查詢語言。 Elasticsearch 使用它可以以簡單的 JSON 接口來展現 Lucene 功能的絕大部分。
# 空查詢 POST/GET /_search curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d' {} ' # 空查詢類似於match_all GET /_search curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match_all": {} } } ' # 查詢tweet字段中是否包含elasticsearch GET /_search curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match": { "tweet": "elasticsearch" } } } '
# 查找 title 字段匹配 how to make millions 並且不被標識爲 spam 的文檔 # 被標識爲 starred 或在2014之後的文檔,將比另外那些文檔擁有更高的排名 { "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }}, { "range": { "date": { "gte": "2014-01-01" }}} ] } } ==> 如果沒有 must 語句,那麼至少需要能夠匹配其中的一條 should 語句. ==> 但,如果存在至少一條 must 語句,則對 should 語句的匹配沒有要求.
當使用於 過濾情況 時,查詢被設置成一個“不評分”或者“過濾”查詢. 即,這個查詢只是簡單的問一個問題:“這篇文檔是否匹配?”. 回答也是非常的簡單,yes 或者 no ,二者必居其一.
對於精確值的查詢,你可能需要使用 filter 語句來取代 query,因爲 filter 將會被緩存.# 帶過濾器組合查詢 { "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }} ], "filter": { "range": { "date": { "gte": "2014-01-01" }} } } } ==> 查找title字段匹配how to make millions,並且不被標識爲spam的文檔. 如果文檔被標識爲starred,那麼該文檔擁有更高的排名得分. ==> 如果文檔date字段大於2014-01-01,那麼使用filter查詢,將不計算相關性排名. # 多個不同的標準來過濾你的文檔,bool 查詢本身也可以被用做不評分的查詢 { "bool": { "must": { "match": { "title": "how to make millions" }}, "must_not": { "match": { "tag": "spam" }}, "should": [ { "match": { "tag": "starred" }} ], "filter": { "bool": { "must": [ { "range": { "date": { "gte": "2014-01-01" }}}, { "range": { "price": { "lte": 29.99 }}} ], "must_not": [ { "term": { "category": "ebooks" }} ] } } } } ==> 查找title字段匹配how to make millions,並且不被標識爲spam的文檔. 如果文檔被標識爲starred,那麼該文檔擁有更高的排名得分. ==> 如果date大於 2014-01-01並且price小於29.99,並且category不等於ebooks,那麼使用filter查詢過濾.
-
3.3.4 自帶的重要查詢語句
- match_all:匹配所有文檔
- match查詢:即可用於全文搜索,也可用於精確查詢
- multi_match:多個字段執行相同的match查詢
- range:找出落在指定區間的數字或者時間 允許的操作符:gt、gte、lt、lte
- term查詢:用於精確值 匹配,這些精確值可能是數字、時間、布爾或者那些 not_analyzed 的字符串
- terms 查詢:允許你指定多值進行匹配,如果這個字段包含了指定值中的任何一個值,那麼這個文檔滿足條件. 不評分
- exists和missing查詢:查找指定字段中有值和無值的文檔.
-
3.3.5 驗證查詢
GET /gb/tweet/_validate/query
-
4 排序和相關性
-
4.1 排序
-
4.1.1 按照字段值排序
GET /_search curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'' { "query" : { "bool" : { "filter" : { "term" : { "user_id" : 1 }} } }, "sort": { "date": { "order": "desc" }} }
-
4.1.2 多級排序
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d' { "query" : { "bool" : { "must": { "match": { "tweet": "manage text search" }}, "filter" : { "term" : { "user_id" : 2 }} } }, "sort": [ { "date": { "order": "desc" }}, { "_score": { "order": "desc" }} ] } '
-
4.1.3 多值字段排序
"sort": { "dates": { "order": "asc", "mode": "min" } }
-
-
4.2 字符串排序與多字段
多字段映射:
"tweet": { "type": "string", "analyzer": "english", "fields": { "raw": { "type": "string", "index": "not_analyzed" } } }
tweet 字段用於搜索,tweet.raw 字段用於排序:
GET /_search { "query": { "match": { "tweet": "elasticsearch" } }, "sort": "tweet.raw" }
5 分析
elasticsearch 有一個功能叫聚合(aggregations),允許我們基於數據生成一些精細的分析結果.
聚合與 SQL 中的 GROUP BY 類似但更強大.
比如這裏對興趣愛好字段:interests進行聚合.
```
# 先執行下面命令,對interests的mapping添加fielddata=true
# 5.x後對排序,聚合這些操作用單獨的數據結構(fielddata)緩存到內存裏了
PUT megacorp/_mapping/employee/
{
"properties": {
"interests": {
"type": "text",
"fielddata": true
}
}
}
# 執行查詢
GET /megacorp/employee/_search
curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d ''
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
輸出結果:兩位員工對音樂感興趣,一位對林業感興趣,一位對運動感興趣.
```
查找叫Smith員工興趣愛好:
```
GET /megacorp/employee/_search
curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d ''
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": {
"field": "interests"
}
}
}
}
```
分級聚合:比如,查詢特定興趣愛好員工的平均年齡.
```
GET /megacorp/employee/_search
curl -X GET "localhost:9200/megacorp/employee/_search?pretty" -H 'Content-Type: application/json' -d ''
{
"aggs" : {
"all_interests" : {
"terms" : { "field" : "interests" },
"aggs" : {
"avg_age" : {
"avg" : { "field" : "age" }
}
}
}
}
}
```
6 文檔
elasticsearch中一個文檔就是一條記錄,一個json串.
-
6.1 索引文檔(存儲文檔)
# 使用自定義的ID PUT /website/blog/123 curl -X PUT "localhost:9200/website/blog/123?pretty" -H 'Content-Type: application/json' -d '' { "title": "My first blog entry", "text": "Just trying this out...", "date": "2014/01/01" } # 自動生成ID POST /website/blog/ curl -X POST "localhost:9200/website/blog/?pretty" -H 'Content-Type: application/json' -d ' ' { "title": "My second blog entry", "text": "Still trying this out...", "date": "2014/01/01" }
-
6.2 獲取文檔
# 取回一個文檔 GET /website/blog/123?pretty # 返回文檔的一部分 GET /website/blog/123?_source=title,text # 只返回_source字段,不需要其他元數據 GET /website/blog/123/_source # 獲取多個文檔 # mget API 要求有一個 docs 數組作爲參數,每個 元素包含需要檢索文檔的元數據, 包括 _index 、 _type 和 _id GET /_mget curl -X GET "localhost:9200/_mget?pretty" -H 'Content-Type: application/json' -d' { "docs" : [ { "_index" : "website", "_type" : "blog", "_id" : 2 }, { "_index" : "website", "_type" : "pageviews", "_id" : 1, "_source": "views" # 檢索某個字段 } ] } ' # 檢索文檔位於一個_index中 GET /website/blog/_mget curl -X GET "localhost:9200/website/blog/_mget?pretty" -H 'Content-Type: application/json' -d' { "docs" : [ { "_id" : 2 }, { "_type" : "pageviews", "_id" : 1 } ] } ' # 如果所有文檔的 _index 和 _type 都是相同的 GET /website/blog/_mget { "ids" : [ "2", "1" ] }
-
6.3 判斷文檔在不在
# 存在的話,頭部信息返回200返回碼 curl -i -X HEAD http://172.22.12.25:9200/megacorp/employee/1
-
6.4 更新文檔
elasticsearch 中文檔是 不可改變 的,不能修改它們. 相反,如果想要更新現有的文檔,需要 重建索引 或者進行替換, 我們可以使用相同的 index API 進行實現
PUT /website/blog/123 curl -X PUT "localhost:9200/website/blog/123?pretty" -H 'Content-Type: application/json' -d'' { "title": "My first blog entry", "text": "I am starting to get the hang of this...", "date": "2014/01/02" }
-
6.5 創建新文檔
如果創建新文檔的請求成功執行,Elasticsearch 會返回元數據和一個 201 Created 的 HTTP 響應碼.
如果具有相同的 _index 、 _type 和 _id 的文檔已經存在,Elasticsearch 將會返回 409 Conflict 響應碼.PUT /website/blog/123/_create curl -X PUT "localhost:9200/website/blog/123/_create" -H 'Content-Type: application/json' -d''
-
6.6 刪除文檔
如果文檔沒有 找到,我們將得到 404 Not Found 的響應碼和類似這樣的響應體.
刪除文檔不會立即將文檔從磁盤中刪除,只是將文檔標記爲已刪除狀態.DELETE /website/blog/123 curl -X DELETE "localhost:9200/website/blog/123?pretty"
-
6.7 處理衝突
使用 index API 更新文檔原理:一次性讀取原始文檔,做修改,然後重新索引整個文檔. elasticsearch只會保留最近一次對文檔的更改狀態.
如果同時有多個用戶更改文檔,他們的更改有可能會丟失.-
兩種併發控制策略:
悲觀併發控制:關係型數據庫使用,假定有可能發生變更衝突,因此阻塞訪問資源防止衝突. 比如 對線程加鎖.
樂觀併發控制:elasticsearch使用,假定不會發生衝突,並且不會阻塞正在嘗試的操作. 但是,如果源數據在讀寫當中被修改,更新將會失敗. 應用程序接下來決定如何解決衝突,例如 重試更新、使用新的數據、將相關情況報告給用戶. -
樂觀併發控制
elasticsearch使用文檔的 _version 字段確保變更以正確順序執行. 如果舊版本在新版本後到達,直接被忽略.
所有文檔的更新或刪除 API,都可以接受 version 參數,這允許你在代碼中使用樂觀的併發控制.創建一個新的博客文章:
PUT /website/blog/1/_create curl -X PUT "localhost:9200/website/blog/1/_create?pretty" -H 'Content-Type: application/json' -d' { "title": "My first blog entry", "text": "Just trying this out..." } '
檢索文檔:
# 響應體包含相同的 _version 版本號 1 curl -X GET "localhost:9200/website/blog/1?pretty" GET /website/blog/1 { "_index" : "website", "_type" : "blog", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "title": "My first blog entry", "text": "Just trying this out..." } }
重建文檔的索引來保存修改: 此時_version=2.
如果我們重新運行相同的索引請求,仍然指定 version=1 , Elasticsearch 返回 409 Conflict HTTP 響應碼(因爲現在的版本號爲2).PUT /website/blog/1?version=1 curl -X PUT "localhost:9200/website/blog/1?version=1&pretty" -H 'Content-Type: application/json' -d' { "title": "My first blog entry", "text": "Starting to get the hang of this..." } '
-
-
6.8 重用版本號
elasticsearch 不是檢查當前 _version 和請求中指定的版本號是否相同, 而是檢查當前 _version 是否 小於 指定的版本號. 如果請求成功,外部的版本號作爲文檔的新 _version 進行存儲. ``` PUT /website/blog/2?version=5&version_type=external PUT /website/blog/2?version=10&version_type=external # 正確響應 PUT /website/blog/2?version=10&version_type=external # 報錯409,因爲當前版本號等於指定的_version ```
-
6.9 批量操作(bulk)
bulk API 允許在單個步驟中進行多次 create 、 index 、 update 或 delete 請求.
- 示例
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} { "create": { "_index": "website", "_type": "blog", "_id": "123" }} POST /_bulk # 每個子請求都是獨立執行,因此某個子請求的失敗不會對其他子請求的成功與否造成影響 { "delete": { "_index": "website", "_type": "blog", "_id": "123" }} { "create": { "_index": "website", "_type": "blog", "_id": "123" }} { "title": "My first blog post" } { "index": { "_index": "website", "_type": "blog" }} { "title": "My second blog post" } { "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} } { "doc" : {"title" : "My updated blog post"} } POST /website/log/_bulk # 相同索引請求 { "index": {}} { "event": "User logged in" } { "index": { "_type": "blog" }} { "title": "Overriding the default type" }
- 示例