【问题标题】:Elasticsearch Groovy Script Syntax for generation of nested fields用于生成嵌套字段的 Elasticsearch Groovy 脚本语法
【发布时间】:2016-04-03 10:08:32
【问题描述】:

以下简单的 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 都会抛出异常,抱怨 Orders 显然是空的。

GroovyScriptExecutionException[NullPointerException[无法设置 空对象上的属性“Shop5Hgk”]

那么,首先创建 Orders 字段,然后是商店名称字段,然后将 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)

【问题讨论】:

    标签: python python-2.7 elasticsearch groovy


    【解决方案1】:

    我认为最初您的 _source.Orders 字段为空,即甚至不是空数组。

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

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

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

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

    更新

    根据您的 cmets,我正在修改我的答案以处理 Orders 是包含商店名称作为键的动态对象并且每个键都指向该商店的一系列订单的情况。和之前的思路基本一样,只是我们需要多处理一层(即店铺名称)。

    首先,脚本确保Orders 对象存在,然后确保Orders 对象中的商店数组也存在。剩下要做的就是将 orderItem 附加到 shop 数组中:

    {
      "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()
      }      
    }
    

    【讨论】:

    • 您的解决方案是指在问题开头截断的(工作)代码。我正在寻找一种解决方案,它允许将商店名称另外添加到 Orders 并附加 orderItems“商店名称”列表。
    • 好吧,这与您最初的问题陈述有点不同。所以Orders 不是一个数组而是一个动态对象,其键是店铺名称,每个店铺名称都包含一个订单数组,对吧?
    • 好的,你能不能至少确保Orders首先被初始化为一个空列表,这样我们就不需要在脚本中处理它了?
    • 试图在我更新的 python 代码示例中做到这一点。见上文
    • 不,我的意思是当您第一次在 Elasticsearch 中创建文档时,即根本没有订单时。你能确定Orders: {}在你创建文档的时候吗?
    猜你喜欢
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多