1

我正在使用用 Cython 编写的NoAho 库。它的内部 trie不能被腌制:如果我将它加载到主节点上,我永远不会得到在 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)

虽然这可行,但所有.add()调用都会针对每个 Spark 作业执行,这大约需要一分钟。因为我不确定“Spark 作业”是正确的术语,所以我会更明确一点:我在 Jupyter 笔记本中使用 Spark,每次运行需要该get_match()功能的单元时,trie 永远不会被缓存并且需要一个分钟来加载尝试,这在运行时间中占主导地位。

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

4

1 回答 1

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 进程执行器时加载所需的数据,而不是在访问数据时加载它。我不确定它是否可以在这里提供帮助,但值得一试。

于 2016-02-19T12:55:09.787 回答