Update API
指定されたスクリプトを使用してドキュメントを更新します。
Request
POST /<index>/_update/<_id>
Prerequisites
- Elasticsearchのセキュリティ機能が有効になっている場合、ターゲットインデックスまたはインデックスエイリアスに対して
index
またはwrite
インデックス権限を持っている必要があります。
Description
ドキュメントの更新をスクリプトで行うことができます。スクリプトは、ドキュメントを更新、削除、または変更をスキップすることができます。更新APIは、既存のドキュメントにマージされる部分的なドキュメントを渡すこともサポートしています。既存のドキュメントを完全に置き換えるには、index
APIを使用してください。
この操作は:
- 1. インデックスからシャードと共にドキュメントを取得します。
- 2. 指定されたスクリプトを実行します。
- 3. 結果をインデックスします。
ドキュメントは再インデックスする必要がありますが、update
を使用することでネットワークの往復を削減し、GETとインデックス操作の間のバージョン競合の可能性を減らします。
## Path parameters
- `````<index>
- (必須、文字列)ターゲットインデックスの名前。デフォルトでは、インデックスが存在しない場合は自動的に作成されます。詳細については、データストリームとインデックスを自動的に作成するを参照してください。
<_id>
- (必須、文字列)更新するドキュメントの一意の識別子。
Query parameters
if_seq_no
- (オプション、整数)ドキュメントがこのシーケンス番号を持つ場合のみ操作を実行します。詳細は楽観的同時実行制御を参照してください。
if_primary_term
- (オプション、整数)ドキュメントがこのプライマリタームを持つ場合のみ操作を実行します。詳細は楽観的同時実行制御を参照してください。
lang
- (オプション、文字列)スクリプト言語。デフォルト:
painless
。 require_alias
- (オプション、ブール値)
true
の場合、宛先はインデックスエイリアスでなければなりません。デフォルトはfalse
です。 refresh
- (オプション、列挙型)
true
の場合、Elasticsearchは影響を受けるシャードをリフレッシュしてこの操作を検索可能にします。wait_for
の場合は、リフレッシュを待ってこの操作を検索可能にします。false
の場合は、リフレッシュに対して何もしません。有効な値:true
、false
、wait_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
resp = client.index(
index="test",
id="1",
document={
"counter": 1,
"tags": [
"red"
]
},
)
print(resp)
Ruby
response = client.index(
index: 'test',
id: 1,
body: {
counter: 1,
tags: [
'red'
]
}
)
puts response
Go
res, err := es.Index(
"test",
strings.NewReader(`{
"counter": 1,
"tags": [
"red"
]
}`),
es.Index.WithDocumentID("1"),
es.Index.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.index({
index: "test",
id: 1,
document: {
counter: 1,
tags: ["red"],
},
});
console.log(response);
Console
PUT test/_doc/1
{
"counter" : 1,
"tags" : ["red"]
}
カウンターをインクリメントするには、次のスクリプトを使用して更新リクエストを送信できます:
Python
resp = client.update(
index="test",
id="1",
script={
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 4
}
},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: {
source: 'ctx._source.counter += params.count',
lang: 'painless',
params: {
count: 4
}
}
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"script": {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 4
}
}
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
script: {
source: "ctx._source.counter += params.count",
lang: "painless",
params: {
count: 4,
},
},
});
console.log(response);
Console
POST test/_update/1
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
}
}
同様に、タグのリストにタグを追加するための更新スクリプトを使用することもできます(これは単なるリストなので、タグが存在していても追加されます):
Python
resp = client.update(
index="test",
id="1",
script={
"source": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params": {
"tag": "blue"
}
},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: {
source: 'ctx._source.tags.add(params.tag)',
lang: 'painless',
params: {
tag: 'blue'
}
}
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"script": {
"source": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params": {
"tag": "blue"
}
}
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
script: {
source: "ctx._source.tags.add(params.tag)",
lang: "painless",
params: {
tag: "blue",
},
},
});
console.log(response);
Console
POST test/_update/1
{
"script": {
"source": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params": {
"tag": "blue"
}
}
}
タグのリストからタグを削除することもできます。タグをremove
するためのPainless関数は、削除したい要素の配列インデックスを取ります。実行時エラーを回避するために、まずタグが存在することを確認する必要があります。リストにタグの重複が含まれている場合、このスクリプトは1つの出現を削除します。
Python
resp = client.update(
index="test",
id="1",
script={
"source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
"lang": "painless",
"params": {
"tag": "blue"
}
},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: {
source: 'if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }',
lang: 'painless',
params: {
tag: 'blue'
}
}
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"script": {
"source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
"lang": "painless",
"params": {
"tag": "blue"
}
}
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
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.log(response);
Console
POST test/_update/1
{
"script": {
"source": "if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }",
"lang": "painless",
"params": {
"tag": "blue"
}
}
}
ドキュメントからフィールドを追加および削除することもできます。たとえば、このスクリプトはフィールドnew_field
を追加します:
Python
resp = client.update(
index="test",
id="1",
script="ctx._source.new_field = 'value_of_new_field'",
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: "ctx._source.new_field = 'value_of_new_field'"
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"script": "ctx._source.new_field = 'value_of_new_field'"
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
script: "ctx._source.new_field = 'value_of_new_field'",
});
console.log(response);
Console
POST test/_update/1
{
"script" : "ctx._source.new_field = 'value_of_new_field'"
}
逆に、このスクリプトはフィールドnew_field
を削除します:
Python
resp = client.update(
index="test",
id="1",
script="ctx._source.remove('new_field')",
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: "ctx._source.remove('new_field')"
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"script": "ctx._source.remove('new_field')"
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
script: "ctx._source.remove('new_field')",
});
console.log(response);
Console
POST test/_update/1
{
"script" : "ctx._source.remove('new_field')"
}
次のスクリプトはオブジェクトフィールドからサブフィールドを削除します:
Python
resp = client.update(
index="test",
id="1",
script="ctx._source['my-object'].remove('my-subfield')",
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: "ctx._source['my-object'].remove('my-subfield')"
}
)
puts response
Js
const response = await client.update({
index: "test",
id: 1,
script: "ctx._source['my-object'].remove('my-subfield')",
});
console.log(response);
Console
POST test/_update/1
{
"script": "ctx._source['my-object'].remove('my-subfield')"
}
ドキュメントを更新する代わりに、スクリプト内で実行される操作を変更することもできます。たとえば、このリクエストはtags
フィールドがgreen
を含む場合にドキュメントを削除し、それ以外の場合は何もしません(noop
):
Python
resp = client.update(
index="test",
id="1",
script={
"source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
"lang": "painless",
"params": {
"tag": "green"
}
},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: {
source: "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
lang: 'painless',
params: {
tag: 'green'
}
}
}
)
puts response
Js
const response = await client.update({
index: "test",
id: 1,
script: {
source:
"if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
lang: "painless",
params: {
tag: "green",
},
},
});
console.log(response);
Console
POST test/_update/1
{
"script": {
"source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'noop' }",
"lang": "painless",
"params": {
"tag": "green"
}
}
}
Update part of a document
次の部分的な更新は、既存のドキュメントに新しいフィールドを追加します:
Python
resp = client.update(
index="test",
id="1",
doc={
"name": "new_name"
},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
doc: {
name: 'new_name'
}
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"doc": {
"name": "new_name"
}
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
doc: {
name: "new_name",
},
});
console.log(response);
Console
POST test/_update/1
{
"doc": {
"name": "new_name"
}
}
### Detect noop updates
デフォルトでは、何も変更しない更新は、何も変更しないことを検出し、`````"result": "noop"`````を返します:
#### Python
``````python
resp = client.update(
index="test",
id="1",
doc={
"name": "new_name"
},
)
print(resp)
`
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
doc: {
name: 'new_name'
}
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"doc": {
"name": "new_name"
}
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
doc: {
name: "new_name",
},
});
console.log(response);
Console
POST test/_update/1
{
"doc": {
"name": "new_name"
}
}
[](#431214115cc3e3677d1ab0cd25950fee)
#### Console-Result
``````console-result
{
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
},
"_index": "test",
"_id": "1",
"_version": 2,
"_primary_term": 1,
"_seq_no": 1,
"result": "noop"
}
`
この動作を無効にするには、"detect_noop": false
を設定します:
Python
resp = client.update(
index="test",
id="1",
doc={
"name": "new_name"
},
detect_noop=False,
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
doc: {
name: 'new_name'
},
detect_noop: false
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"doc": {
"name": "new_name"
},
"detect_noop": false
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
doc: {
name: "new_name",
},
detect_noop: false,
});
console.log(response);
Console
POST test/_update/1
{
"doc": {
"name": "new_name"
},
"detect_noop": false
}
Upsert
ドキュメントがすでに存在しない場合、upsert
要素の内容が新しいドキュメントとして挿入されます。ドキュメントが存在する場合、script
が実行されます:
Python
resp = client.update(
index="test",
id="1",
script={
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 4
}
},
upsert={
"counter": 1
},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
script: {
source: 'ctx._source.counter += params.count',
lang: 'painless',
params: {
count: 4
}
},
upsert: {
counter: 1
}
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"script": {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 4
}
},
"upsert": {
"counter": 1
}
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
script: {
source: "ctx._source.counter += params.count",
lang: "painless",
params: {
count: 4,
},
},
upsert: {
counter: 1,
},
});
console.log(response);
Console
POST test/_update/1
{
"script": {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params": {
"count": 4
}
},
"upsert": {
"counter": 1
}
}
Scripted upsert
ドキュメントが存在するかどうかにかかわらずスクリプトを実行するには、scripted_upsert
をtrue
に設定します:
Python
resp = client.update(
index="test",
id="1",
scripted_upsert=True,
script={
"source": "\n if ( ctx.op == 'create' ) {\n ctx._source.counter = params.count\n } else {\n ctx._source.counter += params.count\n }\n ",
"params": {
"count": 4
}
},
upsert={},
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
scripted_upsert: true,
script: {
source: "\n if ( ctx.op == 'create' ) {\n ctx._source.counter = params.count\n } else {\n ctx._source.counter += params.count\n }\n ",
params: {
count: 4
}
},
upsert: {}
}
)
puts response
Js
const response = await client.update({
index: "test",
id: 1,
scripted_upsert: true,
script: {
source:
"\n if ( ctx.op == 'create' ) {\n ctx._source.counter = params.count\n } else {\n ctx._source.counter += params.count\n }\n ",
params: {
count: 4,
},
},
upsert: {},
});
console.log(response);
Console
POST test/_update/1
{
"scripted_upsert": true,
"script": {
"source": """
if ( ctx.op == 'create' ) {
ctx._source.counter = params.count
} else {
ctx._source.counter += params.count
}
""",
"params": {
"count": 4
}
},
"upsert": {}
}
Doc as upsert
部分的なdoc
とupsert
ドキュメントを送信する代わりに、doc_as_upsert
をtrue
に設定してdoc
の内容をupsert
値として使用できます:
Python
resp = client.update(
index="test",
id="1",
doc={
"name": "new_name"
},
doc_as_upsert=True,
)
print(resp)
Ruby
response = client.update(
index: 'test',
id: 1,
body: {
doc: {
name: 'new_name'
},
doc_as_upsert: true
}
)
puts response
Go
res, err := es.Update(
"test",
"1",
strings.NewReader(`{
"doc": {
"name": "new_name"
},
"doc_as_upsert": true
}`),
es.Update.WithPretty(),
)
fmt.Println(res, err)
Js
const response = await client.update({
index: "test",
id: 1,
doc: {
name: "new_name",
},
doc_as_upsert: true,
});
console.log(response);
Console
POST test/_update/1
{
"doc": {
"name": "new_name"
},
"doc_as_upsert": true
}
doc_as_upsert
を使用した[インジェストパイプライン]はサポートされていません。