• elasticsearch之Index Templates,Routing,Index Aliases


    一、elasticsearch之Index Templates

    前言

    索引模板允许我们定义在创建新索引时自动应用的模板。模板包括设置和映射,以及一个简单的模式模板,该模板控制是否应该将模板应用于新索引。

    为什么需要索引模板?

    在开发中,elasticsearch很大一部分工作是用来处理日志信息的,比如某公司对于日志处理策略是以日期为名创建每天的日志索引。并且每天的索引映射类型和配置信息都是一样的,只是索引名称改变了。如果手动的创建每天的索引,将会是一件很麻烦的事情。为了解决类似问题,elasticsearch提供了预先定义的模板进行索引创建,这个模板称作为Index Templates。通过索引模板可以让类似的索引重用同一个模板。

    模板只在创建索引时应用。更改模板不会对现有索引产生影响。当使用create index API时,作为create index调用的一部分定义的设置/映射将优先于模板中定义的任何匹配设置/映射。
    环境:

    • win10
    • elasticsearch6.5.4
    • kibana6.5.4

    本文所有的示例演示都在kibanaDev Tools中完成。

    创建索引模板

    我们针对前文中提出的问题,来实现一个索引模板:

    Copy
    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是索引模式,指当创建以20product1开头的索引时,使用该索引模板。注意,在elasticsearch的6.x版本中,索引模板模式index_patterns取代原来的template
    ②,在settings设置中,我们自定义为该索引分配3个主分片。复制分片不变。
    ③,mappings中指定映射关系。

    查看索引模板

    我们来查看一下刚才创建的索引模板。

    Copy
    GET _template/2019
    

    我们还可以通过使用通配符来查询多个模板。

    Copy
    GET /_template/temp*
    GET /_template/template_1,template_2
    

    除此之外,我们可以查看所有可用的模板列表:

    Copy
    GET /_template
    

    也可以查询某个模板是否存在:

    Copy
    HEAD _template/2019
    

    注意,返回是以HTTP的状态表示模板是否存在,200表示存在,404表示不存在。

    索引模板的使用

    有了索引模板,我们就可以创建索引并且添加数据了。

    Copy
    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个索引2019010120190102product1_log
    当然查询也是没有问题的:

    Copy
    GET 2019*/doc/_search
    {
      "query": {
        "match_all": {}
      }
    }
    

    我们可以通过查询索引的信息来看一下是否应用上了模板。

    Copy
    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参数的大小决定。比如现在有着一样的一个索引模板:

    Copy
    PUT _template/2018_1
    {
      "index_patterns": ["2018*"],
      "order":0,
      "settings":{
        "number_of_shards": 2
      }
    }
    

    上述索引模板将应用于以2018开头的所有索引,设置索引的主分片数量为2,order参数为0。

    Copy
    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,已经成功应用了索引模板。
    现在我们再来创建一个索引模板:

    Copy
    PUT _template/2018_2
    {
      "index_patterns": ["201802*"],
      "order":1,
      "settings":{
        "number_of_shards": 3
      }
    }
    

    上述模板应用于以201802开头的索引,只是主分片的数量为3,order参数为1。
    我们再来创建一个索引:

    Copy
    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命令删除即可:

    Copy
    DELETE _template/2019
    

    需要注意的是,删除索引模板并不会影响其通过该模板创建的索引。那么,如果想要删除相关的索引怎么办?比如我们删除以2019开头的索引该怎么办?

    Copy
    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如何知道一个文档应该存放到哪个分片中呢?

    首先这肯定不是随机的,否则在检索文档时就不知道该从哪去寻找它了。实际上这个过程是根据下面公式决定的:

    Copy
    shard = hash(routing) % number_of_primary_shards
    

    routing是一个可变值,默认是文档的_id,也可以是自定义的值。hash函数将routing值哈希后生成一个数字,然后这个数字再除以number_of_primary_shards(主分片的数量)得到余数,这个分布在0number_of_primary_shards减一(计数从0开始,比如5个主分片,那么范围就是0~4)之间的余数,就是文档存放的分片位置。
    比如一篇文档的id为123,那么它就应该存在:

    Copy
    >>> hash(123) % 5
    3
    

    这篇文档就存在P3主分片上。

    这也就解释了为什么在创建索引时,主分片的数量一经定义就不能改变,因为如果数量变化了,那么之前所有的路由(routing)值都会无效,文档就再也找不到了。

    一般的,elasticsearch的默认路由算法都会根据文档的id值作为依据将其哈希到相应的主分片上,该算法基本上会将所有的文档平均分布在所有的主分片上,而不会产生某个分片数据过大而导致集群不平衡的情况。
    那么我们在向一个有100个主分片的索引发送查询某篇文档的请求时,该请求发送到集群,集群干了什么呢?

    • 这个请求会被集群交给主节点。
    • 主节点接收这个请求后,将这个查询请求广播到这个索引的每个分片上(包含主、复制分片)。
    • 每个分片执行这个搜索请求,并将结果返回。
    • 结果在主节点上合并、排序后返回给用户。

    这里面就有些问题了。因为在存储文档时,通过hash算法将文档平均分布在各分片上,这就导致了elasticsearch也不确定文档的位置,所以它必须将这个请求广播到所有的分片上去执行。
    为了避免不必要的查询,我们使用自定义的路由模式,这样可以使我们的查询更具目的性。比如之前的查询是这样的:

    Copy
    请求来了,你们(索引下的所有分片)都要检查一下自己是否有符合条件的文档
    

    当能自定义路由后的查询变成了:

    Copy
    请求来了,分片3、5你俩把文档给我返回
    

    自定义路由

    所有的文档 API( getindexdeletebulkupdate 以及 mget )都接受一个叫做 routing 的路由参数 ,通过这个参数我们可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档——例如所有属于同一个用户的文档——都被存储到同一个分片中。

    Copy
    PUT r1/doc/1?routing=user1
    {
      "title":"论母猪的产前保养"
    }
    PUT r1/doc/2?routing=user1
    {
      "title":"论母猪的产后护理"
    }
    
    

    上例中,该文档使用user1作为路由值而不是使用_id。这样,具有相同user1的文档将会被分配同一个分片上。

    通过路由查询文档

    自定义路由可以减少搜索,不需要将搜索请求分发到所有的分片,只需要将请求发送到匹配特定的路由值分片既可。
    我们来查询:

    Copy
    GET r1/doc/1?routing=user1
    # 结果如下
    {
      "_index" : "r1",
      "_type" : "doc",
      "_id" : "1",
      "_version" : 3,
      "_routing" : "user1",
      "found" : true,
      "_source" : {
        "title" : "论母猪的产前保养"
      }
    }
    

    也可通过这个路由值查询文档:

    Copy
    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" : "论母猪的产前保养"
            }
          }
        ]
      }
    }
    

    删除文档

    我们来删除文档。

    Copy
    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
    }
    

    由上例可见,不提供路由,无法删除文档。

    Copy
    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了。
    由此可见,在查询、删除、更新文档时都要提供相同的路由值。

    查询多个路由

    除了指定查询单个路由值之外,还可以指定多个路由值查询:

    Copy
    PUT r2/doc/1?routing=user1
    {
      "title":"母猪产前保养重点在多喂饲料,辅以人工按摩"
    }
    
    PUT r2/doc/2?routing=user2
    {
      "title":"母猪产后护理重点在母子隔离喂养"
    }
    

    此搜索请求将仅在与user1和user2路由值关联的分片上执行。

    Copy
    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" : "母猪产前保养重点在多喂饲料,辅以人工按摩"
            }
          }
        ]
      }
    }
    

    忘了路由值怎么办?

    由之前的示例可以看到,在自定义的路由中,索引、查询、删除、更新文档时,都要提供路由值。但是我们有可能会忘记路由值,导致文档在多个分片建立索引:

    Copy
    PUT r3/doc/1?routing=u1
    {
      "title":"小猪仔真可爱"
    }
    
    PUT r3/doc/2
    {
      "title":"可爱可爱一盘菜"
    }
    

    正如上例所示,我们在创建文档2的时候,忘记路由了,导致这篇文档被默认分配到别的分片上了。那我们想通过u1路由查询就会发现:

    Copy
    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通过这个路由值查询不到,但是可以通过普通的查询:

    Copy
    GET r3/doc/_search
    

    这样,两篇文档都会有被返回。
    为了避免类似上述的情况出现,我们必须采取安全措施,加个套!在自定义映射关系时,使用_routing参数生成那个安全套

    Copy
    # 以下是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错误。就像下面的示例一样。

    Copy
    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来完成的。随着分区大小的增加,数据分布越均匀,代价是每个请求必须搜索更多分片。

    Copy
    PUT r6
    {
      "mappings": {
        "doc":{
          "_routing":{
            "required": true
          }
        }
      },
      "settings": {
        "index.routing_partition_size": 3 
      }
    }
    

    通俗的说,这是限制文档分布到指定个数分片上,而不是默认的所有分片上,既提高了请求效率,也减小单一分片数据量过大的问题。
    当此设置存在时,计算分片的公式变为:

    Copy
    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不知道你要对哪一个具体的索引做操作。

    别名的相关操作

    准备数据

    首先,先准备两个索引:

    Copy
    PUT l1/doc/1
    {
      "title":"我想要睡你"
    }
    
    PUT l2/doc/1
    {
      "title":"你却拿我当兄弟"
    }
    
    PUT l3/doc/1
    {
      "title":"不过,我不介意"
    }
    
    

    创建别名

    我们来为一个索引起一个别名:

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "l1",
            "alias": "a1"
          }
        }
      ]
    }
    

    上例,我们使用add为索引l1添加一个别名a1

    查看别名

    来查看一下刚才添加的别名:

    Copy
    GET l1/_alias
    # result
    {
      "l1" : {
        "aliases" : {
          "a1" : { }
        }
      }
    }
    

    删除别名

    删除别名使用remove

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "remove": {
            "index": "l1",
            "alias": "a1"
          }
        }
      ]
    }
    

    这样就删除了指向索引l1的别名a1,再查l1的别名,你会发现aliases为空。注意,重复删除别名会报aliases_not_found_exception错误。

    重命名别名

    重命名别名是一个简单的remove操作,然后执行add操作,无需担心短时间内别名不指向索引,因为这个操作原子性的:

    Copy
    POST /_aliases
    {
      "actions": [
        {"remove": {"index": "l1", "alias": "a1"}},
        {"add": {"index": "l2", "alias": "a1"}}
      ]
    }
    

    上例,首先索引l1又要有别名a1(别名都没有,删除等着报错呢)。这个原子性的操作,首先删除l1的别名a1,然后添加索引l2的别名a1。这个操作很有爱啊,因为如果要淘汰掉旧的索引l1并将所有数据迁移到了新索引l2上后,这时,我们如果一直使用a1别名处理请求,经过这个操作,在用户毫无感知的情况下就完成了索引的变更。

    为多个索引指向同样的别名

    为多个索引指向同样的别名只需要几个add操作就OK了:

    Copy
    POST /_aliases
    {
      "actions": [
        {"add": {"index": "l1", "alias": "a1"}},
        {"add": {"index": "l2", "alias": "a1"}},
        {"add": {"index": "l3", "alias": "a1"}}
      ]
    }
    

    上例,我们将l1、l2、l3三个索引都指向别名a1

    使用indices数组语法在一个操作中为多个索引指向同一个别名

    可以使用indices数组语法在一个操作中为多个索引指向同一个别名,也是上面示例的另一种写法:

    Copy
    POST /_aliases
    {
      "actions": [
        {"add": {"indices": ["l1", "l2", "l3"], "alias": "a2"}}
      ]
    }
    

    当然,这个套路同样适用于在一个操作中为一个索引指向多个别名

    Copy
    POST /_aliases
    {
      "actions": [
        {"add": {"index": "l1", "aliases": ["a1", "a2", "a3"]}}
      ]
    }
    

    对于上面的示例,也可以使用glob pattern将别名关联到拥有公共名称的多个索引:

    Copy
    POST /_aliases
    {
      "actions": [
        {"add": {"index": "l*", "alias": "f1"}}
      ]
    }
    

    上例指将所有以l开头的索引都指向别名f1。这个操作非常的有用,比如我们处理日志的逻辑是以日期为索引名,每天创建一个索引,那么我们如果想以月为单位分析日志,就可以采用这种方式,比如将2月份每一天的索引都指向一个别名,便于操作。

    别名交换

    在一个操作中使用别名交换:

    Copy
    POST /_aliases
    {
      "actions": [
        {"add": {"index": "l1", "alias": "a1"}},
        {"remove_index":{"index":"a1"}}
      ]
    }
    

    上例的例子的意思是,开始,我们错误的添加了索引a1,而是l1才是我们想要添加的索引,所以这里我们可以先为索引l1创建一个别名a1,然后再把原来的索引a1干掉。remove_index就像删除索引一样(是的,索引a1就这样被干掉了)。

    过滤器别名

    带有过滤器的别名提供了创建相同索引的不同视图的简单方法,过滤器可以使用查询DSL定义,并应用与所有的搜索、计数、按查询删除以及诸如此类的操作。
    要创建一个带过滤器的别名,首先要确保映射字段已存在与mapping中:

    Copy
    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"
    }
    

    我们来看过滤器别名是如何创建的:

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "l4",
            "alias": "a4",
            "filter": {"term": {
              "year": 2019
            }}
          }
        }
      ]
    }
    

    上例,我们为索引l4year字段建立了别名a4。我们来看一下它与普通的别名有什么区别:

    Copy
    {
      "l4" : {
        "aliases" : {
          "a4" : {
            "filter" : {
              "term" : {
                "year" : 2019
              }
            }
          }
        }
      }
    }
    

    如果你够细心的话,你会发现这个带过滤器的别名相较于之前的别名多了过滤条件,普通的别名aliases的字典是空的。
    那么有啥用呢?我们如果以索引l4查询,一切没啥变化:

    Copy
    GET l4/doc/_search
    

    上例查询返回该索引内的所有文档。
    而如果以别名a4查询则仅返回过滤器过滤后的结果:

    Copy
    GET a4/doc/_search
    

    上例仅返回year为2019的文档。

    与路由连用

    除了单独使用别名,还可以将别名与路由值关联,以避免不必要的分片操作。

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "l1",
            "alias": "a1",
            "routing": "1"
          }
        }
      ]
    }
    

    上例为索引l1创建了一个别名a1,在创建完a1后,所有与此别名的操作都将自动修改使用routing值进行路由。
    除此之外,还可以为搜索和索引操作指定不同的路由值:

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "l4",
            "alias": "a4",
            "search_routing": "1,2",
            "index_routing": "1"
          }
        }
      ]
    }
    

    如上例所示,搜索路由(search_routing)可能包含多个(以英文逗号分隔)值,但索引路由(index_routing)就只能包含一个值。
    如果使用路由别名的搜索也有路由参数,则使用在该参数中指定的搜索别名路由和路由的交集:

    Copy
    GET /a4/_search?q=year:2019&routing=2,3
    

    上例中,搜索操作中有路由参数2、3,而搜索路由设置的是1、2,所以取交集2

    写索引

    在之前的介绍中,我们说过,我们仅能使用别名进行查询操作,不能做写入操作,因为如果一个别名关联多个索引的话,es不知道你要将文档写入到哪个索引中,而现在,我们就来解决这个问题,我们要告诉es,要将文档写入到哪个索引中。

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "l1",
            "alias": "a1",
            "is_write_index": true
          }
        },
        {
          "add": {
            "index": "l2",
            "alias": "a1"
          }
        }
      ]
    }
    

    注意,上述的l1l2索引必须存在。
    在上例中,is_write_index:true表示当通过别名a1做写入操作的时候,将文档写入到索引l1中。

    Copy
    PUT a1/doc/2
    {
      "title": "hi gay"
    }
    

    上例中,PUT a1/doc/2相当于向l1/doc/2写入。

    Copy
    GET l1/doc/_search
    GET l1/doc/2
    

    那么如果有些文档的写入要从l1切换到l2该怎么办呢?要交换哪个索引是别名的写入操作,可以利用别名API进行原子交换,交换不依赖于操作的顺序。

    Copy
    POST /_aliases
    {
      "actions": [
        {
          "add": {
            "index": "l1",
            "alias": "a1",
            "is_write_index": false
          }
        },
        {
          "add": {
            "index": "l2",
            "alias": "a1",
            "is_write_index": true
          }
        }
      ]
    }
    

    上例中,我们首先取消l1的写索引权限,然后将该权限交给l2。这样,再写入的话,就是向l2索引了。

    Copy
    PUT a1/doc/3
    {
      "title": "hi man"
    }
    GET l2/doc/3
    

    注意,如果一个别名仅有一个索引指向它时,那么该索引是有写权限的:

    Copy
    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,此时就不能通过该别名做写索引操作了。

    Copy
    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就不知道往哪个索引做写索引操作了。

    添加单个别名

    除了之前添加别名的方法,我们还可以使用端点添加别名:

    Copy
    PUT /{index}/_alias/{name}
    PUT /{index}/_alias/{name}?routing=user1
    
    • index,要为哪个索引添加别名。
    • name,别名的名称。
    • routing,可以与别名关联的路由。

    来个示例,基于时间的别名:

    Copy
    PUT /logs_201905/_alias/2019
    

    再来一个示例,为用户添加别名:

    Copy
    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
    

    索引期间指定别名

    我们除了单独的为一个或多个索引指定别名,也可以在索引创建期间指定别名:

    Copy
    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删除别名:

    Copy
    DELETE /l1/_alias/a1
    DELETE /l2/_aliases/a*
    

    检索现有别名

    使用GET索引别名API检索别名:

    Copy
    GET /{index}/_alias/{alias}
    
    • index,获取别名的索引名称。通过通配符支持部分名称,也可以使用逗号分隔多个索引名称。还可以使用索引的别名。
    • alias,要在响应中返回的别名的名称。与index选项一样,此选项支持通配符,并且选项指定由逗号分隔的多个别名。
    • ignore_unavailable,如果指定的索引名称不存在该怎么办。如果设置为true则那些索引将被忽略。

    来一些示例:
    查询索引指定别名。

    Copy
    GET l1/_alias/a*    # 查询索引l1指向以a开头的所有别名
    GET l1/_alias/*		# 查询索引l1所有的别名
    

    查询所有别名是a12019的索引:

    Copy
    GET /_alias/a1
    GET /_alias/2019
    

    查询所有别名是以20开头的索引:

    Copy
    GET /_alias/20*
    

    HEAD

    通过HEAD检测某个别名是否存在:

    Copy
    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)
  • 相关阅读:
    阅读笔记之FastDepth: Fast Monocular Depth Estimation on Embedded Systems
    AverageMeter一个用来记录和更新变量的工具
    Python中log的简单粗暴的设置和使用
    linux 常用命令
    flutter常用组件总结
    Docker 微服务教程
    Docker 入门教程
    Activiti工作流学习分享
    CentOS7 修改主机名
    Linux中 2>&1 的含义
  • 原文地址:https://www.cnblogs.com/bubu99/p/13593867.html
Copyright © 2020-2023  润新知