• ElasticSearch(八)关于document的一些知识点


    先查看一条数据:

    GET /ecommerce/product/5
    
    {
      "_index" : "ecommerce",
      "_type" : "product",
      "_id" : "5",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "name" : "gaolujie yagao2",
        "desc" : "gaoxiao meibai2",
        "price" : 31,
        "producer" : "gaolujie producer",
        "tags" : [
          "meibai",
          "fangzhu"
        ]
      }
    }

    1、_index元数据

    (1)代表一个document存放在哪个index中

    (2)类似的数据放在一个索引,非类似的数据放不同索引:product index(包含了所有的商品),sales index(包含了所有的商品销售数据),inventory index(包含了所有库存相关的数据)。如果你把比如product,sales,human resource(employee),全都放在一个大的index里面,比如说company index,不合适的。

    2.1)类似的数据放在一个索引,因为这批数据的功能和支持的需求,可能类似,与其他不类似的数据,不在一个shard中,就不会互相影响。

    2.2)类似的数据放在一个索引,也会避免了性能问题,假如不同类型的数据放在同一个index中,可能某些数据会有比较复杂的操作,非常耗时,这样会导致读取某些数据的时候很难,有可能超时。

    (3)index中包含了很多类似的document:类似是什么意思,其实指的就是说,这些document的fields很大一部分是相同的,你说你放了3个document,每个document的fields都完全不一样,这就不是类似了,就不太适合放到一个index里面去了。

    (4)索引名称必须是小写的,不能用下划线开头,不能包含逗号

    2、_type元数据

    (1)代表document属于index中的哪个类别(type)
    (2)一个索引通常会划分为多个type,逻辑上对index中有些许不同的几类数据进行分类:因为一批相同的数据,可能有很多相同的fields,但是还是可能会有一些轻微的不同,可能会有少数fields是不一样的,举个例子,就比如说,商品,可能划分为电子商品,生鲜商品,日化商品,等等。
    (3)type名称可以是大写或者小写,但是同时不能用下划线开头,不能包含逗号

    3、_id元数据

    (1)代表document的唯一标识,与index和type一起,可以唯一标识和定位一个document
    (2)我们可以手动指定document的id(put /index/type/id),也可以不指定,由es自动为我们创建一个id

    4、关于document id

    1、手动指定document id

    1)根据应用情况来说,是否满足手动指定document id的前提:

    一般来说,是从某些其他的系统中,导入一些数据到es时,会采取这种方式,就是使用系统中已有数据的唯一标识,作为es中document的id。举个例子,比如说,我们现在在开发一个电商网站,做搜索功能,或者是OA系统,做员工检索功能。这个时候,数据首先会在网站系统或者IT系统内部的数据库中,会先有一份,此时就肯定会有一个数据库的primary key(自增长,UUID,或者是业务编号)。如果将数据导入到es中,此时就比较适合采用数据在数据库中已有的primary key。

    如果说,我们是在做一个系统,这个系统主要的数据存储就是es一种,也就是说,数据产生出来以后,可能就没有id,直接就放es一个存储,那么这个时候,可能就不太适合说手动指定document id的形式了,因为你也不知道id应该是什么,此时可以采取下面要讲解的让es自动生成id的方式。

    (2)自动生成的id,长度为20个字符,URL安全(可以直接放在url中),base64编码,GUID,分布式系统并行生成时不可能会发生冲突

    4、_source元数据

    _source元数据:就是说,我们在创建一个document的时候,使用的那个放在request body中的json串,默认情况下,在get的时候,会原封不动的给我们返回回来。

    5、定制返回结果

    定制返回的结果,指定_source中,返回哪些field

    PUT /test_index/test_type/1
    {
      "test_field1": "test field1",
      "test_field2": "test field2"
    }
    GET /test_index/test_type/1?_source=test_field1
    
    {
      "_index" : "test_index",
      "_type" : "test_type",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "test_field1" : "test field1"
      }
    }

    6、document的全量替换

    (1)语法与创建文档是一样的,如果document id不存在,那么就是创建;如果document id已经存在,那么就是全量替换操作,替换document的json串内容
    (2)document是不可变的,如果要修改document的内容,第一种方式就是全量替换,直接对document重新建立索引,替换里面所有的内容
    (3)es会将老的document标记为deleted,然后新增我们给定的一个document,当我们创建越来越多的document的时候,es会在适当的时机在后台自动删除标记为deleted的document

    7、document的强制创建

    (1)创建文档与全量替换的语法是一样的,有时我们只是想新建文档,不想替换文档,如果强制进行创建呢?
    (2)PUT /index/type/id?op_type=create,PUT /index/type/id/_create

    8、document的删除 

    (1)DELETE /index/type/id
    (2)不会理解物理删除,只会将其标记为deleted,当数据越来越多的时候,在后台自动删除

    9、_version元数据

    PUT /test_index/test_type/6
    {
      "test_field": "test test"
    }
    {
      "_index" : "test_index",
      "_type" : "test_type",
      "_id" : "6",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 0,
      "_primary_term" : 4
    }

    第一次创建一个document的时候,它的_version内部版本号就是1;以后,每次对这个document执行修改或者删除操作,都会对这个_version版本号自动加1;哪怕是删除,也会对这条数据的版本号加1

    接下来删除该数据

    DELETE /test_index/test_type/6
    
    {
      "_index" : "test_index",
      "_type" : "test_type",
      "_id" : "6",
      "_version" : 2,
      "result" : "deleted",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 4
    }

    然后在创建该数据

    PUT /test_index/test_type/6
    {
      "test_field": "test test"
    }
    
    {
      "_index" : "test_index",
      "_type" : "test_type",
      "_id" : "6",
      "_version" : 3,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 3,
      "_primary_term" : 4
    }

    我们会发现,在删除一个document之后,可以从一个侧面证明,它不是立即物理删除掉的,因为它的一些版本号等信息还是保留着的。先删除一条document,再重新创建这条document,其实会在delete version基础之上,再把version号加1

     关于es后台,多线程异步replica同步并发请求的分析:

    10、document的数据路由

    (1)什么是document路由到shard上

    1.一个index的数据会被分为多片,每片都在一个shard中,所以说,一个document,只能存在于一个shard中
    2.当客户端创建document的时候,es此时就需要决定,这个document是放在这个index的哪个shard上的,这个过程,就称为document routing,数据路由

    (2)路由算法:shard = hash(routing) % number_of_primary_shards

    举个例子,一个index有3个primary shard,P0,P1,P2
    
    每次增删改查一个document的时候,都会带过来一个routing number,默认就是这个document的_id(可能是手动指定,也可能是自动生成)
    routing = _id,假设_id=1
    
    会将这个routing值,传入一个hash函数中,产出一个routing值的hash值,hash(routing) = 21
    然后将hash函数产出的值对这个index的primary shard的数量求余数,21 % 3 = 0
    就决定了,这个document就放在P0上。
    
    决定一个document在哪个shard上,最重要的一个值就是routing值,默认是_id,也可以手动指定,相同的routing值,每次过来,从hash函数中,产出的hash值一定是相同的
    
    无论hash值是几,无论是什么数字,对number_of_primary_shards求余数,结果一定是在0~number_of_primary_shards-1之间这个范围内的。0,1,2。

    (3)自定义routing value

    默认的routing就是_id
    也可以在发送请求的时候,手动指定一个routing value,比如说put /index/type/id?routing=user_id
    
    手动指定routing value是很有用的,可以保证说,某一类document一定被路由到一个shard上去,那么在后续进行应用级别的负载均衡,以及提升批量读取的性能的时候,是很有帮助的

    (4)为什么primary shard数量不可变

    1.primary shard一旦index建立,是不允许修改的。但是replica shard可以随时修改
    2.假设有3个primary shard,我们在某个index下创建一个document,id=1
    ,hash=21,此时计算出的shard=21%3=0
    3.如果修改为4个primary shard,则此时计算出的shard=21%4=1,结果发现没有找到,就会间接导致数据丢失。

    11、关于document的增删改根据coordinating node(协调节点)实现路由原理

    (1)客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)
    (2)coordinating node,对document进行路由,将请求转发给对应的node(有primary shard)
    (3)实际的node上的primary shard处理请求,然后将数据同步到replica node
    (4)coordinating node,如果发现primary node和所有replica node都搞定之后,就返回响应结果给客户端

    11、关于document的写一致性和quorum机制

    写一致性分析:

    1)consistency,one(primary shard),all(all shard),quorum(default)
    
    我们在发送任何一个增删改操作的时候,比如说put /index/type/id,都可以带上一个consistency参数,指明我们想要的写一致性是什么?
    put /index/type/id?consistency=quorum
    
    one:要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行
    all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作
    quorum:默认的值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作

    quorum机制:

    (2)quorum机制,写之前必须确保大多数shard都可用,int( (primary + number_of_replicas) / 2 ) + 1,当number_of_replicas>1时才生效
    
    quroum = int( (primary + number_of_replicas) / 2 ) + 1
    举个例子,3个primary shard,number_of_replicas=1,总共有3 + 3 * 1 = 6个shard
    quorum = int( (3 + 1) / 2 ) + 1 = 3
    所以,要求6个shard中至少有3个shard是active状态的,才可以执行这个写操作
    (3)如果节点数少于quorum数量,可能导致quorum不齐全,进而导致无法执行任何写操作
    
    3个primary shard,replica=1,要求至少3个shard是active,3个shard按照之前学习的shard&replica机制,必须在不同的节点上,如果说只有2台机器的话,是不是有可能出现说,3个shard都没法分配齐全,此时就可能会出现写操作无法执行的情况
    
    es提供了一种特殊的处理场景,就是说当number_of_replicas>1时才生效,因为假如说,你就一个primary shard,replica=1,此时就2个shard
    
    (1 + 1 / 2) + 1 = 2,要求必须有2个shard是活跃的,但是可能就1个node,此时就1个shard是活跃的,如果你不特殊处理的话,导致我们的单节点集群就无法工作

    12、关于document的查询根据coordinating node(协调节点)实现路由原理

    1、客户端发送请求到任意一个node,成为coordinate node(协调节点)
    2、coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡
    3、接收请求的node返回document给coordinate node
    4、coordinate node返回document给客户端
    5、特殊情况:document如果还在建立索引过程中,可能只有primary shard有,任何一个replica shard都没有,此时可能会导致无法读取到document,但是document完成索引建立之后,primary shard和replica shard就都有了

    分析:

  • 相关阅读:
    从开发者角色到产品角色转换
    前端开发做什么?
    最近的前端开发认知总结
    最近的Vue知识总结
    计算机网络
    javascript 字符串加密的几种方法
    JSON数据解析
    JAVA 自定义状态码
    JAVA jdbc获取数据库连接
    JAVA通过md5方法进行加密
  • 原文地址:https://www.cnblogs.com/ql211lin/p/10250723.html
Copyright © 2020-2023  润新知