使用Word2VecModel.transform()在map函数中无法正常工作。
使用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() # 这里抛出错误
非常感谢您的帮助。
问题的原因是由于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])
希望这些方法能够解决您的问题。