上一篇我们已经讲到如何在spark上实现算法的并行化,并且已经能够成功的在Spark平台上运行,根据指定的用户id得出相应的推荐结果。本篇文章要讲的是如何实现算法的持久化。
本篇内容:
1.实现持久化的原因。
2.如何实现持久化。
3.实现代码。
1.实现持久化的原因。
我们在开发或者使用算法的时候,我们要从本地读取数据,这个数据是不变的,因此实现持久化就显得没那么重要。但是当我们的工程真正运用到实际时,数据是经常变化的,我们的算法是针对一批数据得出一个相似度矩阵等(后面统称为模型)。数据会时常补充,在模型的快速迭代过程中,经常会发生问题,所以我们需要回退到上一步,如果每次回退度根据上一次的数据重新计算,就会加大系统负担,而且数据可能也不复存在。因此实现算法持久化是实际工程问题必须考虑的因素。
2.如何实现持久化。
实现持久化的关键问题就是将上次程序算法运行结果保存起来以便下次使用,即存储模型。针对模型存储,我们尝试了多种方法。我们存储使用的是.saveAsTextFile(Path+"module.txt")函数,该函数存储为txt文档。读取的时候,系统自动将某一行归为一个RDD元素。所以我们在读取模型的时候也遇到了一些困难。例如我们存储的数据结构为(user_id_i,[(tem_id,rating),(item_id,rating),.....]),但当我们读取模型时,我们对每一行数据取x[0],我们期望得到的结果为user_id,但是我们得到的结果是“(”(如下图)系统自动的存储为字符串形式,因此我们读取的时候还要对模型进行处理。经过多次尝试,我们选择(item_id,item_id,rating)的形式进行存储。在使用时我们通过一个过滤函数提取出物品id和他们的相似性评分,得到相似度矩阵,然后再根据相似度矩阵进行推荐。
存储的数据格式:
读出数据的第一行与第一个元素:
处理读取到的模型(过滤后结果):
最后的推荐结果:
3.实现代码
计算相似度矩阵以及存储模型代码:
from pyspark import SparkContext
from pyspark import SparkConf
import math
import sys
def CreatSparkContext():
sparkConf=SparkConf() .setAppName("WordCounts").set("spark.ui.showConsoleProgress","false")
sc=SparkContext(conf=sparkConf)
print("master="+sc.master)
SetLogger(sc)
SetPath(sc)
return(sc)
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/pythonwork/PythonProject/"
else:
Path="hdfs://localhost:9000/user/hduser/"
def prepardata(sc):
rawUserData=sc.textFile(Path+"data/u.data")
rawRatings=rawUserData.map(lambda line:line.split("\t")[:2])
ratingsRDD=rawRatings.map(lambda x:(x[0],x[1]))
return(ratingsRDD)
def calculate(x1,x2):
count1=[ ]
count2=[ ]
for x in x1:
count1.append(x)
for x in x2:
count2.append(x)
count=len(count1)*len(count2)*1.0
a=set(count1)
b=set(count2)
c=a&b
bothcount=len(c)
w=bothcount/math.sqrt(count)
return w
def find(x,list_item):
for i in list_item:
if i==x:
return True
return False
def get(x,k):
x.sort(key=lambda x:x[1],reverse=True)
return x[:k]
def recommend(W,user_item,user_id,k):
user_see_item=user_item.filter(lambda x:x[0]==user_id).map(lambda x:x[1]).collect()[0]
sim_item=W.filter(lambda x:find(x[0],user_see_item)).map(lambda x:x[1])
recommend_item=sim_item.flatMap(lambda x:get(x,k)).reduceByKey(lambda x,y:x+y)
recommend_item=recommend_item.sortBy(lambda x:x[1],False)
return recommend_item.take(k)
if __name__=="__main__":
if len(sys.argv)!=3:
print("wrong input")
exit(-1)
sc=CreatSparkContext()
print("prepare data")
ratingsRDD=prepardata(sc)
user_item=ratingsRDD.groupByKey().map(lambda x:(x[0],list(x[1])))
print("got user_item")
RDD=ratingsRDD.map(lambda x:(x[1],x[0]))
item_user=RDD.groupByKey().map(lambda x:(x[0],list(x[1])))
print("got item_user")
print("item_user---item_user")
item_user=item_user.cartesian(item_user).filter(lambda x:x[0][0]!=x[1][0])
print("calculate")
w=item_user.map(lambda x:(x[0][0],x[1][0],calculate(x[0][1],x[1][1])))
w.saveAsTextFile(Path+"module.txt")
读取模型以及模型处理代码:
from pyspark import SparkContext
from pyspark import SparkConf
from RecommendClass import itemCF
import math
import sys
def CreatSparkContext():
sparkConf=SparkConf() .setAppName("WordCounts").set("spark.ui.showConsoleProgress","false")
sc=SparkContext(conf=sparkConf)
print("master="+sc.master)
SetLogger(sc)
SetPath(sc)
return(sc)
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/pythonwork/PythonProject/"
else:
Path="hdfs://localhost:9000/user/hduser/"
def choose(x):
if x in ['0','1','2','3','4','5','6','7','8','9','.']:
return True
return False
def prepardata(sc):
rawUserData=sc.textFile(Path+"module.txt")
print(rawUserData.first())
print(rawUserData.first()[0])
rawRatings=rawUserData.map(lambda line:line.split(","))
print(rawRatings.first())
ratingsRDD=rawRatings.map(lambda x:(filter(str.isdigit,x[0].encode('gbk')),filter(str.isdigit,x[1].encode('gbk')),float(filter(choose,x[2].encode('gbk')))))
print(ratingsRDD.first())
return(ratingsRDD)
def recommend(W,user_item,user_id,k):
user_see_item=user_item.filter(lambda x:x[0]==user_id).map(lambda x:x[1]).collect()[0]
sim_item=W.filter(lambda x:find(x[0],user_see_item)).map(lambda x:x[1])
recommend_item=sim_item.flatMap(lambda x:get(x,k)).reduceByKey(lambda x,y:x+y)
recommend_item=recommend_item.sortBy(lambda x:x[1],False)
return recommend_item.take(k)
def find(x,list_item):
for i in list_item:
if i==x:
return True
return False
def get(x,k):
x.sort(key=lambda x:x[1],reverse=True)
return x[:k]
if __name__=="__main__":
sc=CreatSparkContext()
print("prepare data")
w=prepardata(sc)
W=w.map(lambda x:(x[0],(x[1],x[2])))
W=W.groupByKey().map(lambda x:(x[0],list(x[1])))
user_id='200'
rawUserData=sc.textFile("file:/home/hduser/pythonwork/PythonProject/data/u.data")
rawRatings=rawUserData.map(lambda line:line.split("\t")[:2])
ratingsRDD=rawRatings.map(lambda x:(filter(str.isdigit,x[0].encode('gbk')),filter(str.isdigit,x[1].encode('gbk'))))
user_item=ratingsRDD.groupByKey().map(lambda x:(x[0],list(x[1])))
recommend=recommend(W,user_item,user_id,5)
print("Result:")
for r in recommend:
print(r)