使用Word2VecModel.transform()在map函数中无法正常工作。

8 浏览
0 Comments

使用Word2VecModel.transform()在map函数中无法正常工作。

我已经使用Spark构建了一个Word2Vec模型,并将其保存为模型。现在,我想在另一个离线模型的代码中使用它。我已经加载了模型,并使用它来表示一个单词(例如Hello)的向量,它工作得很好。但是,我需要在一个RDD中使用map调用它来处理许多单词。

当我在map函数中调用model.transform()时,它抛出以下错误:

“看起来您正在尝试从广播变量、操作或转换中引用SparkContext。”

异常:似乎您正在尝试从广播变量、操作或转换中引用SparkContext。SparkContext只能在驱动程序上使用,不能在在工作节点上运行的代码中使用。有关更多信息,请参见SPARK-5063。

代码如下:

from pyspark import SparkContext
from pyspark.mllib.feature import Word2Vec
from pyspark.mllib.feature import Word2VecModel
sc = SparkContext('local[4]',appName='Word2Vec')
model=Word2VecModel.load(sc, "word2vecModel")
x= model.transform("Hello")
print(x[0]) # 这个工作正常,返回[0.234, 0.800,....]
y=sc.parallelize([['Hello'],['test']])
y.map(lambda w: model.transform(w[0])).collect() # 这里抛出错误

非常感谢您的帮助。

0
0 Comments

问题的原因是由于Py4J网关在worker节点上不可访问,所以无法在map函数中调用Java/Scala方法。由于这个原因,Word2VecModel.transform()方法在map函数中无法正常工作。

解决方法是可以尝试将JavaMap对象转换为Python字典,但是这种方法效率极低。另一种方法是将模型保存为DataFrame,然后通过join操作将单词映射为向量。如果数据可以适应驱动程序/工作节点的内存,可以尝试使用broadcast来收集和映射数据。

具体的解决方法如下:

1. 将JavaMap对象转换为Python字典的方法:

from pyspark.mllib.linalg import DenseVector
vectors_ = model.getVectors() # py4j.java_collections.JavaMap
vectors = {k: DenseVector([x for x in vectors_.get(k)])
    for k in vectors_.keys()}

但是这种方法效率非常低。

2. 将模型保存为DataFrame,然后通过join操作将单词映射为向量的方法:

lookup = sqlContext.read.parquet("path_to_word2vec_model/data").alias("lookup")

这样可以得到一个以单词和向量为列的DataFrame。

3. 如果数据可以适应驱动程序/工作节点的内存,可以尝试使用broadcast来收集和映射数据:

lookup_bd = sc.broadcast(lookup.rdd.collectAsMap())
rdd = sc.parallelize([['Hello'],['test']])
rdd.map(lambda ws: [lookup_bd.value.get(w) for w in ws])

希望这些方法能够解决您的问题。

0