用于生成嵌套字段的弹性搜索Groovy脚本语法 [英] Elasticsearch Groovy Script Syntax for generation of nested fields

查看:204
本文介绍了用于生成嵌套字段的弹性搜索Groovy脚本语法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下简单的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 named Orders 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 the orderItem 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 append orderItems 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 the Orders object exists as well. All that remains to do is to append the orderItem 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屋!

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