使用相同的_uid在Elasticsearch索引中复制文档

Suz*_*nne 6 elasticsearch elasticsearch-2.0

我们在其中一个Elasticsearch索引中发现了一些重复文档,但我们无法解决问题.有每个受影响的文件的两个副本,它们拥有完全相同的_id,_type_uid领域.

GET请求/index-name/document-type/document-id只返回一个副本,但是使用这样的查询搜索文档会返回两个结果,这是非常令人惊讶的:

POST /index-name/document-type/_search
{
  "filter": {
    "term": {
      "_id": "document-id"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

_uid字段上聚合还可识别重复文档:

POST /index-name/_search
{
  "size": 0,
  "aggs": {
    "duplicates": {
      "terms": {
        "field": "_uid",
        "min_doc_count": 2
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

重复项都在不同的分片上.例如,文档可能在主分片0上有一个副本,主分片1上有一个副本.我们通过使用首选项参数依次在每个分片上运行上面的聚合查询来验证这一点:它没有找到任何重复项单个碎片.

我们最好的猜测是路由出了问题,但是我们不明白副本如何被路由到不同的分片.根据路由文档,默认路由基于文档ID,并且应始终将文档路由到同一个分片.

我们没有使用会覆盖默认路由的自定义路由参数.我们通过确保重复文档没有_routing字段来仔细检查这一点.

我们也没有定义任何也会影响路由的父/子关系.(例如,在Elasticsearch论坛中查看此问题,其症状与我们的问题相同.我们认为原因不一样,因为我们没有设置任何文档父项).

我们通过重新索引到一个新的索引来解决当前问题,该索引压缩了重复的文档.我们仍然有旧索引进行调试.

我们还没有找到一种复制问题的方法.新索引正确地索引文档,我们尝试重新运行隔夜处理作业,该作业也更新文档,但它没有创建任何更多的重复项.

该集群有3个节点,3个主分片和1个副本(即3个副本分片).minimum_master_nodes设置为2,这应该可以防止裂脑问题.我们正在运行Elasticsearch 2.4(我们知道它已经过时了 - 我们计划很快升级).

有谁知道什么可能导致这些重复?您对调试方法有什么建议吗?

Suz*_*nne 5

我们找到了答案!问题是索引意外地切换了它用于路由的哈希算法,这导致一些更新的文档存储在不同的分片上,使其成为原始版本。

一个 GET 请求/index-name/_settings揭示了这一点:

"version": {
  "created": "1070599",
  "upgraded": "2040699"
},
"legacy": {
  "routing": {
    "use_type": "false",
    "hash": {
      "type": "org.elasticsearch.cluster.routing.DjbHashFunction"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

“1070599”是指 Elasticsearch 1.7,“2040699”是 ES 2.4。

看起来该索引试图将自己从 1.7 升级到 2.4,尽管它已经在运行 2.4。这是这里描述的问题:https : //github.com/elastic/elasticsearch/issues/18459#issuecomment-220313383

我们认为这是触发变化的原因:

  1. 当我们将索引从 ES 1.7 升级到 2.4 时,我们决定不就地升级 Elasticsearch,因为这会导致停机。相反,我们创建了一个单独的 ES 2.4 集群。

    我们使用复制的所有指标设置以及数据,其中包括一个工具加载数据到新的集群version,其设置你不应该在ES 2.4设置

  2. 在处理最近的一个问题时,我们碰巧关闭并重新打开了索引。这通常会保留所有数据,但由于version设置不正确,导致 Elasticsearch 认为正在处理升级。

  3. ES 自动设置legacy.routing.hash.type设置,因为错误升级。这意味着在此之后索引的任何数据都使用旧的DjbHashFunction而不是Murmur3HashFunction最初用于路由数据的默认值。

这意味着将数据重新索引到新索引是解决问题的正确做法。新索引具有正确的版本设置并且没有旧的哈希函数设置:

"version": {
  "created": "2040699"
}
Run Code Online (Sandbox Code Playgroud)