使用Mahout搭建推荐系统之入门篇1-搭建REST风格简单推荐系统

来源:互联网 发布:古典音乐广播 知乎 编辑:程序博客网 时间:2024/05/16 00:47

原始链接:http://my.oschina.net/Cfreedom/blog?catalog=408809


     用意: 网络上有很多关于使用mahout搭建推荐系统的文章,但是还没有一个从建立推荐系统原型至部署到简单服务器的完整教程. 虽然部分朋友对推荐系统很感兴趣, 但是因hadoop的复杂而却步.  同时对于那些没有任何Web开发经验的朋友来说, 一个完整的小型推荐系统可以很大的激发学习的兴趣和动手的冲动. 我觉得动手的冲动比看书的冲动要重要的多. 

     原型分为两个系列 : JAVA原型和Python原型. 

这篇博客主要是介绍JAVA推荐系统原型: 主要参考[1] 

使用MyEclipse和Mahout开发一个REST风格[3]的简单推荐系统

一. 搭建一个Hello world的REST服务器
1. 选择建立MyEclise Web Service Project 
    填写Project Name, 填写完毕后,注意Context root URL的内容.两者是一致的.当然你也可以让两者不一样,自己选择一个名字.如Project Name为testHello.而URL为/rs.(URL十分重要,是最终WEB访问路径的一部分) 

     Library见下图 core server client json. 

 
2. 打开/WEB-INF下的web-xml可以看到 

<servlet-mapping>
<servlet-name>JAX-RS REST Servlet</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping> 

其中的url-pattern将是WEB路径的一部分,具体见下文. 

2. 在/src目录下加入HelloRS文件. 内容如下 


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
importjavax.ws.rs.GET;
importjavax.ws.rs.Path;
importjavax.ws.rs.Produces;
importjavax.ws.rs.core.MediaType;
 
 
//设置路径为http://域名:端口/ConTextRootURL/url-pattern + /hello
//以我的机子为例:http://localhost:8080/rs/rest/hello
 
@Path("/recommend")
publicclass HelloRS {
 
  // 这个方法将返回普通文本
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  publicString sayPlainTextHello() {
    return"Hello REST";
  }
 
  // 这个方法将返回XML文件
  @GET
  @Produces(MediaType.TEXT_XML)
  publicString sayXMLHello() {
    return"<?xml version=\"1.0\"?>" + "<hello> Hello REST" + "</hello>";
  }
 
  // 这个方法将返回HTML文件
  @GET
  @Produces(MediaType.TEXT_HTML)
  publicString sayHtmlHello() {
    return"<html> " + "<title>"+ "Hello REST" + "</title>"
        +"<body><h1>"+ "Hello REST" + "</body></h1>"+ "</html> ";
  }
 
}


3. 选择Project,使用Run as->MyEclipse Server Application即可. 
使用 http://localhost:8080/rs/rest/hello 既可以看到返回Hello REST了. 

修改文件后Tomcat将会自动检测并布置. 
注:有任何问题,看console中的日志输出,找到Exception或者error, Google一下. 

二. 利用mahout搭建简单的推荐系统,数据使用代码生成

1. 在Java Build Path引入mahout相关库文件, 下载地址: http://pan.baidu.com/s/1Ea8pI
mahout核心类: 提供推荐Model等核心类 
    mahout-core-0.5.jar 
    mahout-math-0.5.jar 
辅助类: 提供Log和部分数学公式类. 
    uncommons-maths-1.2.jar 
    google-collections-1.0-rc2.jar 
    guava-r0.3.jar 
    slf4j-api-1.6.0.jar 

2. 在src下新建一个RecommenderIntro.java文件,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<strong>importorg.apache.mahout.cf.taste.impl.model.file.*;
importorg.apache.mahout.cf.taste.impl.neighborhood.*;
importorg.apache.mahout.cf.taste.impl.recommender.*;
importorg.apache.mahout.cf.taste.impl.similarity.*;
importorg.apache.mahout.cf.taste.model.*;
importorg.apache.mahout.cf.taste.neighborhood.*;
importorg.apache.mahout.cf.taste.recommender.*;
importorg.apache.mahout.cf.taste.similarity.*;
importjava.io.*;
importjava.util.*;
 
classRecommenderIntro {
 
     privateFileDataModel model;
     privatePearsonCorrelationSimilarity similarity;
     privateNearestNUserNeighborhood neighborhood;
     privateGenericUserBasedRecommender recommender;
 
 
 
    // 从filename中读取数据(用户id, 物品id, 评分rate), 生成数据类model, 相似类similarity以及最相近的邻居类(2个)
 
     publicRecommenderIntro(String filename) throwsException {
          model = newFileDataModel(newFile(filename));
 
          similarity = newPearsonCorrelationSimilarity(model);
          neighborhood =
               newNearestNUserNeighborhood(2, similarity, model);
 
          recommender = newGenericUserBasedRecommender(
                    model, neighborhood, similarity);
}
 
 
 
// 对用户userid推荐前num个物品.
 
publicList<RecommendedItem> SimpleRecommend(intuserid, intnum) throwsException {
 
     List<RecommendedItem> recommendations =
     recommender.recommend(1,1);
 
     returnrecommendations;
 
}
 
}</strong>

代码介绍: 

    本算法是最简单的基于用户的协同过滤. 现实解释:你想别人给你推荐一个电影,你会从一堆人中找到与你最熟悉的几个人推荐电影给你,然后找到被推荐次数最多的电影. Model类用来存储数据, mahout为了节约内存, 数据结构设计的很好,下次找个机会聊聊. Similarity计算两个人之间的相似性, 而Neighborhood则是为每个人保存最相似的2个人.最后recommener结合model\neighborhood和similarity来为某个user推荐N个好友.  

3. 修改helloRS文件修改如下所示:

    将intro.csv文件放到src/目录下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<strong>importjava.util.List;
 
importjavax.ws.rs.DefaultValue;
importjavax.ws.rs.GET;
importjavax.ws.rs.Path;
importjavax.ws.rs.Produces;
importjavax.ws.rs.QueryParam;
importjavax.ws.rs.core.MediaType;
 
importorg.apache.mahout.cf.taste.recommender.RecommendedItem;
 
//Sets the path to base URL + /hello
@Path("/recommend")
publicclass HelloRS {
 
    privateRecommenderIntro recommender = null;
    privateString filename = null;
 
    // This method is called if TEXT_PLAIN is request
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    publicString sayPlainTextHello(
            @DefaultValue("1")@QueryParam("id") String id,
            @DefaultValue("1")@QueryParam("num") String num) throwsException {
 
        intuserId = Integer.valueOf(id);
        intrankNum = Integer.valueOf(num);
        String resultStr = getRecommender(userId, rankNum);
 
        returnresultStr;
    }
 
    // This method is called if XML is request
    @GET
    @Produces(MediaType.TEXT_XML)
    publicString sayXMLHello(@DefaultValue("1")@QueryParam("id") String id,
            @DefaultValue("1")@QueryParam("num") String num) throwsException {
        intuserId = Integer.valueOf(id);
        intrankNum = Integer.valueOf(num);
        String resultStr = getRecommender(userId, rankNum);
 
        return"<?xml version=\"1.0\"?>" + "<hello> " + resultStr + "</hello>";
    }
 
    // This method is called if HTML is request
    @GET
    @Produces(MediaType.TEXT_HTML)
    publicString sayHtmlHello(@DefaultValue("1")@QueryParam("id") String id,
            @DefaultValue("1")@QueryParam("num") String num) throwsException {
 
        System.out.println(id + " " + num);
        intuserId = Integer.valueOf(id);
        intrankNum = Integer.valueOf(num);
        String resultStr = getRecommender(userId, rankNum);
 
        return"<html> " + "<title>"+ "Hello REST" + "</title>"+ "<body><h1>"
                + resultStr + "</body></h1>"+ "</html> ";
    }
 
    privateString getRecommender(intuserId, intnum) throwsException {
 
        if(filename == null) {
            String classPath = this.getClass().getClassLoader()
                    .getResource("/").getPath();
             
            classPath = classPath.replace("%20","\\ ");
            filename = classPath + "intro.csv";
            System.out.println(filename);
        }
 
        if(recommender == null)
            recommender = newRecommenderIntro(filename);
 
        List<RecommendedItem> recommendedList = recommender.SimpleRecommend(
                userId, num);
        String resultStr = "Result="+ recommendedList.get(0).getItemID() + " "
                + recommendedList.get(0).getValue();
 
        returnresultStr;
    }
 
}</strong>

代码介绍: 代码提供了XML\HTML和普通文本三个格式, 以浏览器默认的HTML格式为例.  

如果浏览器 输入 http://localhost:8080/rs/rest/recommend?id=1&num=1  

参数表@DefaultValue("1") @QueryParam("id") String id, @DefaultValue("1") @QueryParam("num") String num表示获得参数

id = "1", num = "1". 之后通过getRecommender来初始化Recommender并获得数据. QueryParam表示GET方法的数据.

注: 由于intro.csv数据集比较少,所有部分id和num值无法返回合适的结果.

注: 由与intro.csv最终会部署在tomcat上,所以需要获得tomcat中class的路径.

注: recommender作为成员函数,保证每一个函数都引用同一份数据,保证一致性.

获取路径的方法如下:

?
1
2
<strong>String classPath = this.getClass().getClassLoader()
                    .getResource("/").getPath();<span style="line-height:1.428571em;font-family:'sans serif', tahoma, verdana, helvetica;font-size:10pt;font-weight:normal;"></span></strong>

4. 运行代码,即可使用http://localhost:8080/rs/rest/recommend?id=1&num=1 即可在浏览器中访问. 

返回: 

Result=104 4.257081 


一些问题: 
注意: 碰到tomcat端口设置问题: 8080 被占用.原因是已启动了tomcat了.使用/etc/init.d/tomcat6 stop让程序停止即可. 
注意: Myeclipse安装路径中不要出现空格,否则会出现问题. 

参考资料: 
[1] Sean Owen "Mahout in Action"  http://book.douban.com/subject/4893547/

[2] Lars Vogel  REST with Java (JAX-RS) using Jersey - Tutorial http://www.vogella.com/articles/REST/article.html[3] REST 参考豆瓣API http://developers.douban.com/wiki/?title=movie_v2#reviews


0 0
原创粉丝点击