Luigi灵活的管道和传递参数一直通过

时间:2017-10-06 19:12:31

标签: python pipeline luigi

我最近实施了一条luigi管道来处理我们的一条生物信息管道。但是,关于如何设置这些我无法掌握的任务,还有一些基础。

我们说我已经拥有了三个任务链,我希望能够与多个工作人员一起运行。例如,三个工作人员的依赖关系图可能如下所示:

/ taskC - > taskB - >任务A - taskC - > taskB - >任务A \ taskC - > taskB - >任务A

我可能会写

class entry(luigi.Task):

    in_dir = luigi.Parameter()

    def requires(self):
        for f in self.in_dir:
            yield taskC(pass_through=f)

    def run(self):
        some logic using self.input().path
        from each worker in the above yield

class taskA(luigi.Task):

    in_file_A = luigi.Parameter()

    def output(self):
        return luigi.LocalTarget('outA.txt')

    def run(self):
        some logic generating outA.txt

class taskB(luigi.Task):

    pass_through = luigi.Parameter()

    def output(self):
        return luigi.LocalTarget('outB.txt')

    def requires(self):
        return taskA(in_file_A=self.pass_through)

    def run(self):
        some logic using self.input().path [outA.txt] 
        and generating self.output().path [outB.txt]

class taskC(luigi.Task):

    pass_through = luigi.Parameter()

    def output(self):
        return luigi.LocalTarget('outC.txt')

    def requires(self):
        return taskB(pass_through=self.pass_through)

    def run(self):
        some logic using self.input().path [outB.txt] 
        and generating self.output().path [outC.txt]

如果我的代码位于pipeline.py,我可以使用以下代码启动:

luigi --module pipeline entry --workers 3 --in-dir some_dir_w_input_files/

我将参数pass_through一直发送到taskA这一事实并不是一种正确的做法。此外,如果将来某个时候我已经taskA生成(单独)数据,taskB不够灵活,无法处理这种情况。也许我可以写:

class taskB(luigi.Task):

    in_file_B = luigi.Parameter() # if we already have the output of taskA
    pass_through = luigi.Parameter() # if we require taskA

    def output(self):
        return luigi.LocalTarget('outB.txt')

    def requires(self):
        if self.pass_through:
            return taskA(in_file_A=self.pass_through)

    def run(self):
        if self.input().path:
           logic_input = self.input().path
        else:
           logic_input = self.in_file_B

        some logic using 'logic_input'
        and generating self.output().path [outB.txt]

我想知道这是否适当' Luigi的设计模式,或者如果我完全偏离基础。

1 个答案:

答案 0 :(得分:0)

我认为这很大程度上是你在这里抽象任务的一件神器,在现实世界中,你可能需要知道每个你正在阅读/写作的地方。例如见:

class DecompressTask(luigi.Task):
    dirname = luigi.Parameter()
    filename = luigi.Parameter()

    def output(self):
        return luigi.LocalTarget(os.path.join(self.dirname , self.filename + ".txt"))

    def run(self):
        decompress(os.path.join(self.dirname, self.filename + ".gz"),
                   os.path.join(self.dirname, self.filename + ".txt"))


class TranslateTask(luigi.Task):
    dirname = luigi.Parameter()
    filename = luigi.Parameter()

    def requires(self):
        return DecompressTask(dirname=self.dirname, filename=self.filename)

    def output(self):
        return luigi.LocalTarget(os.path.join(self.dirname + self.filename + ".translated"))

    def run(self):
        translate(os.path.join(self.dirname, self.filename + ".txt"),
                  os.path.join(self.dirname, self.filename + ".translated"))


class ProcessDirectory(luigi.WrapperTask):
    dirname = luigi.Parameter()

    def requires(self):
        tasks = []
        for file_name in os.listdir(self.dirname):
            if file_name.endswith("gz"):
                prefix = file_name.split(".")[0]
                tasks.append(TranslateTask(filename=prefix, dirname=self.dirname))
        return tasks