在 Eclipse 运行 ALS 算法进行电影推荐模型时,保存模型 model.save(sc,Path+"ALSmodel")
时,发生报错 Exception in thread "dag-scheduler-event-loop" java.lang.StackOverflowError
运行 hadoop fs -ls /user/hduser
查看模型是存在的
(1)Linux 系统:VirtualBox 6.1.14, Ubuntu 16.04
(2)hadoop 2.7.1
(3)Anaconda 2.5.0
(4)pyspark 2.0.0
(5)Eclipse 3.85
错误原因可能是内存过小,数据量过大,发生栈溢出,无法保存模型。
因此用 checkpoint(self) 标记当前 RDD 的校验点,它会被保存为在由 SparkContext.setCheckpointDir()
方法设置的 checkpoint 目录下的文件集中的一个文件。
简而言之就是当前 RDD 的校验点被保存为了一个文件,而这个文件在一个目录下,这个目录用来让RDD们可以在其下被 checkpoint。
注:如果是在一个集群上跑,这个目录必须是一个HDFS路径。
在原程序的主程序 if __name__ == "__main__":
下添加
sc.setCheckpointDir('checkpoint')
或者
sc.setCheckpointDir('hdfs://master:9000/user/hduser/checkpoint')
两种均可
如下图红线
从图中就可以看到模型保存成功,如果添加的是第二条代码,我们可以看到在相应目录上多出一个 checkpoint 文件夹
在 eclipse 运行 spark-submit Standalone 外部工具执行 Recommend.py ,输入参数 --U 200
或者 --M 200
如下图
--U 200
是针对用户 ID=200 推荐电影--M 200
是针对电影 ID=200 推荐用户点击 OK
等待运行结果
至此完成了在 eclipse 中运行 ALS 推荐算法进行电影推荐。
1、RecommendTrain.py
from pyspark.mllib.recommendation import ALS
from pyspark import SparkConf, SparkContext
def SetLogger( sc ):
logger = sc._jvm.org.apache.log4j
logger.LogManager.getLogger("org"). setLevel( logger.Level.ERROR )
logger.LogManager.getLogger("akka").setLevel( logger.Level.ERROR )
logger.LogManager.getRootLogger().setLevel(logger.Level.ERROR)
def SetPath(sc):
global Path
if sc.master[0:5]=="local" :
Path="file:/home/hduser/pythonsparkexample/PythonProject/"
else:
Path="hdfs://master:9000/user/hduser/"
#如果要在cluster模式运行(hadoop yarn 或Spark Stand alone),请按照书上的说明,先把文件上传到HDFS目录
def CreateSparkContext():
sparkConf = SparkConf() \
.setAppName("RecommendTrain") \
.set("spark.ui.showConsoleProgress", "false")
sc = SparkContext(conf = sparkConf)
print ("master="+sc.master)
SetLogger(sc)
SetPath(sc)
return (sc)
def PrepareData(sc):
#----------------------1.建立用户评价数据-------------
print("开始读取用户评分数据...")
rawUserData = sc.textFile(Path+"data/u.data")
rawRatings = rawUserData.map(lambda line: line.split("\t")[:3] )
ratingsRDD = rawRatings.map(lambda x: (x[0],x[1],x[2]))
#----------------------2.显示数据项数-------------
numRatings = ratingsRDD.count()
numUsers = ratingsRDD.map(lambda x: x[0] ).distinct().count()
numMovies = ratingsRDD.map(lambda x: x[1]).distinct().count()
print("共计:ratings: " + str(numRatings) +
" User:" + str(numUsers) +
" Movie:" + str(numMovies))
return(ratingsRDD)
def SaveModel(sc):
try:
model.save(sc,Path+"ALSmodel")
print("已存储 Model 在ALSmodel")
except Exception :
print "Model已经存在,请先删除再存储."
if __name__ == "__main__":
sc=CreateSparkContext()
sc.setCheckpointDir('checkpoint')
sc.setCheckpointDir('hdfs://master:9000/user/hduser/checkpoint')
print("==========数据准备阶段===========")
ratingsRDD = PrepareData(sc)
print("==========训练阶段===============")
print("开始ALS训练,参数rank=5,iterations=20, lambda=0.1");
model = ALS.train(ratingsRDD, 5, 20, 0.1)
print("========== 存储Model========== ==")
SaveModel(sc)
2、Recommend.py
import sys
from pyspark import SparkConf, SparkContext
from pyspark.mllib.recommendation import MatrixFactorizationModel
def CreateSparkContext():
sparkConf = SparkConf() \
.setAppName("Recommend") \
.set("spark.ui.showConsoleProgress", "false") \
sc = SparkContext(conf = sparkConf)
print("master="+sc.master)
SetLogger(sc)
SetPath(sc)
return (sc)
def SetPath(sc):
global Path
if sc.master[0:5]=="local" :
Path="file:/home/hduser/pythonsparkexample/PythonProject/"
else:
Path="hdfs://master:9000/user/hduser/"
def SetLogger( sc ):
logger = sc._jvm.org.apache.log4j
logger.LogManager.getLogger("org"). setLevel( logger.Level.ERROR )
logger.LogManager.getLogger("akka").setLevel( logger.Level.ERROR )
logger.LogManager.getRootLogger().setLevel(logger.Level.ERROR)
def PrepareData(sc):
print("开始读取电影ID与名称字典...")
itemRDD = sc.textFile(Path+"data/u.item")
movieTitle= itemRDD.map( lambda line : line.split("|")) \
.map(lambda a: (float(a[0]),a[1])) \
.collectAsMap()
return(movieTitle)
def RecommendMovies(model, movieTitle, inputUserID):
RecommendMovie = model.recommendProducts(inputUserID, 10)
print("针对用户id" + str(inputUserID) + "推荐下列电影:")
for rmd in RecommendMovie:
print "针对用户id {0} 推荐电影{1} 推荐评分 {2}". \
format( rmd[0],movieTitle[rmd[1]],rmd[2])
def RecommendUsers(model, movieTitle, inputMovieID) :
RecommendUser = model.recommendUsers(inputMovieID, 10)
print "针对电影 id {0} 电影名:{1}推荐下列用户id:". \
format( inputMovieID,movieTitle[inputMovieID])
for rmd in RecommendUser:
print "针对用户id {0} 推荐评分 {1}".format( rmd[0],rmd[2])
def loadModel(sc):
try:
model = MatrixFactorizationModel.load(sc, Path+"ALSmodel")
print "载入ALSModel模型"
except Exception:
print "找不到ALSModel模型,请先训练"
return model
def Recommend(model):
if sys.argv[1]=="--U":
RecommendMovies(model, movieTitle,int(sys.argv[2]))
if sys.argv[1]=="--M":
RecommendUsers(model, movieTitle,int(sys.argv[2]))
if __name__ == "__main__":
if len(sys.argv) != 3:
print("请输入2个参数")
exit(-1)
sc=CreateSparkContext()
print("==========数据准备===============")
(movieTitle) = PrepareData(sc)
print("==========载入模型===============")
model=loadModel(sc)
print("==========进行推荐===============")
Recommend(model)