Elasticsearch Groovy Script用于生成嵌套字段的语法

时间:2015-12-29 13:53:09

标签: python python-2.7 elasticsearch groovy

下面简单的ES Groovy脚本使用带有订单数据的python字典(orderItem)并将其附加到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'on null object]

那么,首先创建Orders字段的正确groovy语法是什么,然后是商店名称的字段然后将orderItems附加到那个?

更新:完整的python函数(不工作)

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)

1 个答案:

答案 0 :(得分:1)

我认为最初你的_source.Orders字段为空,即使不是空数组。

此外,containsKey可能不是正确的方法,因为您的_source可能包含名为Orders的字段,其类型可能不是数组,即它可能是动态的对象代表现有订单,或者更糟糕的是,只是一个普通的字符串。

我建议您首先检查Orders是否为null,然后将其初始化为空数组,尝试不同的方法。然后,您可以将orderItem附加到生成的数组:

{
  "script" : "ctx._source.Orders = ((ctx._source.Orders ?: []) += orderItem)",
  "params" : {
    "orderItem" : orderItem
  }      
}

另一种方法是简单地确保在第一次索引文档时,确保使用空数组Orders初始化[]字段,然后您的脚本可以简单将orderItems附加到该数组。

<强>更新

根据您的评论,我正在修改我的答案,以便处理Orders是包含商店名称作为键的动态对象并且每个键指向一系列订单的情况那个店。它与之前的想法基本相同,只是我们需要再处理一个级别(即商店名称)。

首先,脚本确保Orders对象存在,然后确保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()
  }      
}