在Luigi的任务之间传递Python对象?

时间:2017-02-28 17:45:51

标签: python python-3.6 luigi

我使用Spotify's Luigi在Python 3.6中编写我的第一个项目,以便在管道中安排一些自然语言处理任务。

我注意到output()类的Task函数总是返回某种Target对象,它只是某个文件,无论是本地还是远程。因为我的任务会产生更复杂的数据结构,比如解析树,所以将它们作为字符串写入文件并在之后再次读取它是非常尴尬的。

因此,我想询问是否有可能在管道中的任务之间传递Python对象?

2 个答案:

答案 0 :(得分:14)

简短回答:不。

Luigi参数仅限于date / datetime对象,string,int和float。请参阅docs for reference

这意味着您需要将复杂数据结构序列化为字符串(使用json,msgpack,无论您喜欢什么序列化程序,甚至压缩它)并将其作为字符串参数传递。

当然,您可以编写自定义参数子类,但基本上需要实现serialize and parse methods

但请注意:如果您使用参数而不是将计算数据保存到目标,那么您将失去使用Luigi的一个关键优势:如果树中的父任务失败超过您指定的重试次数,然后你需要运行再次计算复杂数据结构的任务。如果您的任务计算复杂数据或花费大量时间或消耗大量资源,那么您应该将输出保存为目标,以便不必再次进行所有昂贵的计算。

超越:另一项任务也可能需要这些数据,为什么不保存呢?

另外,请注意目标不仅是文件:您可以将数据保存到数据库表,Redis,Hadoop,弹性搜索索引等等:http://luigi.readthedocs.io/en/stable/api/luigi.contrib.html#submodules

答案 1 :(得分:1)

还有其他方法(仍然有点怪异)可以实现您要使用目标而不是参数来完成的工作。

luigi.mock中有一个特殊的MockFile目标,可用于将其“文件”存储在内存中。

它的api与其他Target继承类相似,因此您必须openreadwrite使用它。突然,它仅支持string输入,因此您仍然需要序列化对象(这是由于通过进程之间的管道发送此数据)。请参见以下示例(yaml序列化):

import yaml
from luigi import Task

class TaskA(Task):
    def output(self):
        return MockFile('whatever')

    def run(self):
        object_to_send = yaml.dump({"example": "dict"})

        _out = self.output().open('r')
        _out.write(object_to_send)
        _out.close()


class TaskB(Task):
    def requires(self):
        return TaskA()

    def run(self):
        _in = self.input().read('r')
        serialised = _in.read()
        deserialised = yaml.load(serialised)
        print(deserialised)

请注意,序列化大对象可能会花费很多时间。