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就都有了

分析:

 

posted @ 2019-01-17 11:36  加肥猫咪  阅读(...)  评论(...编辑  收藏