如何在 Elasticsearch 重新索引无痛脚本中生成 UUID

How to generate a UUID in Elasticsearch reindex painless script

我正在尝试使用重新索引 api 创建一组文档的副本。文档的字段之一 (uuid) 是 UUID。我需要复制的文档在 uuid 字段中具有新的 UUID。

根据 [1] 和 [2],方法 java.util.UUID.randomUUID() 未列入用于无痛脚本的白名单。

问题:

1) 如何轻松生成 UUID?

2) 为什么 UUID.randomUUID() 被认为是不安全的操作?还是只是疏忽没有列入白名单?

3) 如何在 "reindex" 上下文中将 UUID.randomUUID() 列入白名单?我尝试基于 [3] 中的示例构建自己的 elasticsearch painless extension/plugin 来执行此操作。问题是它只适用于 "SearchScript" 上下文。似乎没有等效的 "ReindexContext".

这是我正在尝试的简化版本:

curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "product1"
  },
  "dest": {
    "index": "product2"
  },
  "script": {
    "source": "ctx._source.uuid = java.util.UUID.randomUUID().toString()",
    "lang": "painless"
  }
}
'

这会产生以下错误:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "compile error",
        "script_stack" : [
          "... rce.uuid = java.util.UUID.randomUUID().toString()",
          "                             ^---- HERE"
        ],
        "script" : "ctx._source.uuid = java.util.UUID.randomUUID().toString()",
        "lang" : "painless"
      }
    ],
    "type" : "script_exception",
    "reason" : "compile error",
    "script_stack" : [
      "... rce.uuid = java.util.UUID.randomUUID().toString()",
      "                             ^---- HERE"
    ],
    "script" : "ctx._source.uuid = java.util.UUID.randomUUID().toString()",
    "lang" : "painless",
    "caused_by" : {
      "type" : "illegal_argument_exception",
      "reason" : "method [java.util.UUID, randomUUID/0] not found"
    }
  },
  "status" : 500
}

我知道我的方法是有效的,上面是一个无痛的白名单问题,因为当我尝试不同的方法时 (fromString()) 我没有得到任何错误:

curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "product1"
  },
  "dest": {
    "index": "product2"
  },
  "script": {
    "source": "ctx._source.uuid = java.util.UUID.fromString(\u0027ad139caa-5b54-4179-b812-5015daecad1e\u0027).toString()",
    "lang": "painless"
  }
}
'

参考文献:

[1] - https://discuss.elastic.co/t/generate-a-uuid-using-randomuuid-in-painless/144354/3

[2] - https://www.elastic.co/guide/en/elasticsearch/painless/6.6/painless-api-reference.html

[3] - https://github.com/elastic/elasticsearch/tree/v6.6.0/plugins/examples/painless-whitelist

其他说明:

You can simply do the following,

curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "product1"`enter code here`
  },
  "dest": {
    "index": "product2"
  },
  "script": {
    "source": "ctx._id=ctx._id+1",
    "lang": "painless"
  }
}
'
ctx._id = will always give you a new id and plus 1 will generate the new one.

这只是通过添加后缀获得唯一 ID 的解决方案

最直接的方法就是用自己写的函数,我的。当然这只是一种解决方法,但在大多数情况下应该会有帮助。

String generateUUID(boolean addDashes, boolean upperCase) {
    def chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];

    def dashIndices = [7, 11, 15, 19];

    def sb = new StringBuilder();

    def r = new Random();

    for (def pos = 0; pos < 32; pos += 1) {
       sb.append(chars[r.nextInt(16)]);

       if (addDashes && dashIndices.contains(pos)) {
         sb.append('-');
       }
    }

    def result = sb.toString();

    return upperCase ? result.toUpperCase() : result;
}

将其复制到您的脚本中,如果您需要带破折号和小写的 UUID,您将能够通过调用 generateUUID(true, false) 获取 UUID。

我解决此问题的功能请求已在此处接受并实施:https://github.com/elastic/elasticsearch/issues/39080