zoukankan      html  css  js  c++  java
  • Elasticsearch6.x数据处理(三)

    1.处理冲突

    当使用 index API更新文档的时候,我们读取原始文档,做修改,然后将整个文档(whole document)一次性重新索引。

    最近的索引请求会生效——Elasticsearch中只存储最后被索引的任何文档。如果其他人同时也修改了这个文档,他们的修改将会丢失。

    很多时候,这不是问题。也许我们的主数据存储是关系数据库,我们只是将数据复制到Elasticsearch中以使其可搜索。

    也许两个人几乎不可能同时更改同一个文档。或者,如果偶尔失去变化,对我们的业务来说也许并不重要。

    但有时失去变化非常重要想象一下,我们正在使用Elasticsearch来存储我们在线商店中库存的小部件数量。每次我们出售小部件时,我们都会减少Elasticsearch中的库存数量。

    有一天,管理层决定进行销售。突然间,我们每秒都在销售几个小部件。想象一下,两个并行运行的Web进程,每个进程都处理一个小部件的销售,如下图显示没有并发控制的结果

      

    在数据库领域,通常使用两种方法来确保在并发更新时不会丢失更改

    悲观的并发控制
    这种方法广泛用于关系数据库,它假定可能发生冲突的更改,因此阻止对资源的并发访问以防止冲突。
    一个典型的例子是在读取数据之前锁定一行,确保只有放置锁的线程才能对该行中的数据进行更改。
    乐观的并发控制
    由Elasticsearch使用, 这种方法假定冲突不太可能发生,并且不会阻止尝试操作。
    但是,如果在读取和写入之间修改了基础数据,则更新将失败。然后由应用程序决定如何解决冲突。例如,它可以使用新数据重新尝试更新,或者可以向用户报告情况。

    2.乐观并发控制

      Elasticsearch是分布式的。

    如果要创建,更新或删除新版本的文档,则必须将其复制到群集中的其他节点。

    Elasticsearch也是异步和并发的,这意味着这些复制请求是并行发送的,并且可能不按顺序到达目的地。

    Elasticsearch需要一种方法来确保旧版本的文档永远不会覆盖较新的版本。

    当我们之前讨论过indexgetdelete请求时,我们指出每个文档都有一个_version数字,只要文档被更改,该数字就会递增。

    Elasticsearch使用此_version数字来确保以正确的顺序应用更改。

    如果在新版本之后旧版本文档到达,则可以简单地忽略它。

    我们可以利用这个_version数字来确保 我们的应用程序所做的冲突的更改不会导致数据丢失。

    我们希望通过指定更改的文档的version编号来完成此操作。如果该版本不再是最新版本,我们的请求将失败。

    让我们创建一个新的博客文章:

    curl -X PUT "localhost:9200/website/blog/1/_create" -H 'Content-Type: application/json' -d'
    {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
    }
    '

    响应正文告诉我们这个新创建的文档_version 为1。现在假设我们要编辑文档:我们将其数据加载到Web表单中,进行更改,然后保存新版本。

    首先我们检索文档:

    curl -X GET "localhost:9200/website/blog/1"

    响应正文包含相同的版本_version 1

    {
      "_index" :   "website",
      "_type" :    "blog",
      "_id" :      "1",
      "_version" : 1,
      "found" :    true,
      "_source" :  {
          "title": "My first blog entry",
          "text":  "Just trying this out..."
      }
    }

    现在,当我们尝试通过重新索引文档来保存更改时,我们指定此次修改对应的版本号version

    curl -X PUT "localhost:9200/website/blog/1?version=1" -H 'Content-Type: application/json' -d'
    {
      "title": "My first blog entry",
      "text":  "Starting to get the hang of this..."
    }
    '
    只有当Elasticsearch中此文档的版本为1时,我们的更新才会生效。

    此请求成功(当前此文档的版本为1),响应正文告诉我们_version 已增加到2(因为数据更新了)

    {
      "_index":   "website",
      "_type":    "blog",
      "_id":      "1",
      "_version": 2
      "created":  false
    }

    但是,如果我们要重新运行相同的索引请求,仍然指定 version=1,Elasticsearch将使用409 ConflictHTTP响应代码进行响应,响应内容大致如下:

    {
       "error": {
          "root_cause": [
             {
                "type": "version_conflict_engine_exception",
                "reason": "[blog][1]: version conflict, current [2], provided [1]",
                "index": "website",
                "shard": "3"
             }
          ],
          "type": "version_conflict_engine_exception",
          "reason": "[blog][1]: version conflict, current [2], provided [1]",
          "index": "website",
          "shard": "3"
       },
       "status": 409
    }

    这告诉我们Elasticsearch中当前的文档的_version编号是2,但我们指定更新版本为1

    我们现在所做的工作取决于我们的应用要求。我们可以告诉用户其他人已经对文档进行了更改,并在尝试再次保存之前查看更改。或者,与stock_count先前窗口小部件的情况一样,我们可以检索最新文档并尝试重新应用更改。

    更新或删除文档的所有修改API都接受一个version参数,该参数允许您将乐观并发控制应用于代码中有需要的部分。

    3.使用外部系统中的版本

    常见的设置是使用其他数据库作为主数据存储,使用Elasticsearch使数据可搜索, 这意味着对主数据库的所有更改都需要在发生时复制到Elasticsearch。

    如果多个进程负责此数据同步,则可能会遇到类似于前面描述的并发问题。

    如果您的主数据库已经具有版本号 - 或者诸如 timestamp可以用作版本号的值 - 那么您可以通过添加version_type=external到查询字符串来在Elasticsearch中重用这些相同的版本号。

    版本号必须是大于零且小于9.2e+18的整数 - 在Java中为正值long

    处理外部版本号的方式与我们之前讨论的内部版本号略有不同。

    Elasticsearch检查当前是否小于指定版本,而不是检查当前_version是否请求中指定的当前相同。如果请求成功,则外部版本号将存储为文档的新版本。_version

    外部版本号不仅可以在索引和删除请求中指定,还可以在创建新文档时指定。

    例如,要创建一个外部版本号为5的新博客帖子,我们可以执行以下操作:

    curl -X PUT "localhost:9200/website/blog/2?version=5&version_type=external" -H 'Content-Type: application/json' -d'
    {
      "title": "My first external blog entry",
      "text":  "Starting to get the hang of this..."
    }
    '

    在回复中,我们可以看到当前的_version数字是5

    {
      "_index":   "website",
      "_type":    "blog",
      "_id":      "2",
      "_version": 5,
      "created":  true
    }

    现在我们更新这个文档,指定一个新的version数字10

    curl -X PUT "localhost:9200/website/blog/2?version=10&version_type=external" -H 'Content-Type: application/json' -d'
    {
      "title": "My first external blog entry",
      "text":  "This is a piece of cake..."
    }
    '

    请求成功并将当前设置_version10

    {
      "_index":   "website",
      "_type":    "blog",
      "_id":      "2",
      "_version": 10,
      "created":  false
    }

    如果您要重新运行此请求,它将产生版本冲突错误,因为指定的外部版本号不高于Elasticsearch中的当前版本。  

  • 相关阅读:
    前端基础进阶(四)-让你一分钟就看懂的作用域和作用域链
    前端基础进阶(三)-史上最详细的变量对象详解
    前端基础进阶(二)-知识点解析最精炼最详细
    前端基础进阶(一):内存空间详解-月薪5万
    知道这20个前端正则表达式,能让你做项目时少写1000行甚至一万行,真的
    学习web前端的免费12个学习网站,等你来撩
    一个老牌程序员推荐的JavaScript的书籍,看了真的不后悔!
    零基础的同学看过来,如何系统学习前端
    这是那些大佬程序员常用的学习java网站,这就是别人薪资上万的原因
    Debug outlook add-in (office.js) 小技巧
  • 原文地址:https://www.cnblogs.com/gc65/p/10647612.html
Copyright © 2011-2022 走看看