在 Azure HDInsight 中使用 Apache Mahout 生成推荐

了解如何使用 Apache Mahout 机器学习库通过 Azure HDInsight 生成电影推荐。

Mahout 是适用于 Apache Hadoop 的计算机学习库。 Mahout 包含用于处理数据的算法,例如筛选、分类和群集。 在本文中,用户使用推荐引擎根据好友看过的电影生成电影推荐。

先决条件

HDInsight 中的 Apache Hadoop 群集。 请参阅 Linux 上的 HDInsight 入门

了解建议

由 Mahout 提供的功能之一是推荐引擎。 此引擎接受 userIDitemIdprefValue 格式(项的首选项)的数据。 然后,Mahout 将执行共现分析,以确定: 偏好某个项的用户也偏好其他类似项。 随后,Mahout 确定拥有类似项偏好的用户,这些偏好可用于推荐。

下面的工作流是使用电影数据的简化示例:

  • 共现:Joe、Alice 和 Bob 都喜欢电影《星球大战》、《帝国反击战》和《绝地归来》Jedi。 Mahout 可确定喜欢以上电影之一的用户也喜欢其他两部。

  • 共现:Bob 和 Alice 还喜欢电影《幽灵的威胁》、《克隆人的进攻》和《西斯的复仇》。 Mahout 可确定喜欢前面三部电影的用户也喜欢这三部电影。

  • 类似性推荐:由于 Joe 喜欢前三部电影,Mahout 会查看具有类似偏好的其他人已喜欢但 Joe 还未观看过(已点赞/已评价)的电影。 在这种情况下,Mahout 推荐《幽灵的威胁》、《克隆人的进攻》和《西斯的复仇》。

了解数据

为方便起见,GroupLens 研究以兼容 Mahout 的格式提供电影的评价数据。 此数据在 /HdiSamples/HdiSamples/MahoutMovieData 中群集的默认存储中可用。

有两个文件,即 moviedb.txtuser-ratings.txtuser-ratings.txt 文件在分析期间使用。 moviedb.txt 用于在查看结果时提供用户友好的文本信息。

user-ratings.txt 中包含的数据具有 userIDmovieIDuserRatingtimestamp 的结构,指示每个用户对电影评级的情况。 下面是数据的示例:

    196    242    3    881250949
    186    302    3    891717742
    22     377    1    878887116
    244    51     2    880606923
    166    346    1    886397596

运行分析

  1. 使用 ssh 命令连接到群集。 编辑以下命令(将 CLUSTERNAME 替换为群集的名称),然后输入该命令:

    ssh sshuser@CLUSTERNAME-ssh.azurehdinsight.cn
    
  2. 使用以下命令来运行推荐作业:

    mahout recommenditembased -s SIMILARITY_COOCCURRENCE -i /HdiSamples/HdiSamples/MahoutMovieData/user-ratings.txt -o /example/data/mahoutout --tempDir /temp/mahouttemp
    

注意

该作业可能需要几分钟才能完成,并可能运行多个 MapReduce 作业。

查看输出

  1. 作业完成后,使用以下命令查看生成的输出:

    hdfs dfs -text /example/data/mahoutout/part-r-00000
    

    输出将如下所示:

    1    [234:5.0,347:5.0,237:5.0,47:5.0,282:5.0,275:5.0,88:5.0,515:5.0,514:5.0,121:5.0]
    2    [282:5.0,210:5.0,237:5.0,234:5.0,347:5.0,121:5.0,258:5.0,515:5.0,462:5.0,79:5.0]
    3    [284:5.0,285:4.828125,508:4.7543354,845:4.75,319:4.705128,124:4.7045455,150:4.6938777,311:4.6769233,248:4.65625,272:4.649266]
    4    [690:5.0,12:5.0,234:5.0,275:5.0,121:5.0,255:5.0,237:5.0,895:5.0,282:5.0,117:5.0]
    

    第一列是 userID。 “[”和“]”中包含的值为 movieId:recommendationScore

  2. 可使用该输出以及 moviedb.txt 提供有关建议的详细信息。 首先,使用以下命令在本地复制文件:

    hdfs dfs -get /example/data/mahoutout/part-r-00000 recommendations.txt
    hdfs dfs -get /HdiSamples/HdiSamples/MahoutMovieData/* .
    

    此命令会将输出数据以及电影数据文件复制到当前目录中名为 recommendations.txt 的文件。

  3. 使用如下命令创建 Python 脚本,该脚本查找电影名称中是否存在建议输出中的数据:

    nano show_recommendations.py
    

    编辑器打开后,使用以下文本作为该文件的内容:

    #!/usr/bin/env python
    
    import sys
    
    if len(sys.argv) != 5:
         print "Arguments: userId userDataFilename movieFilename recommendationFilename"
         sys.exit(1)
    
    userId, userDataFilename, movieFilename, recommendationFilename = sys.argv[1:]
    
    print "Reading Movies Descriptions"
    movieFile = open(movieFilename)
    movieById = {}
    for line in movieFile:
        tokens = line.split("|")
        movieById[tokens[0]] = tokens[1:]
    movieFile.close()
    
    print "Reading Rated Movies"
    userDataFile = open(userDataFilename)
    ratedMovieIds = []
    for line in userDataFile:
        tokens = line.split("\t")
        if tokens[0] == userId:
            ratedMovieIds.append((tokens[1],tokens[2]))
    userDataFile.close()
    
    print "Reading Recommendations"
    recommendationFile = open(recommendationFilename)
    recommendations = []
    for line in recommendationFile:
        tokens = line.split("\t")
        if tokens[0] == userId:
            movieIdAndScores = tokens[1].strip("[]\n").split(",")
            recommendations = [ movieIdAndScore.split(":") for movieIdAndScore in movieIdAndScores ]
            break
    recommendationFile.close()
    
    print "Rated Movies"
    print "------------------------"
    for movieId, rating in ratedMovieIds:
        print "%s, rating=%s" % (movieById[movieId][0], rating)
    print "------------------------"
    
    print "Recommended Movies"
    print "------------------------"
    for movieId, score in recommendations:
        print "%s, score=%s" % (movieById[movieId][0], score)
    print "------------------------"
    

    Ctrl-XY,最后按 Enter 来保存数据。

  4. 运行 Python 脚本。 以下命令假设用户处于内含所有已下载文件的目录中:

    python show_recommendations.py 4 user-ratings.txt moviedb.txt recommendations.txt
    

    此命令查看为用户 ID 4 生成的建议。

    • user-ratings.txt 文件用于检索已被评价过的电影。

    • moviedb.txt 文件用于检索电影的名称。

    • recommendations.txt 用于检索此用户的电影建议。

      此命令的输出类似于以下文本:

      Seven Years in Tibet (1997), score=5.0
      Indiana Jones and the Last Crusade (1989), score=5.0
      Jaws (1975), score=5.0
      Sense and Sensibility (1995), score=5.0
      Independence Day (ID4) (1996), score=5.0
      My Best Friend's Wedding (1997), score=5.0
      Jerry Maguire (1996), score=5.0
      Scream 2 (1997), score=5.0
      Time to Kill, A (1996), score=5.0
      

删除临时数据

Mahout 作业不删除在处理作业时创建的临时数据。 在示例作业中指定 --tempDir 参数,以将临时文件隔离到特定路径中轻松删除。 若要删除临时文件,请使用以下命令:

hdfs dfs -rm -f -r /temp/mahouttemp

警告

如需再次运行此命令,则还必须删除输出目录。 使用以下命令删除此目录:

hdfs dfs -rm -f -r /example/data/mahoutout

后续步骤

现在,已经学习了如何使用 Mahout,因此可以探索通过其他方式来使用 HDInsight 上的数据: