我使用的是用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被缓存?或者我的问题有更好的解决方案吗?
答案 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进程执行器时加载所需的数据,而不是在访问数据时加载它。我不确定它是否可以帮到这里,但值得一试。