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

查看:110
本文介绍了elasticsearch node.js API使用无痛脚本从文档上的数组中删除对象会导致数组索引超出范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Elasticsearch中从文档上的数组中删除项目(对象),但是,每当我尝试使用无痛操作运行更新脚本时,都会收到数组索引越界"异常.

I want to remove items (an object) from an array on a document in elasticsearch, however whenever I try and run my update script using painless, I receive an Array Index Out of Bounds exception.

我正在使用javascript elasticsearch npm包在elasticsearch中搜索相关文档,然后向我返回数据,例如:

I'm using the javascript elasticsearch npm package to search elasticsearch for the relevant documents which then returns me data like:

"_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 数组中删除某些项目.我已经创建了要删除的项目的数组,因此对于上面的示例:

I then want to go through and remove certain items from the openDays array. I've created an array of the items I want to remove, so for the above example:

[
  {
    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节点客户端运行更新:

I'm then trying to run an update via the elasticsearch node client like this:

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;});
    }
}

不过,当我运行此代码时,它会返回一个带有"array_index_out_of_bounds_exception"的400.错误:

When I run this though, it returns a 400 with an "array_index_out_of_bounds_exception" error:

  -> 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是否允许搜索数组中对象的属性?

I'm not quite sure where I'm going wrong with this. Am I using the indexOf painless script correctly? Does indexOf allow for the searching of properties on objects in arrays?

推荐答案

我偶然发现了以下问题:

I stumbled across this question and answer: Elasticsearch: Get object index with Painless script

更新脚本的主体需要像这样更改:

The body of the update script needs changing like so:

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的索引,索引就会中断.

I am not au fait with painless scripting, so there are most likely better ways of writing this e.g. breaking once the index of the ID is found.

我还必须将刷新语句移到 Promise.all 中,因为如果您要从对象数组中删除多个项,则将更改文档并更改索引.也许还有更好的方法来解决这个问题.

I have also had to move the refresh statement into the Promise.all since if you're trying to remove more than one item from the array of objects, you'll be changing the document and changing the index. There is probably a better way of dealing with this too.

这篇关于elasticsearch node.js API使用无痛脚本从文档上的数组中删除对象会导致数组索引超出范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆