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中的当前版本。  

原文地址:https://www.cnblogs.com/gc65/p/10647612.html