用于生成嵌套字段的弹性搜索Groovy脚本语法 [英] Elasticsearch Groovy Script Syntax for generation of nested fields
问题描述
以下简单的ES Groovy脚本使用带有订单数据(orderItem)的python字典,并将其附加到Elasticsearch中的订单列表中。所有orderItems的列表然后驻留在_source.Orders
script:if(ctx._source.containsKey(\ Orders \)){ctx._source.Orders + = orderItem;} else {ctx._source.Orders = [orderItem]};
params:{orderItem:orderItem}
在我的用例中,订单来自不同的商店,希望他们进入_source.Orders下的列表结构.Shop5Hgk,_source.Orders.Shop86hG,_source.Orders.Shop5G60等商店名称是动态的。
无论如何,我尝试,ES抛出异常抱怨订单显然是空的。
GroovyScriptExecutionException [NullPointerException [无法设置
属性'零对象上的Shop5Hgk']
<因此,首先创建订单字段的正确格式是什么,然后是商店名称的字段,然后将orderItem附加到该元素?
更新:完整的python函数(不工作)
def updateLastOrdersElasticsearch(self,data):
es = elasticsearch.Elasticsearch(timeout = 500)
actions = []
for shopName,orderList in data.items ):
在orderList中的orderItem
sku = orderItem ['SKU']
action = {
_index:myindex,
script if(ctx._source.containsKey(\Orders\)){if(ctx._source.containsKey(shopName)){ctx._source.Orders。+ shopName ++ = Orders;}} else {ctx ._source.Orders = []; ctx._source.Orders。+ sh opName += [Orders]}; ctx._source.TimestampUpdated = TimestampUpdated,
_type:items,
'_op_type':'update',
_id:sku,
params :{shopName:shopName,Orders:orderItem,TimestampUpdated:datetime.now()。isoformat()}
}
actions.append(action)
return helpers。批量(es,action)
解决方案
_source.Orders
字段为空,即不是空数组。
此外,
containsKey
可能不是正确的方式,因为您的_source
可能包含一个名为Orders
其类型可能不是数组,即它可能是代表现有订单的动态对象,或者更糟的是,只是一个简单的字符串。
我建议您尝试首先检查
Orders
是否为空,并将其初始化为一个不同的方法y数组如果没有,那么你可以将orderItem
附加到结果数组中:script:ctx._source.Orders =((ctx._source.Orders?:[])+ = orderItem),
params:{
orderItem:orderItem
}
}
要确保在首次索引文档时,请确保
Orders
字段用空数组初始化[]
然后您的脚本可以将orderItems
附加到该数组。
更新
根据您的意见,我正在修改我的答案,以处理
订单
是一个动态对象,其中包含商店名称作为键,并且每个键指向该商店的一系列订单。基本上是和以前一样的想法,只是我们需要处理一个级别(即店铺名称)。
首先脚本确保
订单
对象存在,然后确保Orders
对象中的商店数组也存在。所有仍然要做的是将orderItem
附加到商店阵列中:{
script:ctx._source.Orders = ctx._source.Orders?:[shopName:'']; ctx._source.Orders [shopName] =((ctx._source.Orders [shopName ]?:[])+ orderItem); ctx._source.TimestampUpdated = TimestampUpdated,
params:{
shopName:shopName,
orderItem:orderItem,
TimestampUpdated:datetime.now()。isoformat()
}
}
The below simple ES Groovy script takes a python dictionary with order data (orderItem) and appends it to a list of orders within Elasticsearch. The list with all orderItems then resides under _source.Orders
"script": "if (ctx._source.containsKey(\"Orders\")) {ctx._source.Orders += orderItem;} else {ctx._source.Orders = [orderItem]}; " "params":{"orderItem": orderItem}
In my use case, orders come from different shops and want them to go in to a list structure under _source.Orders.Shop5Hgk, _source.Orders.Shop86hG, _source.Orders.Shop5G60, etc. The shop names are dynamic.
No matter, what I try, ES throws exceptions complaining that Orders obviously is null.
GroovyScriptExecutionException[NullPointerException[Cannot set property 'Shop5Hgk' on null object]
So, what is the right groovy syntax to create the Orders field first, and then the field for the shop name and then append orderItems to that?
Update: Full python function with (not working)
def updateLastOrdersElasticsearch(self,data): es = elasticsearch.Elasticsearch(timeout=500) actions = [] for shopName,orderList in data.items(): for orderItem in orderList: sku = orderItem['SKU'] action = { "_index": "myindex", "script": "if (ctx._source.containsKey(\"Orders\")) {if (ctx._source.containsKey(shopName)){ctx._source.Orders."+shopName+" += Orders;}} else {ctx._source.Orders = []; ctx._source.Orders."+shopName+" = [Orders]}; ctx._source.TimestampUpdated = TimestampUpdated", "_type": "items", '_op_type': 'update', "_id": sku, "params":{"shopName":shopName,"Orders": orderItem, "TimestampUpdated":datetime.now().isoformat()} } actions.append(action) return helpers.bulk(es, actions)
解决方案I think that initially your
_source.Orders
field is null, i.e. not even an empty array.Moreover,
containsKey
might not be the right way to go, because your_source
might contain a field namedOrders
whose type might not be an array, i.e. it might be a dynamic object standing for an existing order, or worse, just a plain string.I suggest you try a different approach by first checking if
Orders
is null and initialize it to an empty array if not. Then you can append theorderItem
to the resulting array:{ "script" : "ctx._source.Orders = ((ctx._source.Orders ?: []) += orderItem)", "params" : { "orderItem" : orderItem } }
An alternative to this would be to simply ensure that when you index your document the first time, you make sure that the
Orders
field is initialized with an empty array[]
and then your script could simply appendorderItems
to that array.UPDATE
Based on your comments, I'm revising my answer in order to deal with the case where
Orders
is a dynamic object containing shop names as keys and each of those keys points to an array of orders for that shop. It's basically the same idea as earlier, just that we need to deal with one more level (i.e. the shop names).First the script makes sure that the
Orders
object exists and then it makes sure that the shop array within theOrders
object exists as well. All that remains to do is to append theorderItem
to the shop array:{ "script" : "ctx._source.Orders = ctx._source.Orders ?: [shopName:'']; ctx._source.Orders[shopName] = ((ctx._source.Orders[shopName] ?: []) + orderItem); ctx._source.TimestampUpdated = TimestampUpdated", "params" : { "shopName": shopName, "orderItem" : orderItem, "TimestampUpdated":datetime.now().isoformat() } }
这篇关于用于生成嵌套字段的弹性搜索Groovy脚本语法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!