如何加载每个Spark执行器中无法腌制的数据?

时间:2016-02-19 07:58:56

标签: python apache-spark pyspark google-cloud-dataproc

我使用的是用Cython编写的NoAho library。它的内部特里cannot be pickled:如果我在主节点上加载它,我永远不会为在worker中执行的操作获得匹配。

由于我想在每个Spark执行器中使用相同的trie,我找到了一种方法来加载trie懒惰,受到spaCy on Spark issue的启发。

global trie

def get_match(text):
    # 1. Load trie if needed
    global trie
    try:
        trie
    except NameError:
        from noaho import NoAho

        trie = NoAho()
        trie.add(key_text='ms windows', payload='Windows 2000')
        trie.add(key_text='ms windows 2000', payload='Windows 2000')
        trie.add(key_text='windows 2k', payload='Windows 2000')
        ...

    # 2. Find an actual match to get they payload back
    return trie.findall_long(text)

虽然这样可行,但每个Spark作业都会执行所有.add()次调用,大约需要一分钟。因为我不确定" Spark工作"是正确的术语,我会更明确:我在Jupyter笔记本中使用Spark,每次运行需要get_match()函数的单元格时,trie都不会被缓存,需要一分钟才能加载试图占据了运行时间。

我能做些什么来确保trie被缓存?或者我的问题有更好的解决方案吗?

1 个答案:

答案 0 :(得分:1)

您可以尝试的一件事是使用单例模块加载和初始化trie。基本上你只需要一个单独的模块,如下所示:

  • trie_loader.py

    from noaho import NoAho
    
    def load():
        trie = NoAho()
        trie.add('ms windows', 'Windows 2000')
        trie.add('ms windows 2000', 'Windows 2000')
        trie.add('windows 2k', 'Windows 2000')
        return trie
    
    trie  = load()
    

使用标准的Spark工具分发它:

sc.addPyFile("trie_loader.py")
import trie_loader

rdd = sc.parallelize(["ms windows", "Debian GNU/Linux"])
rdd.map(lambda x: (x, trie_loader.trie.find_long(x))).collect()
## [('ms windows', (0, 10, 'Windows 2000')),
##  ('Debian GNU/Linux', (None, None, None))]

这应该在每次启动Python进程执行器时加载所需的数据,而不是在访问数据时加载它。我不确定它是否可以帮到这里,但值得一试。