Elasticsearch内部提供了一个rest接口用于查看集群内部的健康情况:html
Elasticsearch内部提供了一个rest接口用于查看集群内部的健康情况:html
curl -XGET http://localhost:9200/_cluster/health
|
response结果:java
{
"cluster_name": "format-es",
"status": "green",
...
}
|
这里的status有3种状态,分别是green(全部主分片和复制分片均可用),yellow(全部主分片可用,但不是全部复制分片均可用)和red(不是全部主分片可用)。node
Elasticsearch中的索引(index)是由分片(shard)构成的。git
好比咱们集群中有个索引users,该索引由3个分片组成,那么这个users索引中的文档数据将分布在这3个分片中。github
users索引中的文档是根据下面这个规则肯定该文档属于哪一个分片:spring
shard = hash(routing) % number_of_primary_shards
// routing值默认是文档的_id,number_of_primary_shards是索引的主分片个数
|
这个routing默认是文档的_id,能够自定义(文章后面部分会举例说明)。api
这3个分片能够进行复制,复制是为了实现容错性,好比复制1份,那么一共就须要6个分片(3个主分片+3个主分片复制出来的复制分片)。springboot
users索引的建立命令(主分片3个,复制1份):并发
curl -XPUT http://localhost:9200/users
-d '
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
'
|
建立完users索引以后,es集群(单节点)分片状况以下:curl
因为users索引有3个分片,es内部会建立出3个分片,分别是P0、P1和P2(大写P指的是primary),且这3个分片都是主分片。users索引须要对分片进行复制1份,因此这3个主分片都须要复制1份,分别对应R0、R1和R2这3个复制分片(大写R指的是replica)。这个时候咱们的集群只有1个节点node-1,因此复制分片并无起做用(若是复制分片和主分片在同一个节点了,那么这个复制分片的意义就不存在了。复制分片的意义在于容错性,当一个节点挂了,另外一个节点上的分片能够代替挂掉节点上的分片)。
查看健康状态:
curl -XGET http://localhost:9200/_cluster/health
|
response结果:
{
"cluster_name": "format-es",
"status": "yellow",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 3,
"active_shards": 3,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 3,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 50
}
|
这里能够看到,集群的状态变成了yellow。这是由于users索引中的分片须要复制1份,可是没有足够的机器用来存储复制出来的复制分片,还有其它的一些字段好比unassigned_shards字段为3,对应R0、R1和R2这3个未分配的复制分片。
在集群中加入节点node-2,查看健康情况(这里使用伪集群。node-1节点对应9200端口的进程,node-2节点对应9201端口的进程):
curl -XGET http://localhost:9200/_cluster/health
|
response结果:
{
"cluster_name": "format-es",
"status": "green",
"timed_out": false,
"number_of_nodes": 2,
"number_of_data_nodes": 2,
"active_primary_shards": 3,
"active_shards": 6,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 100
}
|
主分片和复制分片都可用,status为green。
此时,es集群分片状况以下:
这个时候es集群由2个节点node-1和node-2组成,而且这2个节点上具备主分片和复制分片,具备容错性。
咱们往users索引中插入一条文档:
curl -XPOST http://localhost:9200/users/normal -d '
{
"name" : "Format",
"age" : 111
}
'
|
返回:
{
"_index": "users",
"_type": "normal",
"_id": "AV0hs4LnkXxVJ5DURwXr",
"_version": 1,
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"created": true
}
|
从返回的信息中能够看到,这个文档已经被建立成功,而且2个分片都成功。id由es内部自动建立,值为AV0hs4LnkXxVJ5DURwXr。
读取id为AV0hs4LnkXxVJ5DURwXr的文档:
curl -XGET http://localhost:9200/users/normal/AV0hs4LnkXxVJ5DURwXr
# 结果
{
"_index": "users",
"_type": "normal",
"_id": "AV0hs4LnkXxVJ5DURwXr",
"_version": 1,
"found": true,
"_source": {
"name": "Format",
"age": 111
}
}
|
这个时候若是节点node-1挂了,读取数据:
curl -XGET http://localhost:9201/users/normal/AV0hs4LnkXxVJ5DURwXr
# 结果
{
"_index": "users",
"_type": "normal",
"_id": "AV0hs4LnkXxVJ5DURwXr",
"_version": 1,
"found": true,
"_source": {
"name": "Format",
"age": 111
}
}
|
在节点node-1已经挂了的状况下仍是读取到了以前插入的文档。这是由于咱们users索引会复制2份,node-1节点虽然已经挂了,可是node-2节点上这个文档的数据还在,因此文档会被读取到。
在node-1节点挂掉的状况下,再次插入一条文档:
curl -XPOST http://localhost:9201/users/normal -d '
{
"name" : "Jim",
"age" : 66
}
'
|
返回:
{
"_index": "users",
"_type": "normal",
"_id": "AV0qMto5dJHprgu99sSN",
"_version": 1,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
|
这里看到返回的数据中,这个文档对应的分片只有1个成功插入,由于另1个分片对应的节点已经挂了。
而后读取这个新插入的文档:
curl -XGET http://localhost:9201/users/normal/AV0qMto5dJHprgu99sSN
# 结果
{
"_index": "users",
"_type": "normal",
"_id": "AV0qMto5dJHprgu99sSN",
"_version": 1,
"found": true,
"_source": {
"name": "Jim",
"age": 66
}
}
|
而后node-1节点恢复(节点恢复以后,es内部会自动从数据全的分片中复制数据到数据少的分片上,保证高可用),而后读取数据:
curl -XGET http://localhost:9200/users/normal/AV0qMto5dJHprgu99sSN
# 结果
{
"_index": "users",
"_type": "normal",
"_id": "AV0qMto5dJHprgu99sSN",
"_version": 1,
"found": true,
"_source": {
"name": "Jim",
"age": 66
}
}
|
ES中文档的新建、删除和修改都是先在主分片上完成的,在主分片上完成这些操做之后,才会进行复制操做。好比有3个节点node-一、node-2和node-3,索引blogs有2个主分片,而且复制2份,集群结构以下:
当进行新建文档的时候过程以下:
当进行检索文档的时候过程以下:
这里es集群会使用轮询的策略对读取不一样节点上的分片中的文档数据,好比针对上图中的查询,下次查询就会读取node-3节点上的R0分片中的文档。
当对文档进行局部更新的时候过程以下:
在分布式集群状况下,ES中的节点可分为4类:
能够经过es内部提供的rest接口查看master节点:
curl -XGET http://localhost:9200/_cat/master?v
id host ip node
9FINsHCpTKqcpFlnnA4Yww 10.1.251.164 10.1.251.164 node-1
|
查看节点信息:
curl -XGET http://localhost:9200/_cat/nodes?v
host ip heap.percent ram.percent load node.role master name
10.1.251.164 10.1.251.164 6 100 5.48 d * node-1
10.1.251.164 10.1.251.164 6 100 5.48 d m node-3
10.1.251.164 10.1.251.164 7 100 5.48 d m node-2
|
或者使用head插件查看节点状况。图中带有五角星的节点是master,这里users索引有3个主分片和3个复制分片(绿色框外部加粗的边框就是主分片,不然就是复制分片):
若是咱们的集群上node-1节点因为硬盘容量不足致使不可用时,head插件状况以下(3个复制节点未被分配,健康情况为黄色):
也可以使用es内部的rest接口查看分片信息:
curl -XGET http://localhost:9200/_cat/shards?v
index shard prirep state docs store ip node
users 1 p STARTED 1 3.3kb 10.1.251.164 node-2
users 1 r UNASSIGNED
users 2 p STARTED 0 159b 10.1.251.164 node-2
users 2 r UNASSIGNED
users 0 p STARTED 2 6.6kb 10.1.251.164 node-3
users 0 r UNASSIGNED
|
routing参数决定如何分片(能够在index、get、delete、update、bulk等方法中使用),咱们覆盖默认的routing为_id的默认策略:
# 执行10次
curl -XPOST http://localhost:9200/users/normal?routing=1
-d '
{
"name" : "Format345",
"age" : 456
}
'
# 执行1次
curl -XPOST http://localhost:9200/users/normal
-d '
{
"name" : "Format345",
"age" : 456
}
'
# 使用routing参数获得文档的结果(多了个_rouring属性)
{
"_index": "users",
"_type": "normal",
"_id": "AV07AubA6HDSJNRJle0i",
"_version": 1,
"_routing": "1",
"found": true,
"_source": {
"name": "Format345",
"age": 456
}
}
# 查询文档分布状况(前面10次分布到了P2分片,后面1次分布到了P1分片)
curl -XGET http://localhost:9200/_cat/shards?v
index shard prirep state docs store ip node
users 1 p STARTED 2 3.3kb 10.1.251.164 node-2
users 1 r UNASSIGNED
users 2 p STARTED 10 159b 10.1.251.164 node-2
users 2 r UNASSIGNED
users 0 p STARTED 2 6.6kb 10.1.251.164 node-3
users 0 r UNASSIGNED
|
官网上有更多关于_cat api和_cluster api相关的文档。
es中文档的操做可使用其内部提供的rest接口,使用过程当中能够指定一些参数修改默认行为。
1.replication:用于设置复制分片的处理过程是同步仍是异步。默认值是sync(主分片须要等待复制分片所有处理完毕),也能够设置成async(主分片不须要等待复制分片的处理过程,可是仍是会转发请求给复制分片,这个转发过程是异步的)。该参数在2.0.0版本后已经被废弃,由于异步转发给复制分片的话,不知道复制分片是否成功与否,并且复制分片在尚未处理完成的状况下因为一直过来的异步请求而致使es过载,不建议使用async
2.consistency:写文档的一致性参数,能够设置成one,quorum和all;分别表示主分片可用便可、过半分片可用[公式:int( (primary + number_of_replicas) / 2 ) + 1]以及所有分片可用。好比有个blogs索引,有3个主分片,而且复制2份,当集群中的1个节点挂了,并使用all的话,将会抛出异常:
curl -XPOST http://localhost:9200/blogs/normal?consistency=all
-d '
{
"name" : "POST-1"
}
'
# 一分钟后抛出异常
{
"error": {
"root_cause": [
{
"type": "unavailable_shards_exception",
"reason": "[blogs][0] Not enough active copies to meet write consistency of [ALL] (have 2, needed 3). Timeout: [1m], request: [index {[blogs][normal][AV1AF1FEl7qPpRBCQMV7], source[{\n \"name\" : \"POST-1\"\n}]}]"
}
],
"type": "unavailable_shards_exception",
"reason": "[blogs][0] Not enough active copies to meet write consistency of [ALL] (have 2, needed 3). Timeout: [1m], request: [index {[blogs][normal][AV1AF1FEl7qPpRBCQMV7], source[{\n \"name\" : \"POST-1\"\n}]}]"
},
"status": 503
}
|
使用默认的quorum策略:
curl -XPOST http://localhost:9200/blogs/normal
-d '
{
"name" : "POST-1"
}
# 因为集群中的节点挂了1个,所分片只有2个success
{
"_index": "blogs",
"_type": "normal",
"_id": "AV1AckLfl7qPpRBCQMV_",
"_version": 1,
"_shards": {
"total": 3,
"successful": 2,
"failed": 0
},
"created": true
}
'
|
consistency参数在5.0.0版本已经被弃用
3.timeout:当分片不足的时候,es等待的时间(等待节点从新启动,分片恢复),默认为1分钟,能够进行修改,改为10秒:
curl -XPOST http://localhost:9200/blogs/normal?consistency=all&timeout=10s
-d '
{
"name" : "POST-1"
}
'
# 10秒后抛出异常
{
"error": {
"root_cause": [
{
"type": "unavailable_shards_exception",
"reason": "[blogs][1] Not enough active copies to meet write consistency of [ALL] (have 2, needed 3). Timeout: [10s], request: [index {[blogs][normal][AV1AdXxsl7qPpRBCQMWB], source[{\n \"name\" : \"POST-1\"\n}]}]"
}
],
"type": "unavailable_shards_exception",
"reason": "[blogs][1] Not enough active copies to meet write consistency of [ALL] (have 2, needed 3). Timeout: [10s], request: [index {[blogs][normal][AV1AdXxsl7qPpRBCQMWB], source[{\n \"name\" : \"POST-1\"\n}]}]"
},
"status": 503
}
|
4.version
es中每一个文档都有对应的版本信息,可使用version版本参数用来实现并发状况下的乐观锁机制:
# 新建一个文档
curl -XPUT http://localhost:9200/blogs/normal/format-001
-d '
{
"name" : "format-post-001"
}
'
# 结果
{
"_index": "blogs",
"_type": "normal",
"_id": "format-001",
"_version": 1,
"_shards": {
"total": 3,
"successful": 3,
"failed": 0
},
"created": true
}
# id为format-001的文档目前的version为1,进行更新
# 用version为2去更新
curl -XPUT http://localhost:9200/blogs/normal/format-001?version=2
-d '
{
"name" : "format-post-001-001"
}
'
# 报错,版本冲突
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[normal][format-001]: version conflict, current [1], provided [2]",
"shard": "0",
"index": "blogs"
}
],
"type": "version_conflict_engine_exception",
"reason": "[normal][format-001]: version conflict, current [1], provided [2]",
"shard": "0",
"index": "blogs"
},
"status": 409
}
# 用version为1去更新
curl -XPUT http://localhost:9200/blogs/normal/format-001?version=1
-d '
{
"name" : "format-post-001-001"
}
'
# 更新成功,文档版本变成2
{
"_index": "blogs",
"_type": "normal",
"_id": "format-001",
"_version": 2,
"_shards": {
"total": 3,
"successful": 3,
"failed": 0
},
"created": false
}
|
5.op_type:能够指定本次操做的类型,好比create操做。
# 建立一个id为1,type为normal,在blogs索引中的文档
curl -XPUT http://localhost:9200/blogs/normal/1?op_type=create
-d '
{
"name" : "POST-2"
}
'
{
"_index": "blogs",
"_type": "normal",
"_id": "1",
"_version": 1,
"_shards": {
"total": 3,
"successful": 3,
"failed": 0
},
"created": true
}
# 继续调用同一个操做
curl -XPUT http://localhost:9200/blogs/normal/1?op_type=create
-d '
{
"name" : "POST-2"
}
'
# 报错,文档已经存在
{
"error": {
"root_cause": [
{
"type": "document_already_exists_exception",
"reason": "[normal][1]: document already exists",
"shard": "0",
"index": "blogs"
}
],
"type": "document_already_exists_exception",
"reason": "[normal][1]: document already exists",
"shard": "0",
"index": "blogs"
},
"status": 409
}
|
能够不使用op_type操做,在url中指定。这两种方法效果是同样的
http://localhost:9200/blogs/normal/1/_create 效果跟 http://localhost:9200/blogs/normal/1?op_type=create 是同样的。
目前支持的op_type有create(只支持建立文档)和index(支持建立和更新文档)。
6.wait_for_active_shards
在5.0.0版本新引入的一个参数,表示等待活跃的分片数。做用跟consistency相似,能够设置成all或者任意正整数。
好比在这种场景下:集群中有3个节点node-一、node-2和node-3,而且索引中的分片须要复制3份。那么该索引一共拥有4个分片,包括1个主分片和3个复制分片。
默认状况下,索引操做只须要等待主分片可用(wait_for_active_shards为1)便可。
若是node-2和node-3节点挂了,索引操做是不会受影响的(wait_for_active_shards默认为1);若是设置了wait_for_active_shards为3,那么须要3个节点所有存活;若是设置了wait_for_active_shards为4或者all(一共4个分片,4和all是同样的效果),那么该集群中的索引操做永远都会失败,由于集群一共就3个节点,不能处理全部的4个分片。
好比设置成all,则会抛出以下错误:
{
"error": {
"root_cause": [
{
"type": "unavailable_shards_exception",
"reason": "[blogs][2] Not enough active copies to meet shard count of [ALL] (have 3, needed 4). Timeout: [1m], request: [index {[blogs][normal][AV1QVDz3RpA5iuXn159C], source[{\n \"name\" : \"POST-1\"\n}]}]"
}
],
"type": "unavailable_shards_exception",
"reason": "[blogs][2] Not enough active copies to meet shard count of [ALL] (have 3, needed 4). Timeout: [1m], request: [index {[blogs][normal][AV1QVDz3RpA5iuXn159C], source[{\n \"name\" : \"POST-1\"\n}]}]"
},
"status": 503
}
|
wait_for_active_shards的默认值能够在定义索引的时候进行设置,也能够动态地进行修改:
curl -XPUT http://localhost:9200/blogs/_settings
-d '
{
"index.write.wait_for_active_shards": 3
}
'
|
7.自动生成id
建立文档的时候,能够不指定id,es会自动为你生成1个id,须要注意的话须要使用POST方式,而不是PUT方式。
curl -XPOST http://localhost:9200/blogs/normal
-d '
{
"name" : "my-post"
}
'
{
"_index": "blogs",
"_type": "normal",
"_id": "AV1Pj6MdAuPf3r3i0ysL", # 自动生成的id
"_version": 1,
"_shards": {
"total": 3,
"successful": 3,
"failed": 0
},
"created": true
}
|
8.文档的局部更新
# 新建文档
curl -XPUT http://localhost:9200/blogs/normal/format-doc-001
-d '
{
"title" : "springboot in action",
"author" : "Format"
}
'
# 执行全更新操做
curl -XPUT http://localhost:9200/blogs/normal/format-doc-001
-d '
{
"create_at": "2017-07-18"
}
'
# 获取文档
curl -XGET http://localhost:9200/blogs/normal/format-doc-001
{
"_index": "blogs",
"_type": "normal",
"_id": "format-doc-001",
"_version": 2,
"found": true,
"_source": {
"create_at": "2017-07-18"
}
}
# 使用文档局部更新
curl -XPOST http://localhost:9200/blogs/normal/format-doc-001/_update
-d '
{
"doc": {
"title" : "springboot in action",
"author" : "Format"
}
}
'
# 获取文档
curl -XGET http://localhost:9200/blogs/normal/format-doc-001
{
"_index": "blogs",
"_type": "normal",
"_id": "format-doc-001",
"_version": 3,
"found": true,
"_source": {
"create_at": "2017-07-18",
"author": "Format",
"title": "springboot in action"
}
}
# 使用脚本局部更新
curl -XPOST http://localhost:9200/blogs/normal/format-doc-001/_update
-d '
{
"script" : "ctx._source.views = 0; ctx._source.tags = [new_tag]",
"params": {
"new_tag": "java"
}
}
'
# 获取文档
curl -XGET http://localhost:9200/blogs/normal/format-doc-001
{
"_index": "blogs",
"_type": "normal",
"_id": "format-doc-001",
"_version": 3,
"found": true,
"_source": {
"create_at": "2017-07-18",
"author": "Format",
"title": "springboot in action",
"tags": [
"java"
],
"views": 0
}
}
# 使用脚本局部更新新建立的文档
curl -XPOST http://localhost:9200/blogs/normal/format-doc-002/_update
-d '
{
"script" : "ctx._source.views+=1"
}
'
# 报错,由于id为format-doc-002的文档不存在
{
"error": {
"root_cause": [
{
"type": "document_missing_exception",
"reason": "[normal][format-doc-002]: document missing",
"shard": "0",
"index": "blogs"
}
],
"type": "document_missing_exception",
"reason": "[normal][format-doc-002]: document missing",
"shard": "0",
"index": "blogs"
},
"status": 404
}
# 加上upsert参数(设置字段的初始值)
curl -XPOST http://localhost:9200/blogs/normal/format-doc-002/_update
-d '
{
"script" : "ctx._source.views+=1",
"upsert": {
"views": 1
}
}
'
# 获取文档
curl -XGET http://localhost:9200/blogs/normal/format-doc-002
{
"_index": "blogs",
"_type": "normal",
"_id": "format-doc-002",
"_version": 1,
"found": true,
"_source": {
"views": 1
}
}
|
9.检索多个文档(Multi Get API)
能够在一个请求中得到多个文档数据。
# 在全部索引中执行mget,在参数中指定索引
curl -XGET http://localhost:9200/_mget
-d '
{
"docs" : [
{
"_index" : "blogs",
"_type" : "normal",
"_id" : "format-doc-001"
},
{
"_index" : "blogs",
"_type" : "normal",
"_id" : "format-doc-002"
}
]
}
'
# 结果
{
"docs": [
{
"_index": "blogs",
"_type": "normal",
"_id": "format-doc-001",
"_version": 3,
"found": true,
"_source": {
"create_at": "2017-07-18",
"author": "Format",
"title": "springboot in action",
"tags": [
"java"
],
"views": 0
}
},
{
"_index": "blogs",
"_type": "normal",
"_id": "format-doc-002",
"_version": 1,
"found": true,
"_source": {
"views": 1
}
}
]
}
# 基于特定的索引作mget
curl -XGET http://localhost:9200/blogs/_mget
-d '
{
"docs" : [
{
"_type" : "normal",
"_id" : "format-doc-001"
},
{
"_type" : "normal",
"_id" : "format-doc-002"
}
]
}
'
# 基于特定的索引和类型作mget
curl -XGET http://localhost:9200/blogs/normal/_mget
-d '
{
"docs" : [
{
"_id" : "format-doc-001"
},
{
"_id" : "format-doc-002"
}
]
}
'
# 简化版的基于特定的索引和类型作mget
curl -XGET http://localhost:9200/blogs/normal/_mget
-d '
{
"ids": ["format-doc-001", "format-doc-002"]
}
'
# 过滤source中的属性
curl -XGET http://localhost:9200/_mget
-d '
{
"docs" : [
{
"_index": "blogs",
"_type": "normal",
"_id" : "format-doc-001",
"_source": ["title", "author"]
},
{
"_index": "blogs",
"_type": "normal",
"_id" : "format-doc-002",
"_source": false
},
{
"_index": "blogs",
"_type": "normal",
"_id" : "format-doc-003",
"_source": {
"include": ["title"],
"exclude": ["author"]
}
}
]
}
'
|
10.批量操做(bulk)
批量操做能够实现同一个请求操做多个文档的过程。须要注意的是bulk操做Http Body中的格式,对文档进行处理的话须要使用换行。好比建立新文档,更新文档都须要使用换行把建立目录和文档数据进行分割。不一样的操做也须要用换行进行分割,好比建立文档和删除文档。