在Elasticsearch的Painless脚本中比较两个JSON对象数组
Elasticsearch Painless脚本:筛选数组A独有的JSON对象
你之前代码的问题
- 不可修改列表限制:
Arrays.asList()返回的是固定大小的列表,不支持removeAll()这类修改操作,调用会直接抛出UnsupportedOperationException。 - 对象比较逻辑错误:Painless中JSON对象以
Map类型存储,默认的引用比较无法识别内容相同但引用不同的对象,removeAll()根本没法匹配到要移除的元素。
正确实现方式
方式1:生成新数组C(保留原数组A)
将数组A转为可修改的ArrayList,遍历数组B,根据对象的唯一标识字段(比如示例中的key)匹配并移除元素,最后转为数组赋值给C:
// 将A转为可修改的ArrayList ArrayList<Map> listA = new ArrayList<>(Arrays.asList(ctx.payload.A)); // 遍历B中的每个对象,移除listA中内容匹配的元素 for (Map bObj : ctx.payload.B) { Iterator<Map> iterator = listA.iterator(); while (iterator.hasNext()) { Map aObj = iterator.next(); // 按对象的唯一标识字段匹配,示例用"key",可根据实际需求修改 if (aObj.get("key").equals(bObj.get("key"))) { iterator.remove(); break; // 假设每个标识唯一,找到匹配项后跳出循环 } } } // 将处理后的列表转为数组,赋值给C ctx.payload.C = listA.toArray(new Map[0]);
方式2:直接修改原数组A
如果不需要保留原数组A的内容,可直接将处理后的列表赋值回A:
ArrayList<Map> listA = new ArrayList<>(Arrays.asList(ctx.payload.A)); for (Map bObj : ctx.payload.B) { Iterator<Map> iterator = listA.iterator(); while (iterator.hasNext()) { Map aObj = iterator.next(); if (aObj.get("key").equals(bObj.get("key"))) { iterator.remove(); break; } } } // 覆盖原数组A ctx.payload.A = listA.toArray(new Map[0]);
注意事项
- 如果JSON对象的唯一标识是多个字段,需要扩展匹配条件,比如:
if (aObj.get("key").equals(bObj.get("key")) && aObj.get("type").equals(bObj.get("type"))) - 必须使用
Iterator的remove()方法,避免遍历过程中修改集合引发ConcurrentModificationException。 - 不要直接使用
Arrays.asList()生成的列表执行修改操作,必须转为ArrayList这类支持修改的集合类型。
内容的提问来源于stack exchange,提问作者Space_walker
相关产品推荐
相关产品推荐

