您好,登錄后才能下訂單哦!
[TOC]
PUT my_blog/article/1
{
"id":1,
"title":"elasticsearch",
"posttime":"2017-05-01",
"content":"elasticsearch is helpfull!"
}
返回:
{
"_index": "my_blog",
"_type": "article",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
版本號會隨著文檔的更新自動遞增。
不指定id,es會自動生成,但是這時只能使用post:
POST my_blog/article
{
"id":2,
"title":"spark",
"posttime":"2017-05-01",
"content":"spark is helpfull!"
}
返回:
{
"_index": "my_blog",
"_type": "article",
"_id": "AWagTCv8O1qbT1zqbREV",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
獲取存在的文檔:
GET my_blog/article/1
返回:
{
"_index": "my_blog",
"_type": "article",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"id": 1,
"title": "elasticsearch",
"posttime": "2017-05-01",
"content": "elasticsearch is helpfull!"
}
}
獲取不存在的文檔:
GET my_blog/article/2
返回:
{
"_index": "my_blog",
"_type": "article",
"_id": "2",
"found": false
}
使用HEAD可以測試文檔是否存在:
HEAD my_blog/article/1
200 - OK
HEAD my_blog/article/2
404 - Not Found
不同index不同type:
GET _mget
{
"docs":[
{
"_index":"my_blog",
"_type":"article",
"_id":1
},
{
"_index":"twitter",
"_type":"tweet",
"_id":2
}
]
}
同一index下不同type:
GET my_blog/_mget
{
"docs":[
{
"_type":"article",
"_id":1
},
{
"_type":"essay",
"_id":2
}
]
}
同一index同一type:
GET my_blog/article/_mget
{
"docs":[
{"_id":1},
{"_id":2}
]
}
或:
GET my_blog/article/_mget
{
"ids":[1,2]
}
es更新文檔的原理為:先找到這個文檔,刪除舊的文檔內容執行更新,更新完后再索引最新的文檔。
先添加下面一份文檔:
PUT test/type1/1
{
"counter":1,
"tags":["red"]
}
給counter的值增加4:
POST test/type1/1/_update
{
"script": {
"inline": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count":4
}
}
}
Note1:命令中inline是執行的腳本,ctx是腳本語言中的一個執行對象,painless是es內置的一種腳本語言,params是參數集合;
Note2:ctx對象除了可以訪問
_source
之外,還可以訪問_index
、_type
、_id
、_version
、_routing
、_parent
等字段;
對tags字段增加一個值:
POST test/type1/1/_update
{
"script":{
"inline":"ctx._source.tags.add(params.tag)",
"lang":"painless",
"params":{
"tag":"blue"
}
}
}
給test/type1/1添加一個字段name:
POST test/type1/1/_update
{
"script": {
"inline": "ctx._source.name=\"test\""
}
}
上面的命令也可以簡寫為:
{"script":""ctx._source.name=\"test\""}
移除name字段:
POST test/type1/1/_update
{
"script": {
"inline": "ctx._source.remove(\"name\")"
}
}
如果文檔不存在,upsert會新建一個文檔,文檔存在,則正常執行script腳本。如下:
POST test/type1/2/_update
{
"script": {
"inline": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count":4
}
},
"upsert": {
"counter":1,
"tag":["pink"]
}
}
如果test/type1/2存在,則更新count,如果不存在,則新建一個包含字段counter和tag的文檔。
返回:
{
"_index": "test",
"_type": "type1",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
也可以使用doc的方式來更新字段內容或者添加新的字段:
POST myblog/article/1/_update
{
"doc": {
"title":"test new title"
}
}
POST myblog/article/1/_update
{
"doc": {
"new field":"this is a new field"
}
}
POST my_blog/_update_by_query
{
"script":{
"inline": "ctx._source.content = params.content",
"lang": "painless",
"params": {
"content":"spark is popular"
}
},
"query":{
"term": {
"title": {
"value": "spark"
}
}
}
}
返回:
{
"took": 33,
"timed_out": false,
"total": 1,
"updated": 1,
"deleted": 0,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1,
"throttled_until_millis": 0,
"failures": []
}
DELETE my_blog/article/2
如果在索引文檔時指定了路由,刪除時也可以增加路由參數:
DELETE my_blog/article/2?routing=user123
Note1:如果刪除時路由值不正確,刪除會失敗;
Note2:當映射的_routing被設定為required且沒有指定的路由值時,執行刪除操作將拋出路由缺失異常并拒絕該請求;
POST my_blog/_delete_by_query
{
"query":{
"term": {
"title": {
"value": "mybatis"
}
}
}
}
刪除一個type下的所有文檔:
POST my_blog/article/_delete_by_query
{
"query":{
"match_all":{}
}
}
使用如下命令:
curl -XPOST 'localhost:9200/indexname/_bulk?prettry' --data-binary @accounts.json
accounts.json文件應該滿足下面的格式:
action_and_meta_data行
data行
Note1:action_and_meta_data行中,action必須是index、create、update或者delete,metadata需要指明需要被操作文檔的
_index
、_type
以及_id
;Note2:data行就是添加的數據,添加文檔時就需要data行;
Note3:每一行的結尾處都必須有換行符"\n",最后一行也要有,換行符可以有效地分隔每行;
{"index": {"_index": "my_blog"}, "_type": "article", "_id": "1"}
{"title": "blog title"}
或
{"create": {"_index": "my_blog", "_type": "article", "_id": "1"}}
{"title": "blog title"}
不寫id也是可以的。
{"delete": {"_index": "website", "_type": "blog", "_id": "123"}}
下面內容包含索引文檔請求、更新文檔請求和刪除文檔請求:
{"delete": {"_index": "website", "_type": "blog", "_id": "123"}}
{"create": {"_index": "website", "_type": "blog", "_id": "123"}}
{"title": "blog title"}
{"index": {"_index": "website", "_type": "blog"}}
{"title": "blog title"}
{"update": {"_index": "website", "_type": "blog", "_id": "123"}}
{"doc": {"title": "blog title"}}
初次接觸,8.2可以忽略,了解一下8.3的命令操作即可。
es進行文檔更新時,首先讀取源文檔,對原文檔進行更新操作,更新操作執行完成以后再重新索引整個文檔。
很有可能多個用戶同時對同一份文檔數據進行修改更新操作,這時就需要進行事務性控制,或者說需要進行并發控制。
如果有線程對數據進行修改就對數據進行鎖定,其他線程想要訪問需要等待當前鎖定釋放,這樣可確保同一時刻最多只有一個線程訪問數據。傳統的關系型數據庫就用到了很多這種鎖機制,比如行鎖、表鎖、讀鎖、寫鎖等。
對數據資源不會鎖定,只有在數據提交操作時檢查是否違反數據完整性。Elasticsearch使用的就是樂觀鎖機制,樂觀鎖適用于讀操作比寫操作比較多的應用類型,可省去鎖開銷,提高吞吐量。
既然es使用的是樂觀鎖,那么如何保證舊的數據不會覆蓋新的數據呢?在es中使用_version來進行版本的控制,文檔每被更新一次,其就會加1.
es的文檔版本控制機制主要有內部版本控制和外部版本控制:
其實不管是請求獲取數據還是請求更新數據,都是可以攜帶版本號的,不管情況多復雜,只需要記住下面兩點即可:
也可以從是否攜帶版本號的角度去思考這個問題:
至于es為什么這樣設計?其實內部版本號是es提供的,但實際上你可能也有自己業務或程序上的需求,就是說你的應用系統本身就維護了一個版本號,或者說你自己想通過某種機制去維護一個版本號,那么就可以使用外部版本號。
GET website/blog/1?version=1
PUT website/blog/1?version=5&version_type=external
當索引有多個分片時,索引一個文檔,es是如何確定將文檔保存到哪一個文檔上的呢?假設環境如下:
Master Node:
shard0(primary)
shard1
shard2(primary)
Common Node:
shard0
shard1(primary)
shard2
es的路由機制通過哈希算法,將具有相同哈希值的文檔放置到同一個主分片中,方法如下:
shard = hash(routing) % number_of_primary_shards
假如我們添加一份文檔,沒有指定id,es給我們生成的id是AWagTCv8O1qbT1zqbREV
,套用上面的公式,shard就應該為:
shard = hash("AWagTCv8O1qbT1zqbREV") % 3
當然哈希函數的實現不一定,我們可以在python中調用一下其提供的hash()函數來演示一下上面的計算:
>>> shard = hash("AWagTCv8O1qbT1zqbREV") % 3
>>> shard
2
顯然,該文檔會被存儲到分片2也就是第3個分片上。
通過上面的介紹可以知道,默認的路由模式可以保證數據平均分布,不過也可以自定義routing值,從而指定文檔的存儲位置。
假如存在一個有50個分片的索引,在集群上執行一次查詢的過程如下:
可以自定義路由值來避免這種廣播,下面舉一個案例進行說明。
正常我們這樣來添加一份文檔:
PUT website/article/1
{
"title":"My first blog entry",
"text":"Just trying this out...",
"user":"user123"
}
查詢時,希望查詢user123的所有文章:
GET website/article/_search
{
"query":{
"term":{"user":"user123"}
}
}
顯然這樣查詢,會按照上面的流程去走,也就是請求會被發送到所有的分片上,這時希望優化一下。
將user作為routing來添加文檔:
PUT website/article/1?routing=user123
{
"title":"My first blog entry",
"text":"Just trying this out...",
"user":"user123"
}
指定routing值后,后面user123發表的文章(文檔)都會被存儲到同一個分片上,這里假設是分片1,這樣一來,我們再查詢user123發表的文章時,只需要在search時指定routing值,那么就不會被廣播請求的情況了,請求直接到達分片1,查詢如下:
GET website/article/_search?routing=user123
Note1:這樣也會帶來問題,比如user123發表了數十萬篇文章,但是其它用戶只有很少的文章,顯然數據的分配就不均衡了;
Note2:也可以為文檔指定多個路由值,路由值之間使用逗號分隔(這樣一來,文檔就有可能會被分配到多個分片上,至于滿足其條件的這幾個分片,es是如何選擇的,通過什么算法,可以自行研究一下);
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。