一、elasticsearch之Index Templates
前言
索引模板允许我们定义在创建新索引时自动应用的模板。模板包括设置和映射,以及一个简单的模式模板,该模板控制是否应该将模板应用于新索引。
为什么需要索引模板?
在开发中,elasticsearch
很大一部分工作是用来处理日志信息的,比如某公司对于日志处理策略是以日期为名创建每天的日志索引。并且每天的索引映射类型和配置信息都是一样的,只是索引名称改变了。如果手动的创建每天的索引,将会是一件很麻烦的事情。为了解决类似问题,elasticsearch
提供了预先定义的模板进行索引创建,这个模板称作为Index Templates
。通过索引模板可以让类似的索引重用同一个模板。
模板只在创建索引时应用。更改模板不会对现有索引产生影响。当使用create index API
时,作为create index
调用的一部分定义的设置/映射将优先于模板中定义的任何匹配设置/映射。
环境:
- win10
- elasticsearch6.5.4
- kibana6.5.4
本文所有的示例演示都在kibana
的Dev Tools
中完成。
创建索引模板
我们针对前文中提出的问题,来实现一个索引模板:
PUT _template/2019
{
"index_patterns": ["20*", "product1*"], ①
"settings":{ ②
"number_of_shards": 2,
"number_of_replicas": 1
},
"mappings":{ ③
"doc":{
"properties":{
"ip":{
"type":"keyword"
},
"method":{
"type": "keyword"
}
}
}
}
}
①,index_patterns
是索引模式,指当创建以20
和product1
开头的索引时,使用该索引模板。注意,在elasticsearch的6.x版本中,索引模板模式index_patterns
取代原来的template
。
②,在settings
设置中,我们自定义为该索引分配3个主分片。复制分片不变。
③,mappings
中指定映射关系。
查看索引模板
我们来查看一下刚才创建的索引模板。
GET _template/2019
我们还可以通过使用通配符来查询多个模板。
GET /_template/temp*
GET /_template/template_1,template_2
除此之外,我们可以查看所有可用的模板列表:
GET /_template
也可以查询某个模板是否存在:
HEAD _template/2019
注意,返回是以HTTP的状态表示模板是否存在,200
表示存在,404
表示不存在。
索引模板的使用
有了索引模板,我们就可以创建索引并且添加数据了。
PUT 20190101/doc/1
{
"ip": "127.0.0.1",
"method":"GET"
}
PUT 20190102/doc/2
{
"ip":"192.168.1.1",
"method":"POST"
}
PUT product1_log/doc/1
{
"ip":"127.0.0.1",
"method":"GET"
}
上例会按照模板自动生成3个索引20190101
、20190102
和product1_log
。
当然查询也是没有问题的:
GET 2019*/doc/_search
{
"query": {
"match_all": {}
}
}
我们可以通过查询索引的信息来看一下是否应用上了模板。
GET 20190101
# 结果如下
{
"20190101" : {
"aliases" : { },
"mappings" : {
"doc" : {
"properties" : {
"ip" : {
"type" : "keyword"
},
"method" : {
"type" : "keyword"
}
}
}
},
"settings" : {
"index" : {
"creation_date" : "1557889480975",
"number_of_shards" : "2",
"number_of_replicas" : "1",
"uuid" : "FEuyT5aoTnGP3k_7hCtQFA",
"version" : {
"created" : "6050499"
},
"provided_name" : "20190101"
}
}
}
}
由上例可以看出,索引20190101
已经成功应用上了我们之前创建的模板。
多模板匹配
多个索引模板可以应用于同一个索引,顺序由order
参数的大小决定。比如现在有着一样的一个索引模板:
PUT _template/2018_1
{
"index_patterns": ["2018*"],
"order":0,
"settings":{
"number_of_shards": 2
}
}
上述索引模板将应用于以2018
开头的所有索引,设置索引的主分片数量为2,order
参数为0。
PUT 2018010101/doc/1
{
"method":"GET"
}
GET 2018010101/_settings
# 结果如下
{
"2018010101" : {
"settings" : {
"index" : {
"creation_date" : "1557900456281",
"number_of_shards" : "2",
"number_of_replicas" : "1",
"uuid" : "P53RDmT6RRCDY2DlHtpymg",
"version" : {
"created" : "6050499"
},
"provided_name" : "2018010101"
}
}
}
}
可以看到20180101
索引的主分片数量是2,已经成功应用了索引模板。
现在我们再来创建一个索引模板:
PUT _template/2018_2
{
"index_patterns": ["201802*"],
"order":1,
"settings":{
"number_of_shards": 3
}
}
上述模板应用于以201802
开头的索引,只是主分片的数量为3,order
参数为1。
我们再来创建一个索引:
PUT 2018010201/doc/1
{
"method": "POST"
}
GET 20180201/_settings
# 结果如下
{
"20180201" : {
"settings" : {
"index" : {
"creation_date" : "1557901225020",
"number_of_shards" : "3",
"number_of_replicas" : "1",
"uuid" : "-B8_ZiK7QgesmGSzD_8xlQ",
"version" : {
"created" : "6050499"
},
"provided_name" : "20180201"
}
}
}
}
可以看到20180201
索引应用了order
参数为1的索引模板。这在某些情况下非常有效,比如我们预料到2018年2月份的日志将会暴增,而其他月份不变,所以我们通过上述创建多个模板来完成索引创建,2月份每天的索引的主分片都多一片,过了2月,恢复正常。
删除索引模板
删除索引模板使用DELETE
命令删除即可:
DELETE _template/2019
需要注意的是,删除索引模板并不会影响其通过该模板创建的索引。那么,如果想要删除相关的索引怎么办?比如我们删除以2019
开头的索引该怎么办?
DELETE 2019*
可以使用通配符*
来完成。
see also:[Elasticsearch 6 新特性与重要变更解读](https://blog.csdn.net/napoay/article/details/79135136) | [官网:Index Templates](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates.html)
二、elasticsearch之Routing
前言
当索引一个文档的时候,文档会被存储到一个主分片中。那么,elasticsearch如何知道一个文档应该存放到哪个分片中呢?
首先这肯定不是随机的,否则在检索文档时就不知道该从哪去寻找它了。实际上这个过程是根据下面公式决定的:
shard = hash(routing) % number_of_primary_shards
routing
是一个可变值,默认是文档的_id
,也可以是自定义的值。hash函数将routing
值哈希后生成一个数字,然后这个数字再除以number_of_primary_shards
(主分片的数量)得到余数,这个分布在0
到number_of_primary_shards
减一(计数从0开始,比如5个主分片,那么范围就是0~4)之间的余数,就是文档存放的分片位置。
比如一篇文档的id为123,那么它就应该存在:
>>> hash(123) % 5
3
这篇文档就存在P3
主分片上。
这也就解释了为什么在创建索引时,主分片的数量一经定义就不能改变,因为如果数量变化了,那么之前所有的路由(routing)值都会无效,文档就再也找不到了。
一般的,elasticsearch的默认路由算法都会根据文档的id值作为依据将其哈希到相应的主分片上,该算法基本上会将所有的文档平均分布在所有的主分片上,而不会产生某个分片数据过大而导致集群不平衡的情况。
那么我们在向一个有100个主分片的索引发送查询某篇文档的请求时,该请求发送到集群,集群干了什么呢?
- 这个请求会被集群交给主节点。
- 主节点接收这个请求后,将这个查询请求广播到这个索引的每个分片上(包含主、复制分片)。
- 每个分片执行这个搜索请求,并将结果返回。
- 结果在主节点上合并、排序后返回给用户。
这里面就有些问题了。因为在存储文档时,通过hash算法将文档平均分布在各分片上,这就导致了elasticsearch也不确定文档的位置,所以它必须将这个请求广播到所有的分片上去执行。
为了避免不必要的查询,我们使用自定义的路由模式,这样可以使我们的查询更具目的性。比如之前的查询是这样的:
请求来了,你们(索引下的所有分片)都要检查一下自己是否有符合条件的文档
当能自定义路由后的查询变成了:
请求来了,分片3、5你俩把文档给我返回
自定义路由
所有的文档 API( get
、 index
、 delete
、 bulk
、 update
以及 mget
)都接受一个叫做 routing
的路由参数 ,通过这个参数我们可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档——例如所有属于同一个用户的文档——都被存储到同一个分片中。
PUT r1/doc/1?routing=user1
{
"title":"论母猪的产前保养"
}
PUT r1/doc/2?routing=user1
{
"title":"论母猪的产后护理"
}
上例中,该文档使用user1
作为路由值而不是使用_id
。这样,具有相同user1
的文档将会被分配同一个分片上。
通过路由查询文档
自定义路由可以减少搜索,不需要将搜索请求分发到所有的分片,只需要将请求发送到匹配特定的路由值分片既可。
我们来查询:
GET r1/doc/1?routing=user1
# 结果如下
{
"_index" : "r1",
"_type" : "doc",
"_id" : "1",
"_version" : 3,
"_routing" : "user1",
"found" : true,
"_source" : {
"title" : "论母猪的产前保养"
}
}
也可通过这个路由值查询文档:
GET r1/doc/_search
{
"query": {
"terms": {
"_routing":["user1"]
}
}
}
# 结果如下
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "r1",
"_type" : "doc",
"_id" : "2",
"_score" : 1.0,
"_routing" : "user1",
"_source" : {
"title" : "论母猪的产后护理"
}
},
{
"_index" : "r1",
"_type" : "doc",
"_id" : "1",
"_score" : 1.0,
"_routing" : "user1",
"_source" : {
"title" : "论母猪的产前保养"
}
}
]
}
}
删除文档
我们来删除文档。
DELETE r1/doc/1
# 结果如下
{
"_index" : "r1",
"_type" : "doc",
"_id" : "1",
"_version" : 1,
"result" : "not_found",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
由上例可见,不提供路由,无法删除文档。
DELETE r1/doc/1?routing=user1
# 结果如下
{
"_index" : "r1",
"_type" : "doc",
"_id" : "1",
"_version" : 2,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 4,
"_primary_term" : 1
}
给上路由就OK了。
由此可见,在查询、删除、更新文档时都要提供相同的路由值。
查询多个路由
除了指定查询单个路由值之外,还可以指定多个路由值查询:
PUT r2/doc/1?routing=user1
{
"title":"母猪产前保养重点在多喂饲料,辅以人工按摩"
}
PUT r2/doc/2?routing=user2
{
"title":"母猪产后护理重点在母子隔离喂养"
}
此搜索请求将仅在与user1和user2路由值关联的分片上执行。
GET r2/doc/_search?routing=user1,user2
{
"query": {
"match": {
"title": "母猪"
}
}
}
# 结果如下
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.68324494,
"hits" : [
{
"_index" : "r2",
"_type" : "doc",
"_id" : "2",
"_score" : 0.68324494,
"_routing" : "user2",
"_source" : {
"title" : "母猪产后护理重点在母子隔离喂养"
}
},
{
"_index" : "r2",
"_type" : "doc",
"_id" : "1",
"_score" : 0.5753642,
"_routing" : "user1",
"_source" : {
"title" : "母猪产前保养重点在多喂饲料,辅以人工按摩"
}
}
]
}
}
忘了路由值怎么办?
由之前的示例可以看到,在自定义的路由中,索引、查询、删除、更新文档时,都要提供路由值。但是我们有可能会忘记路由值,导致文档在多个分片建立索引:
PUT r3/doc/1?routing=u1
{
"title":"小猪仔真可爱"
}
PUT r3/doc/2
{
"title":"可爱可爱一盘菜"
}
正如上例所示,我们在创建文档2的时候,忘记路由了,导致这篇文档被默认分配到别的分片上了。那我们想通过u1
路由查询就会发现:
GET r3/doc/_search
{
"query": {
"terms": {
"_routing":["u1"]
}
}
}
# 结果如下
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "r3",
"_type" : "doc",
"_id" : "1",
"_score" : 1.0,
"_routing" : "u1",
"_source" : {
"title" : "小猪仔真可爱"
}
}
]
}
}
可以发现,那个文档2通过这个路由值查询不到,但是可以通过普通的查询:
GET r3/doc/_search
这样,两篇文档都会有被返回。
为了避免类似上述的情况出现,我们必须采取安全措施,加个套!在自定义映射关系时,使用_routing
参数生成那个安全套
!
# 以下是6.5.4版本的写法
PUT r4
{
"mappings": {
"doc":{
"_routing":{
"required": true
}
}
}
}
# 以下是7.0官方文档的的写法
PUT my_index2
{
“mappings”:{
“_ usting”:{
“required”:true
}
}
}
在_routing
参数内,将required:true
就表明在对文档做CURD时需要指定路由。不然就会抛出一个routing_missing_exception
错误。就像下面的示例一样。
PUT r4/doc/1
{
"title":"母猪不怀孕怎么办?"
}
# 结果是报错
{
"error": {
"root_cause": [
{
"type": "routing_missing_exception",
"reason": "routing is required for [r4]/[doc]/[1]",
"index_uuid": "_na_",
"index": "r4"
}
],
"type": "routing_missing_exception",
"reason": "routing is required for [r4]/[doc]/[1]",
"index_uuid": "_na_",
"index": "r4"
},
"status": 400
}
有了这种规范,我们在自定义路由时,就可以避免一些不必要的情况发生了。
自定义路由唯一ID
索引指定自定义_routing的文档时,不能保证索引中所有分片的_id唯一性。 事实上,如果使用不同的_routing值索引,具有相同_id的文档可能最终会出现在不同的分片上。
我们应确保ID在索引中是唯一的。
路由到索引分区
问题来了,在实际开发中,可能由于业务场景问题碰到某个路由的文档量非常大,造成该分片非常大,而某些路由的文档却非常小,这就会造成数据偏移而导致集群不平衡。我们该如何办呢?
我们可以配置索引,使得自定义路由值将转到分片的子集而不是单个分片。这有助于降低上述问题导致集群不平衡的风险,同时仍然可以减少搜索的影响。
这是通过在索引创建时提供索引级别设置index.routing_partition_size
来完成的。随着分区大小的增加,数据分布越均匀,代价是每个请求必须搜索更多分片。
PUT r6
{
"mappings": {
"doc":{
"_routing":{
"required": true
}
}
},
"settings": {
"index.routing_partition_size": 3
}
}
通俗的说,这是限制文档分布到指定个数分片上,而不是默认的所有分片上,既提高了请求效率,也减小单一分片数据量过大的问题。
当此设置存在时,计算分片的公式变为:
shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
也就是说,_routing字段用于计算索引中的一组分片,然后_id用于选择该集合中的分片。
要启用此功能,index.routing_partition_size
应具有大于1且小于index.number_of_shards
的值。
启用后,分区索引将具有以下限制:
- 无法在其中创建具有join field关系的映射。
- 索引中的所有映射都必须将_routing字段标记为必需。
欢迎斧正,that's all see also:[路由一个文档到一个分片中](https://www.elastic.co/guide/cn/elasticsearch/guide/current/routing-value.html) | [官方5.6版本的_routing field](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/mapping-routing-field.html) | [官方7.0的_routing field](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-routing-field.html) | [路由文档到分片](https://www.cnblogs.com/bonelee/p/6055340.html) | [Elasticsearch分片、副本与路由(shard replica routing)](https://www.cnblogs.com/kangoroo/p/7622957.html) | [Elasticsearch路由机制介绍](https://blog.csdn.net/wwd0501/article/details/78109617)
三、elasticsearch之Index Aliases
别名解决了哪些问题?
在开发中,随着业务需求的迭代,较老的业务逻辑就要面临更新甚至是重构,而对于es来说,为了适应新的业务逻辑,可能就要对原有的索引做一些修改,比如对某些字段做调整,甚至是重建索引。而做这些操作的时候,可能会对业务造成影响,甚至是停机调整等问题。由此,es提供了索引别名来解决这些问题。
索引别名就像一个快捷方式或是软连接,可以指向一个或多个索引,也可以给任意一个需要索引名的API来使用。别名的应用为程序提供了极大地灵活性,别名允许我们做下面这些操作:
- 在运行的集群中可以无缝的从一个索引切换到另一个索引。
- 可以给多个索引分组。
- 给索引的一个子集创建视图,没错我们可以简单将es中的索引理解为关系型数据库中的视图。
- 可以与路由搭配使用。
当然,既然是别名,就不能与索引同名,并且别名仅支持查询(暂时可以这么说)操作。因为如果有多个索引指向同一个别名的话,es不知道你要对哪一个具体的索引做操作。
别名的相关操作
准备数据
首先,先准备两个索引:
PUT l1/doc/1
{
"title":"我想要睡你"
}
PUT l2/doc/1
{
"title":"你却拿我当兄弟"
}
PUT l3/doc/1
{
"title":"不过,我不介意"
}
创建别名
我们来为一个索引起一个别名:
POST /_aliases
{
"actions": [
{
"add": {
"index": "l1",
"alias": "a1"
}
}
]
}
上例,我们使用add
为索引l1
添加一个别名a1
。
查看别名
来查看一下刚才添加的别名:
GET l1/_alias
# result
{
"l1" : {
"aliases" : {
"a1" : { }
}
}
}
删除别名
删除别名使用remove
:
POST /_aliases
{
"actions": [
{
"remove": {
"index": "l1",
"alias": "a1"
}
}
]
}
这样就删除了指向索引l1
的别名a1
,再查l1
的别名,你会发现aliases
为空。注意,重复删除别名会报aliases_not_found_exception
错误。
重命名别名
重命名别名是一个简单的remove
操作,然后执行add
操作,无需担心短时间内别名不指向索引,因为这个操作原子性的:
POST /_aliases
{
"actions": [
{"remove": {"index": "l1", "alias": "a1"}},
{"add": {"index": "l2", "alias": "a1"}}
]
}
上例,首先索引l1
又要有别名a1
(别名都没有,删除等着报错呢)。这个原子性的操作,首先删除l1
的别名a1
,然后添加索引l2
的别名a1
。这个操作很有爱啊,因为如果要淘汰掉旧的索引l1
并将所有数据迁移到了新索引l2
上后,这时,我们如果一直使用a1
别名处理请求,经过这个操作,在用户毫无感知的情况下就完成了索引的变更。
为多个索引指向同样的别名
为多个索引指向同样的别名只需要几个add
操作就OK了:
POST /_aliases
{
"actions": [
{"add": {"index": "l1", "alias": "a1"}},
{"add": {"index": "l2", "alias": "a1"}},
{"add": {"index": "l3", "alias": "a1"}}
]
}
上例,我们将l1、l2、l3
三个索引都指向别名a1
。
使用indices数组语法在一个操作中为多个索引指向同一个别名
可以使用indices
数组语法在一个操作中为多个索引指向同一个别名,也是上面示例的另一种写法:
POST /_aliases
{
"actions": [
{"add": {"indices": ["l1", "l2", "l3"], "alias": "a2"}}
]
}
当然,这个套路同样适用于在一个操作中为一个索引指向多个别名:
POST /_aliases
{
"actions": [
{"add": {"index": "l1", "aliases": ["a1", "a2", "a3"]}}
]
}
对于上面的示例,也可以使用glob pattern
将别名关联到拥有公共名称的多个索引:
POST /_aliases
{
"actions": [
{"add": {"index": "l*", "alias": "f1"}}
]
}
上例指将所有以l
开头的索引都指向别名f1
。这个操作非常的有用,比如我们处理日志的逻辑是以日期为索引名,每天创建一个索引,那么我们如果想以月为单位分析日志,就可以采用这种方式,比如将2月份每一天的索引都指向一个别名,便于操作。
别名交换
在一个操作中使用别名交换:
POST /_aliases
{
"actions": [
{"add": {"index": "l1", "alias": "a1"}},
{"remove_index":{"index":"a1"}}
]
}
上例的例子的意思是,开始,我们错误的添加了索引a1
,而是l1
才是我们想要添加的索引,所以这里我们可以先为索引l1
创建一个别名a1
,然后再把原来的索引a1
干掉。remove_index
就像删除索引一样(是的,索引a1
就这样被干掉了)。
过滤器别名
带有过滤器的别名提供了创建相同索引的不同视图
的简单方法,过滤器可以使用查询DSL定义,并应用与所有的搜索、计数、按查询删除以及诸如此类的操作。
要创建一个带过滤器的别名,首先要确保映射字段已存在与mapping
中:
PUT l4
{
"mappings": {
"doc":{
"properties":{
"year":{
"type":"integer"
},
"method":{
"type":"keyword"
}
}
}
}
}
PUT l4/doc/1
{
"year":2019,
"method":"GET"
}
PUT l4/doc/2
{
"year":2018,
"method":"POST"
}
PUT l4/doc/3
{
"year":2019,
"method":"POST"
}
我们来看过滤器别名是如何创建的:
POST /_aliases
{
"actions": [
{
"add": {
"index": "l4",
"alias": "a4",
"filter": {"term": {
"year": 2019
}}
}
}
]
}
上例,我们为索引l4
以year
字段建立了别名a4
。我们来看一下它与普通的别名有什么区别:
{
"l4" : {
"aliases" : {
"a4" : {
"filter" : {
"term" : {
"year" : 2019
}
}
}
}
}
}
如果你够细心的话,你会发现这个带过滤器的别名相较于之前的别名多了过滤条件,普通的别名aliases
的字典是空的。
那么有啥用呢?我们如果以索引l4
查询,一切没啥变化:
GET l4/doc/_search
上例查询返回该索引内的所有文档。
而如果以别名a4
查询则仅返回过滤器过滤后的结果:
GET a4/doc/_search
上例仅返回year
为2019的文档。
与路由连用
除了单独使用别名,还可以将别名与路由值关联,以避免不必要的分片操作。
POST /_aliases
{
"actions": [
{
"add": {
"index": "l1",
"alias": "a1",
"routing": "1"
}
}
]
}
上例为索引l1
创建了一个别名a1
,在创建完a1
后,所有与此别名的操作都将自动修改使用routing
值进行路由。
除此之外,还可以为搜索和索引操作指定不同的路由值:
POST /_aliases
{
"actions": [
{
"add": {
"index": "l4",
"alias": "a4",
"search_routing": "1,2",
"index_routing": "1"
}
}
]
}
如上例所示,搜索路由(search_routing)可能包含多个(以英文逗号分隔)值,但索引路由(index_routing)就只能包含一个值。
如果使用路由别名的搜索也有路由参数,则使用在该参数中指定的搜索别名路由和路由的交集:
GET /a4/_search?q=year:2019&routing=2,3
上例中,搜索操作中有路由参数2、3
,而搜索路由设置的是1、2
,所以取交集2
。
写索引
在之前的介绍中,我们说过,我们仅能使用别名进行查询操作,不能做写入操作,因为如果一个别名关联多个索引的话,es不知道你要将文档写入到哪个索引中,而现在,我们就来解决这个问题,我们要告诉es,要将文档写入到哪个索引中。
POST /_aliases
{
"actions": [
{
"add": {
"index": "l1",
"alias": "a1",
"is_write_index": true
}
},
{
"add": {
"index": "l2",
"alias": "a1"
}
}
]
}
注意,上述的l1
和l2
索引必须存在。
在上例中,is_write_index:true
表示当通过别名a1
做写入操作的时候,将文档写入到索引l1
中。
PUT a1/doc/2
{
"title": "hi gay"
}
上例中,PUT a1/doc/2
相当于向l1/doc/2
写入。
GET l1/doc/_search
GET l1/doc/2
那么如果有些文档的写入要从l1
切换到l2
该怎么办呢?要交换哪个索引是别名的写入操作,可以利用别名API进行原子交换,交换不依赖于操作的顺序。
POST /_aliases
{
"actions": [
{
"add": {
"index": "l1",
"alias": "a1",
"is_write_index": false
}
},
{
"add": {
"index": "l2",
"alias": "a1",
"is_write_index": true
}
}
]
}
上例中,我们首先取消l1
的写索引权限,然后将该权限交给l2
。这样,再写入的话,就是向l2
索引了。
PUT a1/doc/3
{
"title": "hi man"
}
GET l2/doc/3
注意,如果一个别名仅有一个索引指向它时,那么该索引是有写权限的:
PUT l5/doc/1
{
"title":"肉肉的猪仔真可爱"
}
POST /_aliases
{
"actions": [
{
"add": {
"index": "l5",
"alias": "a5"
}
}
]
}
PUT a5/doc/2
{
"title":"可爱可爱真可爱"
}
GET l5/doc/_search
如上例所示,此时的别名a5
仅有索引l5
指向它。所以可以通过该别名做写入操作。
但是,当又有新的索引l4
指向该别名时,如果没有显示的设置is_write_index:true
,此时就不能通过该别名做写索引操作了。
POST /_aliases
{
"actions": [
{
"add": {
"index": "l4",
"alias": "a5"
}
}
]
}
PUT a5/doc/3
{
"title":"可爱可爱真可爱"
}
上例中,当PUT a5/doc/3
时会报错illegal_argument_exception
,因为此时没有为哪个索引指定is_write_index:true
,es就不知道往哪个索引做写索引操作了。
添加单个别名
除了之前添加别名的方法,我们还可以使用端点添加别名:
PUT /{index}/_alias/{name}
PUT /{index}/_alias/{name}?routing=user1
- index,要为哪个索引添加别名。
- name,别名的名称。
- routing,可以与别名关联的路由。
来个示例,基于时间的别名:
PUT /logs_201905/_alias/2019
再来一个示例,为用户添加别名:
PUT user
{
"mappings": {
"doc":{
"properties":{
"user_id":{
"type":"integer"
}
}
}
}
}
PUT /user/_alias/user_1
{
"routing": "1",
"filter": {
"term": {
"user_id": "1"
}
}
}
PUT /user/doc/1?routing=1
{
"user_id": "1"
}
GET /user/doc/_search
GET /user/doc/1
索引期间指定别名
我们除了单独的为一个或多个索引指定别名,也可以在索引创建期间指定别名:
PUT l6
{
"mappings": {
"doc":{
"properties":{
"year":{
"type":"integer"
}
}
}
},
"aliases": {
"current_day": {},
"2019":{
"filter": {
"term": {
"year": 2019
}
}
}
}
}
PUT l6/doc/1
{
"year": 2018
}
PUT l6/doc/2
{
"year": 2019
}
GET 2019/_search
删除别名
通过使用DELETE
删除别名:
DELETE /l1/_alias/a1
DELETE /l2/_aliases/a*
检索现有别名
使用GET
索引别名API检索别名:
GET /{index}/_alias/{alias}
- index,获取别名的索引名称。通过通配符支持部分名称,也可以使用逗号分隔多个索引名称。还可以使用索引的别名。
- alias,要在响应中返回的别名的名称。与index选项一样,此选项支持通配符,并且选项指定由逗号分隔的多个别名。
- ignore_unavailable,如果指定的索引名称不存在该怎么办。如果设置为true则那些索引将被忽略。
来一些示例:
查询索引指定别名。
GET l1/_alias/a* # 查询索引l1指向以a开头的所有别名
GET l1/_alias/* # 查询索引l1所有的别名
查询所有别名是a1
或2019
的索引:
GET /_alias/a1
GET /_alias/2019
查询所有别名是以20
开头的索引:
GET /_alias/20*
HEAD
通过HEAD
检测某个别名是否存在:
HEAD /_alias/2019
HEAD /_alias/20*
HEAD /l2/_alias/*
上例中,HEAD
以状态码的形式返回是别名是否存在,200 - OK
是存在,404 - Not Found
是不存在。
欢迎斧正,that's all see also:[Elasticsearch 技术分析(三): 索引别名Aliases问题](https://www.cnblogs.com/jajian/p/10152681.html) | [官网:Index Aliases](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html)