zoukankan      html  css  js  c++  java
  • es之路由:进一步提高Elasticsearch的检索效率(适用大规模数据集)

    1:一条数据是如何落地到对应的shard上的

    当索引一个文档的时候,文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?

    首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个算法决定的:

    shard = hash(routing) % number_of_primary_shards

    routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。

    这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了

    2:路由机制

    现在我们在探讨一个关于路由的问题:

    假设你有一个100个分片的索引。当一个请求在集群上执行时会发生什么呢?

    1. 这个搜索的请求会被发送到一个节点
    2. 接收到这个请求的节点,将这个查询广播到这个索引的每个分片上(可能是主分片,也可能是复制分片)
    3. 每个分片执行这个搜索查询并返回结果
    4. 结果在通道节点上合并、排序并返回给用户

     

    因为默认情况下,Elasticsearch使用文档的ID(类似于关系数据库中的自增ID),如果插入数据量比较大,文档会平均的分布于所有的分片上,这导致了Elasticsearch不能确定文档的位置,所以它必须将这个请求广播到所有的N个分片上去执行

    这种操作会给集群带来负担,增大了网络的开销;

    路由使用:

    PUT my_index/my_type/1?routing=user1&refresh=true 
    {
     "title": "This is a document"
    }

    GET my_index/my_type/1?routing=user1

    上面的代码中,指定了一个用户属性作为路由进行分区,然后查询的时候也必须指定路由。这一点需要注意 只要在索引时候加入路由字段,那么在以后的get,delete,update操作中都必须使用路由字段,否则会出现问题。

    有时候我们会把某些具有相似属性的数据放在同一个路由下,这样可以提高查询的效率;比如:我们把不同季度的销售数据存储在不同的路由下;然后在查询的时候,直接根据路由字段本身进行查询即可,而不需要直接扫描全年的数据:

    PUT department1/order/1?routing=jidu1
    {
     "productName" : "phone",
     "total_price" : 10000000,
     "times" : "2017-01-01"
    }

    PUT department1/order/2?routing=jidu1
    {
     "productName" : "huawei",
     "total_price" : 10000000,
     "times" : "2017-2-01"
    }
    PUT department1/order/1?routing=jidu2
    {
     "productName" : "phone",
     "total_price" : 10009000,
     "times" : "2017-5-01"
    }

    查询季度1的所有数据
    GET department1/_search
    {
     "query": {
       "terms" : {
         "_routing" : [ "jidu1" ]
      }
    }
    }

    查询季度1和季度2的所有数据:
    GET department1/_search
    {
     "query": {
       "terms": {
         "_routing": [ "jidu1" , "jidu2"]
      }
    }
    }

    当然,有时候我们需要查询第一、第二季度的产品中叫做huawei的文档。那么在查询中也是可以指定多个路由的:

    GET department1/_search?routing=jidu1,jidu2 
    {
     "query": {
       "match": {
         "productName": "huawei"
      }
    }
    }

    注意:

    如果加入路由字段之后,其他的操作(indexing,getting,deleting,updating)都必须指定路由字段,为了避免在使用时忘记添加 路由字段,导致同类数据会分布在多个shard上,这就违反了路由的原则,我们可以在mapping中 设置路由字段是必须字段,否则会提示错误:

    PUT department1
    {
    "mappings": {
      "order": {
        "_routing": {
          "required": true
        }
      }
    }
    }

     

  • 相关阅读:
    智能实验室-杀马(Defendio) 3.0.0.670 新春贺岁版
    智能实验室-全能优化(Guardio) 4.0.0.680 beta 9
    解密:骗人的所谓“开放六位 QQ 号码免费申请”
    智能实验室-全能优化(Guardio) 4.0.0.630 beta 3
    智能实验室-全能优化(Guardio) 4.0.0.650 beta 6
    智能实验室-杀马(Defendio) 3.0.0.651 beta 9
    智能实验室-杀马(Defendio) 3.0.0.632 beta 8
    智能实验室-全能优化(Guardio) 4.0.0.691 beta 11
    智能实验室-全能优化(Guardio) 4.0.0.620 beta 2
    智能实验室-全能优化(Guardio) 4.0.0.685 beta 10
  • 原文地址:https://www.cnblogs.com/niutao/p/10909081.html
Copyright © 2011-2022 走看看