https://www.cnblogs.com/crystaltu/articles/6992935.html
一、索引管理
- 創(chuàng)建索引
PUT
http://127.0.0.1:9200/blog
{
"settings" : {
"index" : {
"number_of_shards" : 3, //分片數(shù),創(chuàng)建后不可修改
"number_of_replicas" : 1 //副本數(shù)
}
}
}
返回
{
"acknowledged": true,//索引創(chuàng)建成功
"shards_acknowledged": true,//所需數(shù)量的副本+分片創(chuàng)建成功
"index": "blog"
}
- 索引別名
PUT twitter
{
"aliases" : {
"alias_1" : {},
"alias_2" : {
"filter" : {
"term" : {"user" : "kimchy" }
},
"routing" : "kimchy"
}
}
}
- 更新副本
Elasticsearch 支持修改一個(gè)己存在索引的副本數(shù)
PUT blog/_settings
{
”number of replicas”: 2
}
- 讀寫權(quán)限
blocks.read_only:true 設(shè)置當(dāng)前索引只允許讀不允許寫或者更新。
blocks. read:true 禁止對(duì)當(dāng)前索引進(jìn)行讀操作。
blocks.write:true 禁止對(duì)當(dāng)前索引進(jìn)行寫操作
PUT blog/_settings
{
"blocks. write":true
}
- 查看索引
GET blog/_settings
{
"blogs": {
"settings": {
"index": {
"creation_date": "1541150638499",
"number_of_shards": "2",
"number_of_replicas": "1",
"uuid": "D7KEzlRFQdOapGY64iXxOw",
"version": {
"created": "6040299"
},
"provided_name": "blogs"
}
}
}
}
- 刪除索引
DELETE http://127.0.0.1:9200/blogs
{
"acknowledged": true
}
- 索引的打開和關(guān)閉
Elasticsearch中的索引可以進(jìn)行打開和關(guān)閉操作, 一個(gè)關(guān)閉了的索引幾乎不占用系統(tǒng)資源。
POST /blog/_close
POST /blog/_open
- 復(fù)制索引
_reindexAPI可以把文檔從一個(gè)索引(源索引)復(fù)制到另一個(gè)索引(目標(biāo)索引),目標(biāo)索引不會(huì)復(fù)制源索引中的配置信息,reindex操作之前需要設(shè)置目標(biāo)索引的分片數(shù)、副本數(shù)等信息。(也可以使用type和query來做限制,只復(fù)制原索引的一部分)
POST reindex
{
"source": {
"index": "blog",
"type":"article",
"query":{
"term":{"title":"git"}
}
},
"dest": {
"index": "blog news"
}
}
- 收縮索引
使用 shrink index AP 提供的縮小索引分片數(shù)機(jī)制,把一個(gè)索引變成一個(gè)更少分片的索引,收縮后的分片數(shù)必須是原始分片數(shù)的因子,比如有8個(gè)分片的索引可以收縮為4、2、1,有15個(gè)分片的索引可以收縮為5、3、l,如果分片數(shù)為素?cái)?shù)(7、ll等),那么只能收縮為1個(gè)分片。
在收縮索引前,索引必須標(biāo)記為已讀。
步驟:
先把所有主分片都轉(zhuǎn)移到一臺(tái)主機(jī)上;
在這臺(tái)主機(jī)上創(chuàng)建一個(gè)新索引,分片數(shù)較小,其他設(shè)置和原索引一致;
把原索引的所有分片,復(fù)制(或硬鏈接)到新索引的目錄下;
對(duì)新索引進(jìn)行打開操作恢復(fù)分片數(shù)據(jù);
(可選)重新把新索引的分片均衡到其他節(jié)點(diǎn)上。
PUT /my_source_index/_settings
{
"settings": {
<!-- 指定進(jìn)行收縮的節(jié)點(diǎn)的名稱 -->
"index.routing.allocation.require._name": "shrink_node_name",
<!-- 阻止寫,只讀 -->
"index.blocks.write": true
}
}
進(jìn)行收縮:
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 1,
"index.codec": "best_compression"
}
}
- 拆分索引
當(dāng)索引的分片容量過大時(shí),可以通過拆分操作將索引拆分為一個(gè)倍數(shù)分片數(shù)的新索引。能拆分為幾倍由創(chuàng)建索引時(shí)指定的index.number_of_routing_shards 路由分片數(shù)決定。這個(gè)路由分片數(shù)決定了根據(jù)一致性hash路由文檔到分片的散列空間。
如index.number_of_routing_shards = 30 ,指定的分片數(shù)是5,則可按如下倍數(shù)方式進(jìn)行拆分:
5 → 10 → 30 (split by 2, then by 3)
5 → 15 → 30 (split by 3, then by 2)
5 → 30 (split by 6)
注:只有在創(chuàng)建時(shí)指定了index.number_of_routing_shards 的索引才可以進(jìn)行拆分,ES7開始將不再有這個(gè)限制。
PUT my_source_index
{
"settings": {
"index.number_of_shards" : 1,
<!-- 創(chuàng)建時(shí)需要指定路由分片數(shù) -->
"index.number_of_routing_shards" : 2
}
}
設(shè)置索引只讀
PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
}
}
做拆分
POST my_source_index/_split/my_target_index
{
"settings": {
<!--新索引的分片數(shù)需符合拆分規(guī)則-->
"index.number_of_shards": 2
}
}
監(jiān)控拆分過程:
GET _cat/recovery?v
GET _cluster/health
二、文檔管理
- 新建文檔
指定文檔id,新增或者修改
PUT blogs/article/1
{
"id":1,
"title":"Git簡(jiǎn)介",
"posttime":"2017 - 05-01",
"content ":"Git 是一款免費(fèi)、開源的分布式版本控制系統(tǒng)"
}
返回
{
"_index": "blogs",
"_type": "article",
"_id": "1", //文檔id
"_version": 1,
"result": "created",
"_shards": {
"total": 2, //所在分片有2個(gè)副本
"successful": 1, //1個(gè)副本上成功寫入
"failed": 0 //失敗副本數(shù)
},
"_seq_no": 0,
"_primary_term": 1
}
不指定文檔id,新增并返回id
POST blogs/article
{
"id":1,
"title":"Git簡(jiǎn)介",
"posttime":"2017 - 05-01",
"content ":"Git 是一款免費(fèi)、開源的分布式版本控制系統(tǒng)"
}
返回
{
"_index": "blogs",
"_type": "article",
"_id": "yT9942YBJT1L8mzoKCO2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
- 獲取文檔
GET http://127.0.0.1:9200/blogs/article/1
返回
{
"_index": "blogs",
"_type": "article",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"id": 1,
"title": "Git簡(jiǎn)介",
"posttime": "2017 - 05-01",
"content ": "Git 是一款免費(fèi)、開源的分布式版本控制系統(tǒng)"
}
}
- 批量獲取
POST http://127.0.0.1:9200/blogs/_mget
{
"ids":["1","2"]
}
返回
{
"docs": [
{
"_index": "blogs",
"_type": "article",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"id": 1,
"title": "Git簡(jiǎn)介",
"posttime": "2017 - 05-01",
"content ": "Git 是一款免費(fèi)、開源的分布式版本控制系統(tǒng)"
}
},
{
"_index": "blogs",
"_type": "article",
"_id": "2",
"_version": 1,
"found": true,
"_source": {
"id": 1,
"title": "svn簡(jiǎn)介",
"posttime": "2017 - 05-01",
"content ": "svn 是一款免費(fèi)、開源的分布式版本控制系統(tǒng)"
}
}
]
}
- 更新文檔
PUT http://127.0.0.1:9200/test/type1/1
{
"counter":1,
"tags":["red"]
}
返回
{
"_index": "test",
"_type": "type1",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
- 更新請(qǐng)求
POST http://127.0.0.1:9200/test/type1/1/_update
{
"script":{
"inline":"ctx._source.counter += params.count",
"lang":"painless",
"params":{
"count":4
}
}
"upsert" : { "counter" : 1 }
}
返回
{
"_index": "test",
"_type": "type1",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
命令中inline是執(zhí)行的腳本,ctx是腳本語言中的一個(gè)執(zhí)行對(duì)象,painless是Elasticsearch內(nèi)置的一種腳本語言,params是參數(shù)集合。上述命令的自然語言描述如下:使用painless腳本更新文檔,通過ctx獲?。遱ource再修改counter字段,counter字段等于原值加上count參數(shù)的值。ctx對(duì)象除了可以訪問_source之外,還可以訪問_index_type、_id、_version、_routing、_parent等字段。
upsert字段:如果不存在文檔,則新增文檔,并新增一個(gè)字段counter。
增加文檔中字段
POST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.name_of_new_field = \"value_of_new_field\""
}'
刪除文檔
POST 'localhost:9200/test/type1/1/_update' -d '{
"script" : "ctx._source.remove(\"name_of_field\")"
}'
刪除指定文檔
{
"script":{
"inline":"if(ctx._source.tags.contains(params.tag)){ctx.op=\"delete\"}else{ctx.op=\"none\"}",
"lang":"painless",
"params":{"tag":"red"}
}
- 查詢并更新
POST blog/_update_by_query
{
"script": {
"inline": "ctx._source.category=params.category",
"lang": "painless",
"params": {
"category": "git"
}
},
"query": {
"term": {
"title": "git"
}
}
}
- 刪除文檔
DELETE http://127.0.0.1:9200/blog/article/1
返回
{
"_index": "blog",
"_type": "article",
"_id": "1",
"_version": 1,
"result": "not_found",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 5
}
刪除時(shí)也可以指定路由,DELETE http://127.0.0.1:9200/blog/article/1?routing=user123
- 查詢并刪除
POST http://127.0.0.1:9200/blog/_delete_by_query
{
"query":{
"term":{
"titie":"hibernate"
}
}
}
- 批量操作
Bulk API 允許使用單一請(qǐng)求來實(shí)現(xiàn)多個(gè)文檔的 create 、 index、update 或 delete 。
curl -XPOST 'localhost:9200/customer/external/_bulk?pretty' -d '
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
action and meta data 行指定了將要在哪個(gè)文檔中執(zhí)行什么操作,其中 action 必須是 index 、create 、 update 或者 delete, metadata 需要指明需要被操作文檔的_index 、_type 以及_id 。
Elasticsearch 響應(yīng)包含一個(gè) items 數(shù)組,它羅列了每一個(gè)請(qǐng)求的結(jié)果,結(jié)果的順序與請(qǐng)求的順序相同:
{
"took": 30,
"errors": false,
"items": [
{
"index": {
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201,
"_seq_no" : 0,
"_primary_term": 1
}
},
{
"delete": {
"_index": "test",
"_type": "_doc",
"_id": "2",
"_version": 1,
"result": "not_found",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 404,
"_seq_no" : 1,
"_primary_term" : 2
}
},
{
"create": {
"_index": "test",
"_type": "_doc",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201,
"_seq_no" : 2,
"_primary_term" : 3
}
},
{
"update": {
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 200,
"_seq_no" : 3,
"_primary_term" : 4
}
}
]
}
使用 Bulle 操作需要注意一次提交請(qǐng)求文件的大小,整個(gè)批量請(qǐng)求需要被加載到接受請(qǐng)求節(jié)點(diǎn)的內(nèi)存里, 所以請(qǐng)求越大 , 給其他請(qǐng)求可用的內(nèi)存就越小。有一個(gè)最佳的 Bulk 請(qǐng)求大小,超過這個(gè)大小,性能不再提升而且可能降低 。 一般一個(gè)好的批次最好保持在 5~15MB 之間 。
三、版本控制
當(dāng)我們使用 Elasticsearch 的 API 進(jìn)行文檔更新的時(shí)候整個(gè)過程如下:首先讀取源文檔,對(duì)原文檔進(jìn)行更新操作,更新操作執(zhí)行完成以后再重新索引整個(gè)文檔 。 不論執(zhí)行多少次更新,最后保存在 Elasticsearch 中的是最后一次更新后的文檔。但是如果有兩個(gè)線程同時(shí)修改一個(gè)文檔,這時(shí)候就會(huì)發(fā)生沖突。

Elasticsearch 使用的就是樂觀鎖機(jī)制(假定不會(huì)發(fā)生并發(fā)訪問沖突,對(duì)數(shù)據(jù)資源不會(huì)鎖定,只有在數(shù)據(jù)提交操作時(shí)檢查是否違反數(shù)據(jù)完整性。樂觀鎖適用于讀操作比較多的應(yīng)用類型,可省去鎖開銷,可以提高吞吐量。)
Elasticsearch 是一個(gè)分布式系統(tǒng),當(dāng)文檔被創(chuàng)建、更新、刪除,新版本的文檔必須要復(fù)制到集群中的其他節(jié)點(diǎn)。 Elasticsearch 也是異步并發(fā)的,這意味著復(fù)制請(qǐng)求會(huì)被并行發(fā)送,也意味著請(qǐng)求不是按順序到達(dá)的, Elasticsearch 需要一種方式確保舊版本的文檔不會(huì)覆蓋較新版本的文檔。
我們?cè)谇懊鎸?duì)文檔進(jìn)行索引時(shí)提到,文檔每被修改→次,文檔版本號(hào)會(huì)自增一次。
Elasticsearch 使用_version 字段確保所有的更新都有序進(jìn)行。 如果一個(gè)低版本的文檔在一個(gè)高版本的文檔之后到達(dá),那么舊版本的文檔會(huì)被忽略。 Elasticsearch 的文檔版本控制機(jī)制主要有內(nèi)部版本控制和外部版本控制,內(nèi)部版本控制機(jī)制要求每次操作請(qǐng)求,只有當(dāng)版本號(hào)相等時(shí)才能操作成功, 外部版本控制要求外部文檔版本比內(nèi)部文檔版本高時(shí)才能更新成功。下面通過具體實(shí)例演示一遍 。
創(chuàng)建文檔
PUT /website/blog/1/_create
{
"title": "My first blog entry",
"text": "Just trying this out..."
}
查詢結(jié)果,_version為1
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=1 更新文檔
PUT /website/blog/1?version=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
返回version自增為2
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 2
"created": false
}
如果再以version=1更新,則報(bào)異常version_conflict_engine_exception
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, current [2], provided [1]",
"index": "website",
"shard": "3"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, current [2], provided [1]",
"index": "website",
"shard": "3"
},
"status": 409
}
外部版本號(hào)
PUT /website/blog/2?version=5&version_type=external
{
"title": "My first external blog entry",
"text": "Starting to get the hang of this..."
}
返回
{
"_index": "website",
"_type": "blog",
"_id": "2",
"_version": 5,
"created": true
}
四、路由機(jī)制
當(dāng)索引 一個(gè)文檔時(shí)文檔會(huì)被存儲(chǔ)到 master 節(jié)點(diǎn)上的一個(gè)主分片上。那么 Elasticsearch 是如何知道文檔屬于哪個(gè)分片的呢?再有當(dāng)你創(chuàng)建一個(gè)新文檔,Elasticsearch 是如何知道應(yīng)該存儲(chǔ)在分片 1還是分片 2 上?要想回答這些問題,就需要了解Elasticsearch 的路由機(jī)制。 Elasticsearch 的路由機(jī)制即是通過哈希算法,將具有相同哈希值的文檔放置到同一個(gè)主分片中,分片位置計(jì)算方法:
shard= hash(routing)% number_of_primary_shards
routing 值可以是一個(gè)任意字符串, Elasticsearch 默認(rèn)將文檔的 id 值作為 routing 值,通過哈希函數(shù)根據(jù) routing 字符串生成一個(gè)數(shù)字,然后除以主切片的數(shù)量得到一個(gè)余數(shù)( remainder )。這個(gè)數(shù)字就是特定文檔所在的分片。這種算法基本上會(huì)保持所有數(shù)據(jù)在所有分片上的一個(gè)平均分布,而不會(huì)造成數(shù)據(jù)分配不均衡的情況。
也可以自定義 routing 值。默認(rèn)的路由模式可以保證數(shù)據(jù)平均分布,文檔分配算法對(duì)我們來說是透明的,很多時(shí)候性能也不是問題。自定義 routing 值在深入理解數(shù)據(jù)特征之后, 能夠帶來很多使用上的方便和性能上的提升。
自定義routing 值的好處:
默認(rèn)情況下, Elasticsearch 使用文檔的 id 將文檔平均分布于所有的分片上,這導(dǎo)致了Elasticsearch 不能確定文檔的位置,所以它必須將這個(gè)請(qǐng)求廣播到所有的分片上去執(zhí)行。主分片的數(shù)量在索引創(chuàng)建的時(shí)候是固定的,并且永遠(yuǎn)不能改變。因?yàn)槿绻制臄?shù)量改變了,所有先前的路由值就會(huì)變成非法,文檔相當(dāng)于丟失了。使用自定義的路由模式,可以便查詢更具目的性。你不必盲目地去廣播查詢請(qǐng)求,而是要告訴Elasticsearch 你的數(shù)據(jù)在哪個(gè)分片上。
PUT /website/blog/l?routing=user123
{
"title":"My first blog entry",
"text":"Just trying this out ..."
}
GET /myblog/search?routing=user123
如果想要查詢 user123發(fā)布了哪些博客,可 以通過 routing值進(jìn)行過濾,這樣可以避免 Elasticsearch 向所有分片都發(fā)送查詢請(qǐng)求,大大減少系統(tǒng)的資源。
需要注意的是,可以為文檔指定多個(gè)路由值,路由值之間使用逗號(hào)隔開。
使用自定義 routing 值也會(huì)造成一些潛在的問題,比如 user123 本身的文檔就非常多,有數(shù)十萬個(gè),而其他大多數(shù)的用戶只有幾個(gè)文檔,這樣的話就會(huì)導(dǎo)致 user123 所在的分片較大,出現(xiàn)數(shù)據(jù)偏移的情況,特別是多個(gè)這樣的用戶處于同一分片的時(shí)候現(xiàn)象會(huì)更明顯。具體的使用還是要結(jié)合實(shí)際的應(yīng)用場(chǎng)景來選擇。
五、映射詳解
1、映射介紹
映射也就是 Mapping,用來定義一個(gè)文檔以及其所包含的字段如何被存儲(chǔ)和索引,可以在映射中事先定義字段的數(shù)據(jù)類型、分詞器等屬性。類似關(guān)系數(shù)據(jù)庫定義表結(jié)構(gòu)和字段類型。
映射可分為動(dòng)態(tài)映射和靜態(tài)映射。在關(guān)系型數(shù)據(jù)庫中寫入數(shù)據(jù)之前首先要建表,在建表語句中聲明宇段的屬性,在 Elasticsearch 中則不必如此, Elasticsearch 最重要的功能之一就是讓你盡可能快地開始探索數(shù)據(jù),文檔寫入 Elasticsearch 中,它會(huì)根據(jù)字段的類型自動(dòng)識(shí)別,這種機(jī)制稱為動(dòng)態(tài)映射,而靜態(tài)映射則是寫入數(shù)據(jù)之前對(duì)宇段的屬性進(jìn)行手工設(shè)置。
PUT http://127.0.0.1:9200/books
http://127.0.0.1:9200/books/_mapping
返回
{
"books": {
"mappings": {}
}
}
添加文檔之后
PUT books/it/1
{
"id":1,
"publish_date":"2017-06-01",
"name":"master Elasticsearch"
}
http://127.0.0.1:9200/books/_mapping
返回
{
"books": {
"mappings": {
"it": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"publish_date": {
"type": "date"
}
}
}
}
}
}
說明es自動(dòng)識(shí)別了文檔中字段的類型。
使用動(dòng)態(tài) Mapping 要結(jié)合實(shí)際業(yè)務(wù)需求來綜合考慮 ,如果將 Elasticsearch 當(dāng)作主要的數(shù)據(jù)存儲(chǔ)使用,井且希望出現(xiàn)未知宇段時(shí)拋出異常來提醒你注意這一問題,那么開啟動(dòng)態(tài) Mapping并不適用。在 Mapping 中可以通過 dynamic 設(shè)置來控制是否自動(dòng)新增宇段。
PUT http://127.0.0.1:9200/books
{
"mappings": {
"it": {
"dynamic":"strict", //dynamic有true默認(rèn)自動(dòng)添加字段,false不添加,strict嚴(yán)格模式 發(fā)現(xiàn)新字段拋異常
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"publish_date": {
"type": "date"
}
}
}
}
}
如果
PUT books/it/1
{
"id":1,
"publish_date":"2017-06-01",
"name":"master Elasticsearch",
"author":"psk"
}
則會(huì)拋出strict_dynamic_mapping_exception 異常
2、元字段
元字段是映射中描述文檔本身的字段,從大的分類上來看,主要有文檔屬性的元字段、源文檔的元字段、索引的元字段、路由的元字段和自定義元字段。

GET _index1,_index2/_search
{
"query": {
"terms": {
"_index": [
"_indexl",
"_index2"
]
}
},
"aggs": {
"indices": {
"terms": {
"field": "_index",
"size": 10
}
}
},
"sort": [
{
"_index": {
"order": "asc"
}
}
]
}