ES-CRUD提高
  TEZNKK3IfmPf 2023年11月14日 74 0

手动生成

 

  • 当我们从外界导入数据到 ES 时,我们并不希望改变原本数据的主键,就需要手动设置 ID
  • 手动设置的方式在上面已经学习
  • 方式如下:

 

PUT /index/type/id

ES-CRUD提高

自动生成

 

  • 语法如下:

 

POST /index/type

ES-CRUD提高

 

  • 自动生成的 ID,长度是 20 个字符的 GUID,分布式全局唯一

 

查询指定字段

 

  • 在我们操作 MySQL 时,想必大部分的公司都是禁止使用​​select *​​ 的,而要求用到什么列就查询什么列
  • 而我们上面使用 ES 的方式,就相当于在写​​select *​​ ,这是不推荐的,我们在实际使用的时候,可以只查询指定的字段
  • 语法如下:

 

GET /index/type/id?_source_includes=字段名,多个字段逗号隔开
article/_doc/3?_source_includes=title,red

ES-CRUD提高

强制创建

 

在上面的学习中,我们发现,替换文档和创建文档的 API 是一样的,这就意味着,我们在创建文档的过程中,可能这个文档其实已经存在了,但是我们不知道,通过创建的 API 直接把该文档进行了替换,这不是我们想要的结果,因此需要使用强制创建

 

 

  • 强制创建限定这个 API 只能是创建文档,如果指定 ID 的文档已经存在了,就抛出异常
  • 语法如下:

 

PUT /index/type/id/_create
article/_doc/4/_create

ES-CRUD提高

Lazy Delete

 

  • ES 在替换文档、修改文档的时候,本质上并不是直接替换,而是先将旧文档标记为 deleted,然后再创建新的文档
  • 此时旧的文档实际上还是存在于索引库里的,并不会立即删除,集群会找个合适的时机,一并删除所有标记deleted 的文档
  • 同样,删除的 API 也只是把文档标记了 deleted,并不是立即删除
  • 如果删除一条数据立马删除的话,所有分片和副本都要立马删除,对 es 集群压力太大

 

手动设置版本号

 

  • 我们的数据库中可能已经维护了版本号,现在需要同步这些数据,同步的时候需要手动设置版本号
  • 可以通过使用​​external version​​ 控制,设置的时候版本号必须大于当前文档的版本号
  • 语法如下:

 

PUT /index/type/id?version=要修改的版本号&version_type=external
article/_doc/4/?version=2&version_type=external

ES-CRUD提高

 

  • 两个客户端同时修改,只会有一个会修改成功

 

批量操作

批量查询

 

  • 当我们要根据 id 查询的时候,如果一条一条查,性能损耗和网络开销大,可以使用批量查询
  • 语法如下:

 

GET /_mget

 

  • ​_mget​​​ 是全查询,操作起来并不是那么方便,并且容易报出​​request body or source parameter is required​​ 异常,因此使用率较少

 

批量增删改

 

  • ​_bulk​​ 操作将文档的增删改查一系列操作,通过一次请求全部做完,减少网络传输次数

 

POST /_bulk

 

  • 注意,​​_bulk​​ 操作的形式是多个 JSON,每个 JSON 写完必须换行,而在 JSON 内则不可以换行
  • 多个 JSON 之间操作互不影响,即使前面的报错了,其他行也可以正常执行

 

ES-CRUD提高

{"delete": {"_index": "article", "_id": 6}}
{"create": {"_index": "article", "_id": 7}}
{"title": "我是批量操作中创建的数据,ID是7 "}
{"update": {"_index": "article", "_id": 5}}
{"doc": {"content": "我在批量操作中进行了修改,但是PHP依然是最好的语言"}}

 

  • ​delete​​:删除一个文档,只要 1 个 JSON 串就可以了
  • ​create​​:相当于强制创建,就是:PUT /index/type/id/_create
  • ​index​​:普通的 put 操作,可以是创建文档,也可以是全量替换文档
  • ​update​​​:执行的是局部更新​​partial update​​ 操作

 

 

  • 使用 JSON 格式发送数据

 

ES的并发问题

 

  • 通常情况下,ES 在多线程操作的时候,会产生并发问题
  • 举个例子,我跟你在淘宝在同一时间下单买了同一本书,两个线程同时去 es 扣这本书的库存,库存有 100 本书,正常情况扣完库存后应该变成 98 本,但如果两个线程同时扣减就会有并发冲突,就会变成这样如下例子

 

 

  • 可以看到库存的值变成了 97 本,与我们期望中的 94 本不符
  • 这一现象也叫​​超卖​​,对数据库的库存扣减的时候也会出现这种并发冲突的情况

 

 

  • 为了控制并发问题,我们通常采用​​锁​​ 机制
  • 分为​​悲观锁​​​ 和​​乐观锁​​ 两种机制

 

ES-CRUD提高

悲观锁

 

悲观锁的思路是在线程1读到库存是 100 的时候就把 es 的这条库存给锁上,阻止线程2去读库存,线程1扣完库存并把新的库存量 97 写入 es 后,才允许线程2去读取库存,这时线程2读取出来的库存是 99 而不是100,扣减完变成 98 再写入es

这种思路实际是把并发的线程转成串行执行,非常方便,直接加锁就行,对程序来说不需要做额外的操作,但是并发能力低,同一时间只能一条线程去扣减库存

乐观锁

乐观锁的思路是给 es 的库存附加一个版本号,并发冲突的情况下,线程1读取库存库存 100 (版本号是1)线程2 读取库存 100(版本号1)线程1扣减库存后变成 99,线程2扣减后变成 99,线程1写入库存 99 到 es 前对比库存版本号(线程1读取的库存版本号为1,当前 es 的库存版本号为1)发现一致,于是写入库存 99 到 es 并更新库存版本号为 2,线程2写入库存 99 到 es 前对比库存版本号(线程2读取的库存版本号为1,当前 es 的库存版本号为2)发现不一致,线程2写入失败,线程2重新读取库存 99(版本号2)线程2扣减后变成 98,线程2写入库存98 到 es 前对比库存版本号(都是2)发现一致,于是写入库存 98 到 es 并更新库存版本号为3

这种方式只是在把库存写入 es 那一刻检查一下版本号判断是否可以写入就行了,不需要把库存锁上,因此并发能力很高,但这种方式编码的时候比较麻烦,每次更新库存都要去比对版本号和更新版本号,版本号对不上的时候还需要重新读取库存并扣库存

ES的乐观锁

ES 对文档的增删改都是基于版本号,也就是 ​​_version​​​ 字段,新版本基于 ​​_seq_no​​ 字段

ES-CRUD提高

 

  • 多次新增同一个文档,发现版本号递增
  • 删除文档再新增,发现版本号依然递增,验证了延迟删除策略

 

乐观锁演示

 

  • 查询数据当前的版本号

 

GET /article/_doc/7
article/_doc/4

ES-CRUD提高

 

  • 客户端1更新,带版本号

 

PUT /article/_doc/4?if_seq_no=7&if_primary_term=1

ES-CRUD提高

 

  • 客户端2更新,带版本号,报错

 

PUT /article/_doc/4?if_seq_no=7&if_primary_term=1

ES-CRUD提高

 

  • 客户端2重新查询版本号

 

article/_doc/4

ES-CRUD提高

 

  • 客户端2更新,带版本号

 

article/_doc/4?if_seq_no=10&if_primary_term=1

ES-CRUD提高

更新时的重试机制

  • 更新时的重试机制(retry_on_conflict)
  • 有时候我们在更新时,并不希望失败了直接报错,而是想让程序有一定的重试机制,重试一定次数后如果还是失败,就报错,这时候可以使用retry_on_conflict指定重试次数
  • 语法如下:
POST /index/type/4/_update?retry_on_conflict=次数
article/_doc/4/_update?retry_on_conflict=2
  • 还可以和​​_version​​ 一起使用
  • 使用之前你可以先查看一下版本号
POST /index/type/4/_update?retry_on_conflict=3&version=4&version_type=external
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月14日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   2023年11月14日   35   0   0 elasticsearchDocker
  TEZNKK3IfmPf   2023年11月14日   34   0   0 elasticsearch
TEZNKK3IfmPf