elasticsearch node.js API 使用无痛脚本从文档中的数组中删除对象导致数组索引超出范围
elasticsearch node.js API remove an object from an array on a document using painless script results in array Index Out of Bounds
我想从 elasticsearch 文档的数组中删除项目(一个对象),但是每当我尝试 运行 我的更新脚本使用 painless 时,我都会收到数组索引越界异常。
我正在使用 javascript elasticsearch npm package 在 elasticsearch 中搜索相关文档,然后 returns 我的数据如下:
"_index": "centres",
"_type": "doc",
"_id": "51bc77d1-b514-4f4e-85fa-412def6829f5",
"_score": 1,
"_source": {
"id": "cbaa7daa-f1a2-4ac3-8d7c-fc981245d21c",
"name": "Five House",
"openDays": [
{
"title": "new open Day",
"endDate": "2022-03-22T00:00:00.000Z",
"id": "82be934b-eeb1-419c-96ed-a58808b30df7"
},
{
"title": "last open Day",
"endDate": "2020-12-24T00:00:00.000Z",
"id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
]
}
然后我想遍历并从 openDays
数组中删除某些项目。我已经创建了一个要删除的项目数组,因此对于上面的示例:
[
{
id: '51bc77d1-b514-4f4e-85fa-412def6829f5',
indexes: [
{
"title": "last open Day",
"endDate": "2020-12-24T00:00:00.000Z",
"id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
]
}
]
然后我尝试 运行 通过 elasticsearch 节点客户端进行更新,如下所示:
for (const centre of updates) {
if (centre.indexes.length) {
await Promise.all(centre.indexes.map(async (theIndex) => {
const updated = await client.update({
index: 'centres',
type: 'doc',
id: centre.id,
body: {
script: {
lang: 'painless',
source: "ctx._source.openDays.remove(ctx._source.openDays.indexOf('openDayID'))",
params: {
"openDayID": theIndex.id
}
}
}
}).catch((err) => {throw err;});
}))
.catch((err) => {throw err;});
await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
}
}
当我 运行 虽然如此时,它 returns 一个 400 错误“array_index_out_of_bounds_exception”:
-> POST http://localhost:9200/centres/doc/51bc77d1-b514-4f4e-85fa-412def6829f5/_update
{
"script": {
"lang": "painless",
"source": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
"params": {
"openDayID": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
}
}
<- 400
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[oSsa7mn][172.17.0.2:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [],
"script": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
"lang": "painless",
"caused_by": {
"type": "array_index_out_of_bounds_exception",
"reason": null
}
}
},
"status": 400
}
我不太确定哪里出了问题。我是否正确使用了 indexOf
无痛脚本? indexOf 是否允许搜索数组中对象的属性?
我偶然发现了这个问题和答案:Elasticsearch: Get object index with Painless script
更新脚本的主体需要像这样更改:
Promise.all(...
const inline = `
def openDayID = '${theIndex.id}';
def openDays = ctx._source.openDays;
def openDayIndex = -1;
for (int i = 0; i < openDays.length; i++)
{
if (openDays[i].id == openDayID)
{
openDayIndex = i;
}
}
if (openDayIndex != -1) {
ctx._source.openDays.remove(openDayIndex);
}
`;
const updated = await client.update({
index: 'centres',
type: 'doc',
id: centre.id,
body: {
script: {
lang: 'painless',
inline: inline,
},
}
}).catch((err) => {throw err;});
await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
})).catch(... //end of Promise.all
我不熟悉无痛脚本,所以很可能有更好的编写方法,例如一旦找到 ID 的索引就会中断。
我还必须将刷新语句移到 Promise.all
中,因为如果您尝试从对象数组中删除多个项目,您将更改文档并更改索引.可能还有更好的方法来处理这个问题。
'openDayID' 应该是 params.openDayID
并使用 removeIf:
"ctx._source.openDays.removeIf(el -> (el.id == params.openDayID))"
我想从 elasticsearch 文档的数组中删除项目(一个对象),但是每当我尝试 运行 我的更新脚本使用 painless 时,我都会收到数组索引越界异常。
我正在使用 javascript elasticsearch npm package 在 elasticsearch 中搜索相关文档,然后 returns 我的数据如下:
"_index": "centres",
"_type": "doc",
"_id": "51bc77d1-b514-4f4e-85fa-412def6829f5",
"_score": 1,
"_source": {
"id": "cbaa7daa-f1a2-4ac3-8d7c-fc981245d21c",
"name": "Five House",
"openDays": [
{
"title": "new open Day",
"endDate": "2022-03-22T00:00:00.000Z",
"id": "82be934b-eeb1-419c-96ed-a58808b30df7"
},
{
"title": "last open Day",
"endDate": "2020-12-24T00:00:00.000Z",
"id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
]
}
然后我想遍历并从 openDays
数组中删除某些项目。我已经创建了一个要删除的项目数组,因此对于上面的示例:
[
{
id: '51bc77d1-b514-4f4e-85fa-412def6829f5',
indexes: [
{
"title": "last open Day",
"endDate": "2020-12-24T00:00:00.000Z",
"id": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
]
}
]
然后我尝试 运行 通过 elasticsearch 节点客户端进行更新,如下所示:
for (const centre of updates) {
if (centre.indexes.length) {
await Promise.all(centre.indexes.map(async (theIndex) => {
const updated = await client.update({
index: 'centres',
type: 'doc',
id: centre.id,
body: {
script: {
lang: 'painless',
source: "ctx._source.openDays.remove(ctx._source.openDays.indexOf('openDayID'))",
params: {
"openDayID": theIndex.id
}
}
}
}).catch((err) => {throw err;});
}))
.catch((err) => {throw err;});
await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
}
}
当我 运行 虽然如此时,它 returns 一个 400 错误“array_index_out_of_bounds_exception”:
-> POST http://localhost:9200/centres/doc/51bc77d1-b514-4f4e-85fa-412def6829f5/_update
{
"script": {
"lang": "painless",
"source": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
"params": {
"openDayID": "8cc339b9-d2f8-4252-b68a-ed0a49cbfabd"
}
}
}
<- 400
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[oSsa7mn][172.17.0.2:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "runtime error",
"script_stack": [],
"script": "ctx._source.openDays.remove(ctx._source.openDays.indexOf(\u0027openDayID\u0027))",
"lang": "painless",
"caused_by": {
"type": "array_index_out_of_bounds_exception",
"reason": null
}
}
},
"status": 400
}
我不太确定哪里出了问题。我是否正确使用了 indexOf
无痛脚本? indexOf 是否允许搜索数组中对象的属性?
我偶然发现了这个问题和答案:Elasticsearch: Get object index with Painless script
更新脚本的主体需要像这样更改:
Promise.all(...
const inline = `
def openDayID = '${theIndex.id}';
def openDays = ctx._source.openDays;
def openDayIndex = -1;
for (int i = 0; i < openDays.length; i++)
{
if (openDays[i].id == openDayID)
{
openDayIndex = i;
}
}
if (openDayIndex != -1) {
ctx._source.openDays.remove(openDayIndex);
}
`;
const updated = await client.update({
index: 'centres',
type: 'doc',
id: centre.id,
body: {
script: {
lang: 'painless',
inline: inline,
},
}
}).catch((err) => {throw err;});
await client.indices.refresh({ index: 'centres' }).catch((err) => { throw err;});
})).catch(... //end of Promise.all
我不熟悉无痛脚本,所以很可能有更好的编写方法,例如一旦找到 ID 的索引就会中断。
我还必须将刷新语句移到 Promise.all
中,因为如果您尝试从对象数组中删除多个项目,您将更改文档并更改索引.可能还有更好的方法来处理这个问题。
'openDayID' 应该是 params.openDayID
并使用 removeIf:
"ctx._source.openDays.removeIf(el -> (el.id == params.openDayID))"