123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- [[docs-update]]
- == Update API
- The update API allows to update a document based on a script provided.
- The operation gets the document (collocated with the shard) from the
- index, runs the script (with optional script language and parameters),
- and index back the result (also allows to delete, or ignore the
- operation). It uses versioning to make sure no updates have happened
- during the "get" and "reindex".
- Note, this operation still means full reindex of the document, it just
- removes some network roundtrips and reduces chances of version conflicts
- between the get and the index. The `_source` field needs to be enabled
- for this feature to work.
- For example, let's index a simple doc:
- [source,js]
- --------------------------------------------------
- PUT test/_doc/1
- {
- "counter" : 1,
- "tags" : ["red"]
- }
- --------------------------------------------------
- // CONSOLE
- [float]
- === Scripted updates
- Now, we can execute a script that would increment the counter:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : {
- "source": "ctx._source.counter += params.count",
- "lang": "painless",
- "params" : {
- "count" : 4
- }
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- We can add a tag to the list of tags (note, if the tag exists, it
- will still add it, since it's a list):
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : {
- "source": "ctx._source.tags.add(params.tag)",
- "lang": "painless",
- "params" : {
- "tag" : "blue"
- }
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- We can remove a tag from the list of tags. Note that the Painless function to
- `remove` a tag takes as its parameter the array index of the element you wish
- to remove, so you need a bit more logic to locate it while avoiding a runtime
- error. Note that if the tag was present more than once in the list, this will
- remove only one occurrence of it:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : {
- "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
- "lang": "painless",
- "params" : {
- "tag" : "blue"
- }
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- In addition to `_source`, the following variables are available through
- the `ctx` map: `_index`, `_type`, `_id`, `_version`, `_routing`
- and `_now` (the current timestamp).
- We can also add a new field to the document:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : "ctx._source.new_field = 'value_of_new_field'"
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- Or remove a field from the document:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : "ctx._source.remove('new_field')"
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- And, we can even change the operation that is executed. This example deletes
- the doc if the `tags` field contain `green`, otherwise it does nothing
- (`noop`):
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : {
- "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
- "lang": "painless",
- "params" : {
- "tag" : "green"
- }
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- [float]
- === Updates with a partial document
- The update API also support passing a partial document,
- which will be merged into the existing document (simple recursive merge,
- inner merging of objects, replacing core "keys/values" and arrays).
- To fully replace the existing document, the <<docs-index_,`index` API>> should
- be used instead.
- The following partial update adds a new field to the
- existing document:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "doc" : {
- "name" : "new_name"
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- If both `doc` and `script` are specified, then `doc` is ignored. Best is
- to put your field pairs of the partial document in the script itself.
- [float]
- === Detecting noop updates
- If `doc` is specified its value is merged with the existing `_source`.
- By default updates that don't change anything detect that they don't change anything and return "result": "noop" like this:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "doc" : {
- "name" : "new_name"
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- If `name` was `new_name` before the request was sent then the entire update
- request is ignored. The `result` element in the response returns `noop` if
- the request was ignored.
- [source,js]
- --------------------------------------------------
- {
- "_shards": {
- "total": 0,
- "successful": 0,
- "failed": 0
- },
- "_index": "test",
- "_type": "_doc",
- "_id": "1",
- "_version": 7,
- "result": "noop"
- }
- --------------------------------------------------
- // TESTRESPONSE
- You can disable this behavior by setting "detect_noop": false like this:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "doc" : {
- "name" : "new_name"
- },
- "detect_noop": false
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- [[upserts]]
- [float]
- === Upserts
- If the document does not already exist, the contents of the `upsert` element
- will be inserted as a new document. If the document does exist, then the
- `script` will be executed instead:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "script" : {
- "source": "ctx._source.counter += params.count",
- "lang": "painless",
- "params" : {
- "count" : 4
- }
- },
- "upsert" : {
- "counter" : 1
- }
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- [float]
- ==== `scripted_upsert`
- If you would like your script to run regardless of whether the document exists
- or not -- i.e. the script handles initializing the document instead of the
- `upsert` element -- then set `scripted_upsert` to `true`:
- [source,js]
- --------------------------------------------------
- POST sessions/session/dh3sgudg8gsrgl/_update
- {
- "scripted_upsert":true,
- "script" : {
- "id": "my_web_session_summariser",
- "params" : {
- "pageViewEvent" : {
- "url":"foo.com/bar",
- "response":404,
- "time":"2014-01-01 12:32"
- }
- }
- },
- "upsert" : {}
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[s/"id": "my_web_session_summariser"/"source": "ctx._source.page_view_event = params.pageViewEvent"/]
- // TEST[continued]
- [float]
- ==== `doc_as_upsert`
- Instead of sending a partial `doc` plus an `upsert` doc, setting
- `doc_as_upsert` to `true` will use the contents of `doc` as the `upsert`
- value:
- [source,js]
- --------------------------------------------------
- POST test/_doc/1/_update
- {
- "doc" : {
- "name" : "new_name"
- },
- "doc_as_upsert" : true
- }
- --------------------------------------------------
- // CONSOLE
- // TEST[continued]
- [float]
- === Parameters
- The update operation supports the following query-string parameters:
- [horizontal]
- `retry_on_conflict`::
- In between the get and indexing phases of the update, it is possible that
- another process might have already updated the same document. By default, the
- update will fail with a version conflict exception. The `retry_on_conflict`
- parameter controls how many times to retry the update before finally throwing
- an exception.
- `routing`::
- Routing is used to route the update request to the right shard and sets the
- routing for the upsert request if the document being updated doesn't exist.
- Can't be used to update the routing of an existing document.
- `timeout`::
- Timeout waiting for a shard to become available.
- `wait_for_active_shards`::
- The number of shard copies required to be active before proceeding with the update operation.
- See <<index-wait-for-active-shards,here>> for details.
- `refresh`::
- Control when the changes made by this request are visible to search. See
- <<docs-refresh>>.
- `_source`::
- Allows to control if and how the updated source should be returned in the response.
- By default the updated source is not returned.
- See <<search-request-source-filtering, `source filtering`>> for details.
- `version`::
- The update API uses the Elasticsearch's versioning support internally to make
- sure the document doesn't change during the update. You can use the `version`
- parameter to specify that the document should only be updated if its version
- matches the one specified.
- [NOTE]
- .The update API does not support versioning other than internal
- =====================================================
- External (version types `external` & `external_gte`) or forced (version type `force`)
- versioning is not supported by the update API as it would result in Elasticsearch
- version numbers being out of sync with the external system. Use the
- <<docs-index_,`index` API>> instead.
- =====================================================
|