2

In the old version of Elasticsearch, we can do:

% curl -XPOST 'localhost:9200/online-shop/shirts/1/_update' -d '{
 "script": "Thread.sleep(10000); ctx._source.price = 2" 
}' 

How to do the sleep with painless in Elasticsearch 7?

  1. Index a document and then update it (update1).
  2. Update1 starts in background and includes a waiting time (sleep).
  3. During that sleep, issue another update command (update2) that modifies the document. This change occurs between update1’s fetch of the original document and its re-indexing operation.
  4. Instead of canceling the changes of update2, update1 fails because the document is already at version 2. At this point you have the chance to retry update1 and apply the changes in version 3. (See listing 3.6.)
Q. Qiao
  • 767
  • 6
  • 17
  • I'm curious about the use case here, can you explain more? – Val Feb 18 '22 at 04:53
  • 1
    @Val I am reading the book Elasticsearch in Action. In an example, it is trying to simulate the situation confliction with 2 updates. Both read the same document and each were updating different fields. I was trying to repeat the example in ES7 while the book was with ES6. – Q. Qiao Feb 19 '22 at 23:54
  • Then you can do it with my answer. The sleep must happen outside ES – Val Feb 20 '22 at 07:05
  • I think I need to have the first entry fetched before issuing the second query. I do not think sleep with bash will work. Thanks for the reply, I added more information in my question. – Q. Qiao Feb 20 '22 at 15:06
  • 1
    There's no other way – Val Feb 20 '22 at 15:07

2 Answers2

0

It was possible to do it with Groovy in ES 5 but as of ES 6 onwards, it is not possible to do it with Painless. Also I'm not sure why this would be needed.

Since you're calling via curl, you can simply do it in your shell

% sleep 10s
% curl -XPOST 'localhost:9200/online-shop/shirts/1/_update' -d '{
 "script": "ctx._source.price = 2" 
}' 
Val
  • 207,596
  • 13
  • 358
  • 360
0

In Painless, you'd have to come up with a very expensive script somehow. Something like:

curl -XPOST -H 'Content-Type: application/json' 'localhost:9200/test/_doc/1/_update?pretty' -d '{
  "script" : {
    "lang": "painless",
    "source": "long total = 0; for (int i = 0; i < 1000000000; ++i) { ctx._source.price += total }"
  }
}'

But this will give you an error like:

        "type" : "painless_error",
        "reason" : "The maximum number of statements that can be executed in a loop has been reached."

Which is because there's a hardcoded maxLoopCounter value that gets triggered.

I eventually gave up trying to craft an expensive script on a dummy setup and ended up cloning the Elasticsearch repo, changing that one number, then doing something like:

./gradlew ':distribution:archives:$DISTRIBUTION_NAME_GOES_HERE:assemble' --parallel

Where $DISTRIBUTION_NAME_GOES_HERE can be linux-tar or whatever Elasticsearch distribution you need - you'll find the complete list in the settings.gradle file. The Java version will need to match (e.g. export JAVA_HOME=/path/to/java-home-where-you-untar-the-expected-version)

Unless you find a way to craft an expensive script without that much data. In which case you don't this this whole mess :)

Radu Gheorghe
  • 984
  • 9
  • 6