Update API

指定されたスクリプトを使用してドキュメントを更新します。

Request

POST /<index>/_update/<_id>

Prerequisites

  • Elasticsearchのセキュリティ機能が有効になっている場合、ターゲットインデックスまたはインデックスエイリアスに対してindexまたはwrite インデックス権限を持っている必要があります。

Description

ドキュメントの更新をスクリプトで行うことができます。スクリプトは、ドキュメントを更新、削除、または変更をスキップすることができます。更新APIは、既存のドキュメントにマージされる部分的なドキュメントを渡すこともサポートしています。既存のドキュメントを完全に置き換えるには、index APIを使用してください。

この操作は:

  • 1. インデックスからシャードと共にドキュメントを取得します。
  • 2. 指定されたスクリプトを実行します。
  • 3. 結果をインデックスします。

ドキュメントは再インデックスする必要がありますが、updateを使用することでネットワークの往復を削減し、GETとインデックス操作の間のバージョン競合の可能性を減らします。

  1. ## Path parameters
  2. - `````<index>
  • (必須、文字列)ターゲットインデックスの名前。デフォルトでは、インデックスが存在しない場合は自動的に作成されます。詳細については、データストリームとインデックスを自動的に作成するを参照してください。
  • <_id>
  • (必須、文字列)更新するドキュメントの一意の識別子。

Query parameters

  • if_seq_no
  • (オプション、整数)ドキュメントがこのシーケンス番号を持つ場合のみ操作を実行します。詳細は楽観的同時実行制御を参照してください。
  • if_primary_term
  • (オプション、整数)ドキュメントがこのプライマリタームを持つ場合のみ操作を実行します。詳細は楽観的同時実行制御を参照してください。
  • lang
  • (オプション、文字列)スクリプト言語。デフォルト:painless
  • require_alias
  • (オプション、ブール値)trueの場合、宛先はインデックスエイリアスでなければなりません。デフォルトはfalseです。
  • refresh
  • (オプション、列挙型)trueの場合、Elasticsearchは影響を受けるシャードをリフレッシュしてこの操作を検索可能にします。wait_forの場合は、リフレッシュを待ってこの操作を検索可能にします。falseの場合は、リフレッシュに対して何もしません。有効な値:truefalsewait_for。デフォルト:false
  • retry_on_conflict
  • (オプション、整数)競合が発生した場合に操作を再試行する回数を指定します。デフォルト:0。
  • routing
  • (オプション、文字列)操作を特定のシャードにルーティングするために使用されるカスタム値。
  • _source
  • (オプション、リスト)ソース取得を無効にするにはfalseに設定します(デフォルト:true)。取得したいフィールドのカンマ区切りリストを指定することもできます。
  • _source_excludes
  • (オプション、リスト)除外したいソースフィールドを指定します。
  • _source_includes
  • (オプション、リスト)取得したいソースフィールドを指定します。
  • timeout
  • (オプション、時間単位)次の操作を待つ期間:
    • 動的マッピングの更新
    • アクティブシャードの待機
      デフォルトは1m(1分)です。これにより、Elasticsearchは失敗する前に少なくともタイムアウトまで待機します。実際の待機時間は、特に複数の待機が発生する場合、長くなる可能性があります。
  • wait_for_active_shards
  • (オプション、文字列)操作を進める前にアクティブでなければならないシャードコピーの数。allまたはインデックス内のシャードの総数(number_of_replicas+1)までの任意の正の整数に設定します。デフォルト:1、プライマリシャード。
    アクティブシャードを参照してください。

Examples

まず、シンプルなドキュメントをインデックスします:

Python

  1. resp = client.index(
  2. index="test",
  3. id="1",
  4. document={
  5. "counter": 1,
  6. "tags": [
  7. "red"
  8. ]
  9. },
  10. )
  11. print(resp)

Ruby

  1. response = client.index(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. counter: 1,
  6. tags: [
  7. 'red'
  8. ]
  9. }
  10. )
  11. puts response

Go

  1. res, err := es.Index(
  2. "test",
  3. strings.NewReader(`{
  4. "counter": 1,
  5. "tags": [
  6. "red"
  7. ]
  8. }`),
  9. es.Index.WithDocumentID("1"),
  10. es.Index.WithPretty(),
  11. )
  12. fmt.Println(res, err)

Js

  1. const response = await client.index({
  2. index: "test",
  3. id: 1,
  4. document: {
  5. counter: 1,
  6. tags: ["red"],
  7. },
  8. });
  9. console.log(response);

Console

  1. PUT test/_doc/1
  2. {
  3. "counter" : 1,
  4. "tags" : ["red"]
  5. }

カウンターをインクリメントするには、次のスクリプトを使用して更新リクエストを送信できます:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script={
  5. "source": "ctx._source.counter += params.count",
  6. "lang": "painless",
  7. "params": {
  8. "count": 4
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: {
  6. source: 'ctx._source.counter += params.count',
  7. lang: 'painless',
  8. params: {
  9. count: 4
  10. }
  11. }
  12. }
  13. )
  14. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "script": {
  6. "source": "ctx._source.counter += params.count",
  7. "lang": "painless",
  8. "params": {
  9. "count": 4
  10. }
  11. }
  12. }`),
  13. es.Update.WithPretty(),
  14. )
  15. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: {
  5. source: "ctx._source.counter += params.count",
  6. lang: "painless",
  7. params: {
  8. count: 4,
  9. },
  10. },
  11. });
  12. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script" : {
  4. "source": "ctx._source.counter += params.count",
  5. "lang": "painless",
  6. "params" : {
  7. "count" : 4
  8. }
  9. }
  10. }

同様に、タグのリストにタグを追加するための更新スクリプトを使用することもできます(これは単なるリストなので、タグが存在していても追加されます):

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script={
  5. "source": "ctx._source.tags.add(params.tag)",
  6. "lang": "painless",
  7. "params": {
  8. "tag": "blue"
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: {
  6. source: 'ctx._source.tags.add(params.tag)',
  7. lang: 'painless',
  8. params: {
  9. tag: 'blue'
  10. }
  11. }
  12. }
  13. )
  14. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "script": {
  6. "source": "ctx._source.tags.add(params.tag)",
  7. "lang": "painless",
  8. "params": {
  9. "tag": "blue"
  10. }
  11. }
  12. }`),
  13. es.Update.WithPretty(),
  14. )
  15. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: {
  5. source: "ctx._source.tags.add(params.tag)",
  6. lang: "painless",
  7. params: {
  8. tag: "blue",
  9. },
  10. },
  11. });
  12. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "ctx._source.tags.add(params.tag)",
  5. "lang": "painless",
  6. "params": {
  7. "tag": "blue"
  8. }
  9. }
  10. }

タグのリストからタグを削除することもできます。タグをremoveするためのPainless関数は、削除したい要素の配列インデックスを取ります。実行時エラーを回避するために、まずタグが存在することを確認する必要があります。リストにタグの重複が含まれている場合、このスクリプトは1つの出現を削除します。

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script={
  5. "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
  6. "lang": "painless",
  7. "params": {
  8. "tag": "blue"
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: {
  6. source: 'if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }',
  7. lang: 'painless',
  8. params: {
  9. tag: 'blue'
  10. }
  11. }
  12. }
  13. )
  14. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "script": {
  6. "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
  7. "lang": "painless",
  8. "params": {
  9. "tag": "blue"
  10. }
  11. }
  12. }`),
  13. es.Update.WithPretty(),
  14. )
  15. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: {
  5. source:
  6. "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
  7. lang: "painless",
  8. params: {
  9. tag: "blue",
  10. },
  11. },
  12. });
  13. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
  5. "lang": "painless",
  6. "params": {
  7. "tag": "blue"
  8. }
  9. }
  10. }

ドキュメントからフィールドを追加および削除することもできます。たとえば、このスクリプトはフィールドnew_fieldを追加します:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script="ctx._source.new_field = 'value_of_new_field'",
  5. )
  6. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: "ctx._source.new_field = 'value_of_new_field'"
  6. }
  7. )
  8. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "script": "ctx._source.new_field = 'value_of_new_field'"
  6. }`),
  7. es.Update.WithPretty(),
  8. )
  9. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: "ctx._source.new_field = 'value_of_new_field'",
  5. });
  6. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script" : "ctx._source.new_field = 'value_of_new_field'"
  4. }

逆に、このスクリプトはフィールドnew_fieldを削除します:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script="ctx._source.remove('new_field')",
  5. )
  6. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: "ctx._source.remove('new_field')"
  6. }
  7. )
  8. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "script": "ctx._source.remove('new_field')"
  6. }`),
  7. es.Update.WithPretty(),
  8. )
  9. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: "ctx._source.remove('new_field')",
  5. });
  6. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script" : "ctx._source.remove('new_field')"
  4. }

次のスクリプトはオブジェクトフィールドからサブフィールドを削除します:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script="ctx._source['my-object'].remove('my-subfield')",
  5. )
  6. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: "ctx._source['my-object'].remove('my-subfield')"
  6. }
  7. )
  8. puts response

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: "ctx._source['my-object'].remove('my-subfield')",
  5. });
  6. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script": "ctx._source['my-object'].remove('my-subfield')"
  4. }

ドキュメントを更新する代わりに、スクリプト内で実行される操作を変更することもできます。たとえば、このリクエストはtagsフィールドがgreenを含む場合にドキュメントを削除し、それ以外の場合は何もしません(noop):

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script={
  5. "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
  6. "lang": "painless",
  7. "params": {
  8. "tag": "green"
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: {
  6. source: "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
  7. lang: 'painless',
  8. params: {
  9. tag: 'green'
  10. }
  11. }
  12. }
  13. )
  14. puts response

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: {
  5. source:
  6. "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
  7. lang: "painless",
  8. params: {
  9. tag: "green",
  10. },
  11. },
  12. });
  13. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
  5. "lang": "painless",
  6. "params": {
  7. "tag": "green"
  8. }
  9. }
  10. }

Update part of a document

次の部分的な更新は、既存のドキュメントに新しいフィールドを追加します:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. doc={
  5. "name": "new_name"
  6. },
  7. )
  8. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. doc: {
  6. name: 'new_name'
  7. }
  8. }
  9. )
  10. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "doc": {
  6. "name": "new_name"
  7. }
  8. }`),
  9. es.Update.WithPretty(),
  10. )
  11. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. doc: {
  5. name: "new_name",
  6. },
  7. });
  8. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. }
  6. }
  1. ### Detect noop updates
  2. デフォルトでは、何も変更しない更新は、何も変更しないことを検出し、`````"result": "noop"`````を返します:
  3. #### Python
  4. ``````python
  5. resp = client.update(
  6. index="test",
  7. id="1",
  8. doc={
  9. "name": "new_name"
  10. },
  11. )
  12. print(resp)
  13. `

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. doc: {
  6. name: 'new_name'
  7. }
  8. }
  9. )
  10. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "doc": {
  6. "name": "new_name"
  7. }
  8. }`),
  9. es.Update.WithPretty(),
  10. )
  11. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. doc: {
  5. name: "new_name",
  6. },
  7. });
  8. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. }
  6. }
  1. [](#431214115cc3e3677d1ab0cd25950fee)
  2. #### Console-Result
  3. ``````console-result
  4. {
  5. "_shards": {
  6. "total": 0,
  7. "successful": 0,
  8. "failed": 0
  9. },
  10. "_index": "test",
  11. "_id": "1",
  12. "_version": 2,
  13. "_primary_term": 1,
  14. "_seq_no": 1,
  15. "result": "noop"
  16. }
  17. `

この動作を無効にするには、"detect_noop": falseを設定します:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. doc={
  5. "name": "new_name"
  6. },
  7. detect_noop=False,
  8. )
  9. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. doc: {
  6. name: 'new_name'
  7. },
  8. detect_noop: false
  9. }
  10. )
  11. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "doc": {
  6. "name": "new_name"
  7. },
  8. "detect_noop": false
  9. }`),
  10. es.Update.WithPretty(),
  11. )
  12. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. doc: {
  5. name: "new_name",
  6. },
  7. detect_noop: false,
  8. });
  9. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. },
  6. "detect_noop": false
  7. }

Upsert

ドキュメントがすでに存在しない場合、upsert要素の内容が新しいドキュメントとして挿入されます。ドキュメントが存在する場合、scriptが実行されます:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. script={
  5. "source": "ctx._source.counter += params.count",
  6. "lang": "painless",
  7. "params": {
  8. "count": 4
  9. }
  10. },
  11. upsert={
  12. "counter": 1
  13. },
  14. )
  15. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. script: {
  6. source: 'ctx._source.counter += params.count',
  7. lang: 'painless',
  8. params: {
  9. count: 4
  10. }
  11. },
  12. upsert: {
  13. counter: 1
  14. }
  15. }
  16. )
  17. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "script": {
  6. "source": "ctx._source.counter += params.count",
  7. "lang": "painless",
  8. "params": {
  9. "count": 4
  10. }
  11. },
  12. "upsert": {
  13. "counter": 1
  14. }
  15. }`),
  16. es.Update.WithPretty(),
  17. )
  18. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. script: {
  5. source: "ctx._source.counter += params.count",
  6. lang: "painless",
  7. params: {
  8. count: 4,
  9. },
  10. },
  11. upsert: {
  12. counter: 1,
  13. },
  14. });
  15. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "script": {
  4. "source": "ctx._source.counter += params.count",
  5. "lang": "painless",
  6. "params": {
  7. "count": 4
  8. }
  9. },
  10. "upsert": {
  11. "counter": 1
  12. }
  13. }

Scripted upsert

ドキュメントが存在するかどうかにかかわらずスクリプトを実行するには、scripted_upserttrueに設定します:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. scripted_upsert=True,
  5. script={
  6. "source": "\n if ( ctx.op == 'create' ) {\n ctx._source.counter = params.count\n } else {\n ctx._source.counter += params.count\n }\n ",
  7. "params": {
  8. "count": 4
  9. }
  10. },
  11. upsert={},
  12. )
  13. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. scripted_upsert: true,
  6. script: {
  7. source: "\n if ( ctx.op == 'create' ) {\n ctx._source.counter = params.count\n } else {\n ctx._source.counter += params.count\n }\n ",
  8. params: {
  9. count: 4
  10. }
  11. },
  12. upsert: {}
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. scripted_upsert: true,
  5. script: {
  6. source:
  7. "\n if ( ctx.op == 'create' ) {\n ctx._source.counter = params.count\n } else {\n ctx._source.counter += params.count\n }\n ",
  8. params: {
  9. count: 4,
  10. },
  11. },
  12. upsert: {},
  13. });
  14. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "scripted_upsert": true,
  4. "script": {
  5. "source": """
  6. if ( ctx.op == 'create' ) {
  7. ctx._source.counter = params.count
  8. } else {
  9. ctx._source.counter += params.count
  10. }
  11. """,
  12. "params": {
  13. "count": 4
  14. }
  15. },
  16. "upsert": {}
  17. }

Doc as upsert

部分的なdocupsertドキュメントを送信する代わりに、doc_as_upserttrueに設定してdocの内容をupsert値として使用できます:

Python

  1. resp = client.update(
  2. index="test",
  3. id="1",
  4. doc={
  5. "name": "new_name"
  6. },
  7. doc_as_upsert=True,
  8. )
  9. print(resp)

Ruby

  1. response = client.update(
  2. index: 'test',
  3. id: 1,
  4. body: {
  5. doc: {
  6. name: 'new_name'
  7. },
  8. doc_as_upsert: true
  9. }
  10. )
  11. puts response

Go

  1. res, err := es.Update(
  2. "test",
  3. "1",
  4. strings.NewReader(`{
  5. "doc": {
  6. "name": "new_name"
  7. },
  8. "doc_as_upsert": true
  9. }`),
  10. es.Update.WithPretty(),
  11. )
  12. fmt.Println(res, err)

Js

  1. const response = await client.update({
  2. index: "test",
  3. id: 1,
  4. doc: {
  5. name: "new_name",
  6. },
  7. doc_as_upsert: true,
  8. });
  9. console.log(response);

Console

  1. POST test/_update/1
  2. {
  3. "doc": {
  4. "name": "new_name"
  5. },
  6. "doc_as_upsert": true
  7. }

doc_as_upsertを使用した[インジェストパイプライン]はサポートされていません。