• 粉丝日志首页

昨日终于找到攻击服务器的黑手了

近期服务器,总是收到IO,CPU的报警。

每天某一时刻,IO,CPU, 网络负载值非常高,并不是我的应用流量大。唯一的原因就是服务器被攻击了。

下面4幅图为服务器异常时的状态。

traffic

traffic IPV6

IO

CPU

 

应用软件设置:

  • Open-SSH:    SSH登陆
  • MySQL:         数据库服务器
  • Tomcat:        Java Web服务器
  • Nginx:           Http服务器
  • php-cgi:       PHP脚本解析服务

 

服务器的端口设置:

~# netstat -nlt

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:1723 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 127.0.0.1:8005 :::* LISTEN
tcp6 0 0 :::8009 :::* LISTEN
tcp6 0 0 :::8080 :::* LISTEN

 

找到攻击源:

发现在tomcat7/webapps下面,部署了一个我不认识的应用。

找到tomcat7/logs日志,查看是否有使用过Tomcat管理后台


~ tomcat7/logs# ls manager*

manager.2012-07-01.log  manager.2013-04-01.log  manager.2013-04-25.log
manager.2012-08-21.log  manager.2013-04-05.log  manager.2013-04-26.log
manager.2012-10-31.log  manager.2013-04-08.log  manager.2013-04-30.log
manager.2012-11-01.log  manager.2013-04-09.log  manager.2013-05-01.log
manager.2012-12-26.log  manager.2013-04-16.log  manager.2013-05-06.log
manager.2013-01-23.log  manager.2013-04-17.log  manager.2013-05-07.log
manager.2013-03-01.log  manager.2013-04-23.log

真被我发现了!!这么多文件操作,我自己并没有这么多的使用。

我们看一下黑客在管理后台干了什么。


~ /tomcat7/logs# vi manager.2013-05-06.log

May 6, 2013 2:20:48 PM org.apache.catalina.core.ApplicationContext log
INFO: HTMLManager: list: Listing contexts for virtual host 'localhost'
May 6, 2013 2:33:45 PM org.apache.catalina.core.ApplicationContext log
INFO: HTMLManager: list: Listing contexts for virtual host 'localhost'
May 6, 2013 2:34:00 PM org.apache.catalina.core.ApplicationContext log
SEVERE: HTMLManager: FAIL - Deploy Upload Failed, Exception: java.io.FileNotFoundException: /root/toolkit/tomcat7/webapps/51.war (Permission denied)
java.io.IOException: java.io.FileNotFoundException: /root/toolkit/tomcat7/webapps/51.war (Permission denied)
	at org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:123)
	at org.apache.catalina.manager.HTMLManagerServlet.upload(HTMLManagerServlet.java:332)
	at org.apache.catalina.manager.HTMLManagerServlet.doPost(HTMLManagerServlet.java:211)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.filters.CsrfPreventionFilter.doFilter(CsrfPreventionFilter.java:186)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:108)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:581)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)
Caused by: java.io.FileNotFoundException: /root/toolkit/tomcat7/webapps/51.war (Permission denied)
	at java.io.FileOutputStream.open(Native Method)
	at java.io.FileOutputStream.(FileOutputStream.java:194)
	at java.io.FileOutputStream.(FileOutputStream.java:145)
	at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.write(DiskFileItem.java:457)
	at org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:121)
	... 26 more
May 6, 2013 2:34:00 PM org.apache.catalina.core.ApplicationContext log
INFO: HTMLManager: list: Listing contexts for virtual host 'localhost'

上传名叫 51.war 的包程序在到tomcat/webapps目录。

再来找到黑客是如何获得后台访问权限的


~ vi localhost_access_log.2013-05-06.txt

218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - tomcat [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 200 19009
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:20:49 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - - [06/May/2013:14:33:39 +0000] "GET /manager/html HTTP/1.1" 401 2486
218.15.154.174 - tomcat [06/May/2013:14:33:45 +0000] "GET /manager/html HTTP/1.1" 200 17513
218.15.154.174 - tomcat [06/May/2013:14:33:46 +0000] "GET /manager/images/tomcat.gif HTTP/1.1" 200 2066
218.15.154.174 - tomcat [06/May/2013:14:33:46 +0000] "GET /manager/images/asf-logo.gif HTTP/1.1" 200 7279
218.15.154.174 - tomcat [06/May/2013:14:34:00 +0000] "POST /manager/html/upload?org.apache.catalina.filters.CSRF_NONCE=64E6C202103BF3113A72485F80F5133F HTTP/1.1" 200 17638
218.15.154.174 - - [06/May/2013:14:34:11 +0000] "GET /doc HTTP/1.1" 302 -
218.15.154.174 - - [06/May/2013:14:34:11 +0000] "GET /doc/ HTTP/1.1" 200 3309

黑客的扫描程序实验多次后,终于发现了管理后台的密码,并成功登陆
218.15.154.174 – tomcat [06/May/2013:14:20:49 +0000] “GET /manager/html HTTP/1.1” 200 19009

上传自己的程序包
218.15.154.174 – tomcat [06/May/2013:14:34:00 +0000] “POST /manager/html/upload?org.apache.catalina.filters.CSRF_NONCE=64E6C202103BF3113A72485F80F5133F HTTP/1.1” 200 17638

发现黑客的手段后,果断采取防御措施

1. 暂停tomcat的运行
2. 进入webapps目录,删除黑客上传的文件和文件包
3. 分析日志找到攻击者的IP
4. 把这些IP加到iptabls黑名单中
5. 关闭Tomcat管理控制台

分析日志找到攻击者的IP

183.191.4.235
58.180.70.160
113.30.74.125
113.30.106.92
124.160.217.200
218.15.154.174
61.187.94.66
180.179.206.10
187.188.175.49
65.126.238.4
61.167.33.222
54.228.209.57
95.211.121.136
77.79.125.2
218.15.154.174
222.184.121.15
182.140.241.19
121.199.27.236
116.55.226.215
124.129.18.178
109.186.134.160
61.187.94.66
101.226.33.208
101.226.51.226
112.64.235.89
14.63.196.181
113.30.106.90
109.186.134.160
58.180.70.160
49.156.145.2
61.191.31.27
14.17.18.152
113.30.106.95
61.187.94.66
61.187.94.66
101.226.65.106
180.153.163.191
110.4.89.42
61.187.94.66
109.186.134.160
80.241.209.155
85.17.156.16
218.15.154.174
121.199.27.236
61.187.94.66
113.30.74.125
61.191.31.27
121.189.59.207
82.80.248.188
203.174.60.2
182.140.241.19
124.129.18.178
14.63.196.181
49.156.145.2
199.254.238.207
206.172.16.30
61.167.33.222
203.174.60.2
65.126.238.4
59.188.29.254
118.180.7.60
221.12.174.123
46.32.254.6
59.188.29.254
223.16.9.122

把这些IP加到黑名单中


iptables -I INPUT -s 183.191.4.235 -j DROP
iptables -I INPUT -s 58.180.70.160 -j DROP
iptables -I INPUT -s 113.30.74.125 -j DROP
iptables -I INPUT -s 113.30.106.92 -j DROP
iptables -I INPUT -s 124.160.217.200 -j DROP
iptables -I INPUT -s 218.15.154.174 -j DROP
iptables -I INPUT -s 61.187.94.66 -j DROP
iptables -I INPUT -s 180.179.206.10 -j DROP
iptables -I INPUT -s 187.188.175.49 -j DROP
iptables -I INPUT -s 65.126.238.4 -j DROP
iptables -I INPUT -s 61.167.33.222 -j DROP
iptables -I INPUT -s 54.228.209.57 -j DROP
iptables -I INPUT -s 95.211.121.136 -j DROP
iptables -I INPUT -s 77.79.125.2 -j DROP
iptables -I INPUT -s 222.184.121.15 -j DROP
iptables -I INPUT -s 182.140.241.19 -j DROP
iptables -I INPUT -s 121.199.27.236 -j DROP
iptables -I INPUT -s 116.55.226.215 -j DROP
iptables -I INPUT -s 124.129.18.178 -j DROP
iptables -I INPUT -s 109.186.134.160 -j DROP
iptables -I INPUT -s 101.226.33.208 -j DROP
iptables -I INPUT -s 101.226.51.226 -j DROP
iptables -I INPUT -s 112.64.235.89 -j DROP
iptables -I INPUT -s 14.63.196.181 -j DROP
iptables -I INPUT -s 113.30.106.90 -j DROP
iptables -I INPUT -s 49.156.145.2 -j DROP
iptables -I INPUT -s 61.191.31.27 -j DROP
iptables -I INPUT -s 14.17.18.152 -j DROP
iptables -I INPUT -s 113.30.106.95 -j DROP
iptables -I INPUT -s 101.226.65.106 -j DROP
iptables -I INPUT -s 180.153.163.191 -j DROP
iptables -I INPUT -s 110.4.89.42 -j DROP
iptables -I INPUT -s 80.241.209.155 -j DROP
iptables -I INPUT -s 85.17.156.16 -j DROP
iptables -I INPUT -s 121.189.59.207 -j DROP
iptables -I INPUT -s 82.80.248.188 -j DROP
iptables -I INPUT -s 203.174.60.2 -j DROP
iptables -I INPUT -s 14.63.196.181 -j DROP
iptables -I INPUT -s 199.254.238.207 -j DROP
iptables -I INPUT -s 206.172.16.30 -j DROP
iptables -I INPUT -s 59.188.29.254 -j DROP
iptables -I INPUT -s 118.180.7.60 -j DROP
iptables -I INPUT -s 221.12.174.123 -j DROP
iptables -I INPUT -s 46.32.254.6 -j DROP
iptables -I INPUT -s 223.16.9.122 -j DROP

iptables -I INPUT -s 50.23.210.133 -j DROP
iptables -I INPUT -s 208.109.219.192 -j DROP
iptables -I INPUT -s 50.87.248.103 -j DROP
iptables -I INPUT -s 182.50.130.77 -j DROP
iptables -I INPUT -s 50.87.248.181 -j DROP
iptables -I INPUT -s 50.87.90.193 -j DROP
iptables -I INPUT -s 220.177.198.84 -j DROP
iptables -I INPUT -s 50.62.208.135 -j DROP
iptables -I INPUT -s 162.218.210.232 -j DROP
iptables -I INPUT -s 184.168.193.131 -j DROP
iptables -I INPUT -s 50.63.197.206 -j DROP
iptables -I INPUT -s 174.143.240.181 -j DROP
iptables -I INPUT -s 205.144.171.18 -j DROP
iptables -I INPUT -s 205.144.171.18 -j DROP
iptables -I INPUT -s 108.168.219.178 -j DROP
iptables -I INPUT -s 203.198.63.60 -j DROP
iptables -I INPUT -s 119.18.52.114 -j DROP
iptables -I INPUT -s 91.237.52.5 -j DROP
iptables -I INPUT -s 14.102.254.210 -j DROP
iptables -I INPUT -s 108.168.219.178 -j DROP
iptables -I INPUT -s 173.201.196.146 -j DROP
iptables -I INPUT -s 114.215.113.131 -j DROP
iptables -I INPUT -s 184.168.200.185 -j DROP
iptables -I INPUT -s 139.223.200.149 -j DROP
iptables -I INPUT -s 184.168.27.57 -j DROP
iptables -I INPUT -s 122.155.3.113 -j DROP
iptables -I INPUT -s 113.11.250.65 -j DROP
iptables -I INPUT -s 123.30.209.152 -j DROP
iptables -I INPUT -s 184.168.27.57 -j DROP
iptables -I INPUT -s 122.155.3.113 -j DROP
iptables -I INPUT -s 113.11.250.65 -j DROP
iptables -I INPUT -s 123.30.209.152 -j DROP
iptables -I INPUT -s 103.254.12.144 -j DROP
iptables -I INPUT -s 184.168.27.164 -j DROP
iptables -I INPUT -s 107.170.218.152 -j DROP
iptables -I INPUT -s 72.167.232.144 -j DROP
iptables -I INPUT -s 184.168.200.133 -j DROP
iptables -I INPUT -s 175.102.35.39 -j DROP
iptables -I INPUT -s 184.168.193.208 -j DROP

iptables -I INPUT -s 193.0.61.97 -j DROP
iptables -I INPUT -s 184.168.152.201 -j DROP
iptables -I INPUT -s 31.24.128.43 -j DROP
iptables -I INPUT -s 184.168.193.169 -j DROP
iptables -I INPUT -s 185.76.77.160 -j DROP
iptables -I INPUT -s 208.64.62.17 -j DROP
iptables -I INPUT -s 50.62.176.218 -j DROP
iptables -I INPUT -s 50.76.12.242 -j DROP
iptables -I INPUT -s 208.180.34.230  -j DROP
iptables -I INPUT -s 157.7.188.28 -j DROP
iptables -I INPUT -s 184.168.46.193  -j DROP
iptables -I INPUT -s 184.168.27.26 -j DROP
iptables -I INPUT -s 109.2.222.226 -j DROP
iptables -I INPUT -s 50.62.177.130 -j DROP
iptables -I INPUT -s 188.132.236.186 -j DROP
iptables -I INPUT -s 50.97.138.113 -j DROP
iptables -I INPUT -s 72.167.232.225  -j DROP
iptables -I INPUT -s 182.50.132.104  -j DROP
iptables -I INPUT -s 184.168.193.122 -j DROP
iptables -I INPUT -s 184.168.27.144  -j DROP
iptables -I INPUT -s 63.251.175.215  -j DROP
iptables -I INPUT -s 88.208.252.228  -j DROP
iptables -I INPUT -s 101.50.1.11 -j DROP
iptables -I INPUT -s 218.5.79.103 -j DROP
iptables -I INPUT -s 184.168.193.59  -j DROP
iptables -I INPUT -s 97.74.24.214 -j DROP
iptables -I INPUT -s 50.63.196.134 -j DROP
iptables -I INPUT -s 113.10.222.214  -j DROP
iptables -I INPUT -s 184.168.46.92 -j DROP
iptables -I INPUT -s 50.63.197.67 -j DROP
iptables -I INPUT -s 184.168.192.45  -j DROP
iptables -I INPUT -s 182.50.130.111  -j DROP
iptables -I INPUT -s 37.77.3.133 -j DROP
iptables -I INPUT -s 182.50.130.14 -j DROP
iptables -I INPUT -s 184.168.193.121 -j DROP
iptables -I INPUT -s 182.50.130.114  -j DROP
iptables -I INPUT -s 69.16.197.227 -j DROP
iptables -I INPUT -s 97.74.24.172 -j DROP
iptables -I INPUT -s 50.62.208.191 -j DROP
iptables -I INPUT -s 50.62.161.7 -j DROP
iptables -I INPUT -s 82.200.247.241  -j DROP
iptables -I INPUT -s 216.245.192.26  -j DROP
iptables -I INPUT -s 122.155.16.127  -j DROP
iptables -I INPUT -s 50.62.177.161 -j DROP
iptables -I INPUT -s 50.22.62.68 -j DROP
iptables -I INPUT -s 5.101.157.89 -j DROP
iptables -I INPUT -s 70.32.98.71 -j DROP
iptables -I INPUT -s 50.62.176.42 -j DROP
iptables -I INPUT -s 50.62.161.74 -j DROP
iptables -I INPUT -s 106.186.125.120 -j DROP
iptables -I INPUT -s 94.103.47.8 -j DROP
iptables -I INPUT -s 23.101.136.55 -j DROP
iptables -I INPUT -s 185.50.196.214  -j DROP
iptables -I INPUT -s 184.168.200.12  -j DROP
iptables -I INPUT -s 103.233.98.157  -j DROP
iptables -I INPUT -s 50.62.161.38 -j DROP
iptables -I INPUT -s 50.206.14.7 -j DROP
iptables -I INPUT -s 118.186.240.109 -j DROP
iptables -I INPUT -s 182.50.130.114 -j DROP
iptables -I INPUT -s 173.230.136.186 -j DROP
iptables -I INPUT -s 50.63.197.69 -j DROP
iptables -I INPUT -s 194.247.174.66 -j DROP


~ iptables-save > /etc/iptables.up.rules

~ iptables -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  223.16.9.122         anywhere
DROP       all  --  327458.vps-10.com    anywhere
DROP       all  --  221.12.174.123       anywhere
DROP       all  --  118.180.7.60         anywhere
DROP       all  --  smtp.efaxonline.com  anywhere
DROP       all  --  van-router-01.boats.com  anywhere
DROP       all  --  seattle207.riseup.net  anywhere
DROP       all  --  14.63.196.181        anywhere
DROP       all  --  203.174.60.2         anywhere
DROP       all  --  bzq-82-80-248-188.static.dcenter.bezeqint.net  anywhere      
DROP       all  --  121.189.59.207       anywhere
DROP       all  --  hosted-by.leaseweb.com  anywhere
DROP       all  --  ip-155-209-241-80.static.contabo.net  anywhere
DROP       all  --  110.4.89.42          anywhere
DROP       all  --  180.153.163.191      anywhere
DROP       all  --  101.226.65.106       anywhere
DROP       all  --  113.30.106.95        anywhere
DROP       all  --  14.17.18.152         anywhere
DROP       all  --  61.191.31.27         anywhere
DROP       all  --  smtpmail8102.brixmail.com  anywhere
DROP       all  --  113.30.106.90        anywhere
DROP       all  --  14.63.196.181        anywhere
DROP       all  --  112.64.235.89        anywhere
DROP       all  --  101.226.51.226       anywhere
DROP       all  --  101.226.33.208       anywhere
DROP       all  --  109-186-134-160.bb.netvision.net.il  anywhere
DROP       all  --  124.129.18.178       anywhere
DROP       all  --  215.226.55.116.broad.km.yn.dynamic.163data.com.cn  anywhere  
DROP       all  --  121.199.27.236       anywhere
DROP       all  --  182.140.241.19       anywhere
DROP       all  --  222.184.121.15       anywhere
DROP       all  --  reverse-77-79-125-2.grid.com.tr  anywhere
DROP       all  --  95.211.121.136       anywhere
DROP       all  --  ec2-54-228-209-57.eu-west-1.compute.amazonaws.com  anywhere  
DROP       all  --  61.167.33.222        anywhere
DROP       all  --  wickedgoodcharcoal.com  anywhere
DROP       all  --  fixed-188-175-49.iusacell.net  anywhere
DROP       all  --  180.179.206.10       anywhere
DROP       all  --  61.187.94.66         anywhere
DROP       all  --  218.15.154.174       anywhere
DROP       all  --  124.160.217.200      anywhere
DROP       all  --  113.30.106.92        anywhere
DROP       all  --  113.30.74.125        anywhere
DROP       all  --  58.180.70.160        anywhere
DROP       all  --  235.4.191.183.adsl-pool.sx.cn  anywhere
DROP       all  --  124.115.0.199        anywhere
DROP       all  --  cust.static.62-202-18-26.swisscomdata.ch  anywhere           
DROP       all  --  60-199-223-196.static.tfn.net.tw  anywhere
DROP       all  --  148.208.222.7        anywhere
DROP       all  --  woman22.ru           anywhere

关闭Tomcat管理控制台

把tomcat-users.xml文件的内容都注释掉。

vi ~/tomcat7/conf/tomcat-users.xml

<tomcat-users>

<!–
<role rolename=”manager-gui”/>
<user username=”tomcat” password=”bsspirit” roles=”manager-gui”/>
<user username=”both” password=”tomcat” roles=”tomcat,role1″/>
<user username=”role1″ password=”tomcat” roles=”role1″/>
–>

</tomcat-users>

重启Tomcat服务器!完成Tomcat防御。

服务器的root账号,并没有被破解。为了安全还是换一个吧,攻击手段并不高明,只是我们疏于防范了。

再次给使用TOMCAT的用户提个醒,平时不要打开管理控制台,会被黑客当枪用的。

打赏作者

R利剑NoSQL系列文章 之 Redis

R利剑NoSQL系列文章,主要介绍通过R语言连接使用nosql数据库。涉及的NoSQL产品,包括Redis,MongoDBHBaseHiveCassandra, Neo4j。希望通过我的介绍让广大的R语言爱好者,有更多的开发选择,做出更多地激动人心的应用。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

由于文章篇幅有限,均跳过NoSQL的安装过程,请自行参考文档安装。

转载请注明:
http://blog.fens.me/nosql-r-redis/

r-nosql-redis

第二篇 R利剑Redis,分为4个章节。

  1. Redis环境准备
  2. rredis函数库
  3. rredis基本使用操作
  4. rredis使用案例

每一章节,都会分为”文字说明部分”和”代码部分”,保持文字说明与代码的连贯性。

第一章 Redis环境准备

文字说明部分:

首先环境准备,这里我选择了Linux Ubuntu操作系统12.04的64位服务器版本,大家可以根据自己的使用习惯选择顺手的Linux。
(more…)

R利剑NoSQL系列文章 之 MongoDB

R利剑NoSQL系列文章,主要介绍通过R语言连接使用nosql数据库。涉及的NoSQL产品,包括Redis,MongoDBHBaseHiveCassandra, Neo4j。希望通过我的介绍让广大的R语言爱好者,有更多的开发选择,做出更多地激动人心的应用。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

由于文章篇幅有限,均跳过NoSQL的安装过程,请自行参考文档安装。

转载请注明:
http://blog.fens.me/nosql-r-mongodb/

r-nosql-mongodb

第一篇 R利剑MongeDB,分为4个章节。

  1. MongoDB环境准备
  2. rmongodb函数库
  3. rmongodb基本使用操作
  4. rmongodb测试案例

每一章节,都会分为”文字说明部分”和”代码部分”,保持文字说明与代码的连贯性。

1. MongoDB环境准备

文字说明部分:

首先环境准备,这里我选择了Linux Ubuntu操作系统12.04的32位桌面版本,大家可以根据自己的使用习惯选择顺手的Linux。
(more…)

RHadoop实践系列之四 rhbase安装与使用

RHadoop实践系列文章,包含了R语言与Hadoop结合进行海量数据分析。Hadoop主要用来存储海量数据,R语言完成MapReduce 算法,用来替代Java的MapReduce实现。有了RHadoop可以让广大的R语言爱好者,有更强大的工具处理大数据1G, 10G, 100G, TB, PB。 由于大数据所带来的单机性能问题,可能会一去不复返了。

RHadoop实践是一套系列文章,主要包括”Hadoop环境搭建”,”RHadoop安装与使用”,R实现MapReduce的协同过滤算法”,”HBase和rhbase的安装与使用”。对于单独的R语言爱好者,Java爱好者,或者Hadoop爱好者来说,同时具备三种语言知识并不容 易。此文虽为入门文章,但R,Java,Hadoop基础知识还是需要大家提前掌握。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/rhadoop-hbase-rhase/

rhadoop-rhbase

第四篇 HBase和rhbase的安装与使用,分为3个章节。


1. 环境准备及HBase安装
2. rhbase安装
3. rhbase程序用例

每一章节,都会分为”文字说明部分”和”代码部分”,保持文字说明与代码的连贯性。

注:Hadoop环境及RHadoop的环境,请查看同系列前二篇文章,此文将不再介绍。

1. 环境准备及HBase安装

文字说明部分:

首先环境准备,这里我选择了Linux Ubuntu操作系统12.04的64位版本,大家可以根据自己的使用习惯选择顺手的Linux。

但JDK一定要用Oracle SUN官方的版本,请从官网下载,操作系统的自带的OpenJDK会有各种不兼容。JDK请选择1.6.x的版本,JDK1.7版本也会有各种的不兼容情况。
http://www.oracle.com/technetwork/java/javase/downloads/index.html

Hadoop的环境安装,请参考RHadoop实践系统”Hadoop环境搭建”的一文。

Hadoop和HBase版本:hadoop-1.0.3,hbase-0.94.2

配置HBase的启动命令的环境变量,使用HBase自带的ZooKeeper
export HBASE_MANAGES_ZK=true

配置hbase-site.xml,设置访问目录,数据副本数,ZooKeeper的访问端口。

复制Hadoop环境的类库,覆盖HBase中的类库。

配置完成,启动HBase服务。

代码部分:

hbase安装

1) 下载安装hbase

~ http://www.fayea.com/apache-mirror/hbase/hbase-0.94.2/hbase-0.94.2.tar.gz
~ tar xvf hbase-0.94.2.tar.gz

2) 修改配置文件

~ cd hbase-0.94.2/
~ vi conf/hbase-env.sh 

    export JAVA_HOME=/root/toolkit/jdk1.6.0_29
    export HBASE_HOME=/root/hbase-0.94.2
    export HADOOP_INSTALL=/root/hadoop-1.0.3
    export HBASE_CLASSPATH=/root/hadoop-1.0.3/conf
    export HBASE_MANAGES_ZK=true

~ vi conf/hbase-site.xml

    <configuration>
      <property>
        <name>hbase.rootdir</name>
        <value>hdfs://master:9000/hbase</value>
      </property>

      <property>
        <name>hbase.cluster.distributed</name>
        <value>true</value>
      </property>

      <property>
         <name>dfs.replication</name>
         <value>1</value>
      </property>

      <property>
        <name>hbase.zookeeper.quorum</name>
        <value>master</value>
      </property>

      <property>
          <name>hbase.zookeeper.property.clientPort</name>
          <value>2181</value>
      </property>

      <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/root/hadoop/hdata</value>
      </property>
    </configuration>

3) 复制hadoop环境的配置文件和类库

  ~ cp ~/hadoop-1.0.3/conf/hdfs-site.xml ~/hbase-0.94.2/conf
  ~ cp ~/hadoop-1.0.3/hadoop-core-1.0.3.jar ~/hbase-0.94.2/lib
  ~ cp ~/hadoop-1.0.3/lib/commons-configuration-1.6.jar ~/hbase-0.94.2/lib
  ~ cp ~/hadoop-1.0.3/lib/commons-collections-3.2.1.jar ~/hbase-0.94.2/lib

4) 启动hadoop和hbase

  ~/hadoop-1.0.3/bin/start-all.sh
  ~/hbase-0.94.2/bin/start-hbase.sh 

5) 查看hbase进行

~ jps

    12041 HMaster
    12209 HRegionServer
    31734 TaskTracker
    31343 DataNode
    31499 SecondaryNameNode
    13328 Jps
    31596 JobTracker
    11916 HQuorumPeer
    31216 NameNode

6) 打开hbase命令行客户端

~/hbase-0.94.2/bin/hbase shell

HBase Shell; enter 'help<RETURN>' for list of supported commands.
Type "exit<RETURN>" to leave the HBase Shell
Version 0.94.2, r1395367, Sun Oct  7 19:11:01 UTC 2012

hbase(main):001:0> list

    TABLE
    0 row(s) in 0.0150 seconds

HBase安装完成。

2. rhbase安装

文字说明部分:

安装完成HBase后,我们还需要安装Thrift,因为rhbase是通过Thrift调用HBase的。

Thrift是需要本地编译的,官方没有提供二进制安装包,首先下载thrift-0.8.0。

在thrift解压目录输入./configure,会列Thrift在当前机器所支持的语言环境,如果只是为了rhbase默认配置就可以了。
在我的配置中除了希望支持rhbase访问,还支持PHP,Python,C++。因此需要在系统中,装一些额外的类库。大家可以根据自己的要求,设置Thrift的编译参数。

编译并安装Thrift,然后启动HBase的ThriftServer服务。

最后,安装rhbase。

代码部分:

  1. 下载thrift
    ~ wget http://archive.apache.org/dist/thrift/0.8.0/thrift-0.8.0.tar.gz
    ~ tar xvf thrift-0.8.0.tar.gz
    ~ cd thrift-0.8.0/
    
  2. 下载PHP支持类库(可选)
    ~ sudo apt-get install php-cli
    
  3. 下载C++支持类库(可选)
    ~ sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev
    
  4. 生成编译的配置参数
    ~ ./configure
    
      thrift 0.8.0
    
      Building code generators ..... :
    
      Building C++ Library ......... : yes
      Building C (GLib) Library .... : no
      Building Java Library ........ : no
      Building C# Library .......... : no
      Building Python Library ...... : yes
      Building Ruby Library ........ : no
      Building Haskell Library ..... : no
      Building Perl Library ........ : no
      Building PHP Library ......... : yes
      Building Erlang Library ...... : no
      Building Go Library .......... : no
    
      Building TZlibTransport ...... : yes
      Building TNonblockingServer .. : yes
    
      Using Python ................. : /usr/bin/python
    
      Using php-config ............. : /usr/bin/php-config
    
  5. 编译和安装
    ~ make
    ~ make install
    
  6. 查看thrift版本
    ~ thrift -version
    
      Thrift version 0.8.0
    
  7. 启动HBase的Thrift Server
      ~ /hbase-0.94.2/bin/hbase-daemon.sh start thrift
    
      ~ jps 
    
          12041 HMaster
          12209 HRegionServer
          13222 ThriftServer
          31734 TaskTracker
          31343 DataNode
          31499 SecondaryNameNode
          13328 Jps
          31596 JobTracker
          11916 HQuorumPeer
          31216 NameNode
    
  8. 安装rhbase
      ~ R CMD INSTALL rhbase_1.1.1.tar.gz
    

很顺利的安装完成。

3. rhbase程序用例

文字说明部分:

rhbase的相关函数:

hb.compact.table      hb.describe.table     hb.insert             hb.regions.table
hb.defaults           hb.get                hb.insert.data.frame  hb.scan
hb.delete             hb.get.data.frame     hb.list.tables        hb.scan.ex
hb.delete.table       hb.init               hb.new.table          hb.set.table.mode

hbase和rhbase的基本操作对比:

建表
HBASE:     create 'student_shell','info'
RHBASE:    hb.new.table("student_rhbase","info")

列出所有表
HBASE:     list
RHBASE:    hb.list.tables()

显示表结构
HBASE:     describe 'student_shell'
RHBASE:    hb.describe.table("student_rhbase")

插入一条数据
HBASE:     put 'student_shell','mary','info:age','19'
RHBASE:    hb.insert("student_rhbase",list(list("mary","info:age", "24")))

读取数据
HBASE:     get 'student_shell','mary'
RHBASE:    hb.get('student_rhbase','mary')

删除表(HBASE需要两条命令,rhbase仅是一个操作)
HBASE:     disable 'student_shell'
HBASE:     drop 'student_shell'
RHBASE:    hb.delete.table('student_rhbase')

代码部分:

Hbase Shell

> create 'student_shell','info'
> list

    TABLE
    student_shell

> describe 'student_shell'

   DESCRIPTION                                                          ENABLED
   {NAME => 'student_shell', FAMILIES => [{NAME => 'info', DATA_BLOCK_ true
   ENCODING => 'NONE', BLOOMFILTER => 'NONE', REPLICATION_SCOPE => '0'
   , VERSIONS => '3', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL
   => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536
   ', IN_MEMORY => 'false', ENCODE_ON_DISK => 'true', BLOCKCACHE => 't
   rue'}]}

>  put 'student_shell','mary','info:age','19'
>  get 'student_shell','mary'

  COLUMN                      CELL
  info:age                   timestamp=1365414964962, value=19

> disable 'student_shell'
> drop 'student_shell'

rhbase script

~ R
> library(rhbase)
> hb.init()

    <pointer: 0x16494a0>
    attr(,"class")
    [1] "hb.client.connection"

 >hb.new.table("student_rhbase","info",opts=list(maxversions=5,x=list(maxversions=1L,compression='GZ',inmemory=TRUE)))

   [1] TRUE

> hb.list.tables()

    $student_rhbase
      maxversions compression inmemory bloomfiltertype bloomfiltervecsize
    info:           5        NONE    FALSE            NONE                  0
          bloomfilternbhashes blockcache timetolive
    info:                   0      FALSE         -1

 > hb.describe.table("student_rhbase")

          maxversions compression inmemory bloomfiltertype bloomfiltervecsize
    info:           5        NONE    FALSE            NONE                  0
          bloomfilternbhashes blockcache timetolive
    info:                   0      FALSE         -1

> hb.insert("student_rhbase",list(list("mary","info:age", "24")))

    [1] TRUE

> hb.get('student_rhbase','mary')

    [[1]]
    [[1]][[1]]
    [1] "mary"

    [[1]][[2]]
    [1] "info:age"

    [[1]][[3]]
    [[1]][[3]][[1]]
    [1] "24"

> hb.delete.table('student_rhbase')

    [1] TRUE

RHadoop实践系列文章的第四篇完成!希望这个四篇文章对大家有所帮助。
稍后我可能还会写一些,关于rmr算法实践,rhadoop架构方面和hive的使用的相关文章。
欢迎大家多提问题,多交流。

转载请注明出处:
http://blog.fens.me/rhadoop-hbase-rhase/

打赏作者

RHadoop实践系列之三 R实现MapReduce的协同过滤算法

RHadoop实践系列文章,包含了R语言与Hadoop结合进行海量数据分析。Hadoop主要用来存储海量数据,R语言完成MapReduce 算法,用来替代Java的MapReduce实现。有了RHadoop可以让广大的R语言爱好者,有更强大的工具处理大数据1G, 10G, 100G, TB, PB。 由于大数据所带来的单机性能问题,可能会一去不复返了。

RHadoop实践是一套系列文章,主要包括”Hadoop环境搭建”,”RHadoop安装与使用”,R实现MapReduce的协同过滤算法”,”HBase和rhbase的安装与使用”。对于单独的R语言爱好者,Java爱好者,或者Hadoop爱好者来说,同时具备三种语言知识并不容 易。此文虽为入门文章,但R,Java,Hadoop基础知识还是需要大家提前掌握。

由于rmr2的对hadoop操作有一些特殊性,代码实现有一定难度。需要深入学习的同学,请多尝试并思考key/value值的设计。

本文难度为中高级。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/rhadoop-mapreduce-rmr/

rhadoop-mapreduce-rmr

第三篇 R实现MapReduce的协同过滤算法,分为3个章节。

1.基于物品推荐的协同过滤算法介绍
2.R本地程序实现
3.R基于Hadoop分步式程序实现

每一章节,都会分为”文字说明部分”和”代码部分”,保持文字说明与代码的连贯性。

注:Hadoop环境及RHadoop的环境,请查看同系列前二篇文章,此文将不再介绍。

1. 基于物品推荐的协同过滤算法介绍

文字说明部分:

越来越多的互联网应用,都开始使用推荐算法(协同过滤算法)。根据用户活跃度和物品流行度,可以分为”基于用户的协同过滤算法”和”基于物品的协同过滤算法”。

基于用户的协同过滤算法,是给用户推荐和他兴趣相似的其他用户喜欢的物品。
基于物品的协同过滤算法,是给用户推荐和他之前喜欢的物品相似的物品。
基于物品的协同过滤算法,是目前广泛使用的一种推荐算法,像Netflix, YouTube, Amazon等。

算法主要分为两步:
1. 计算物品之间的相似度
2. 根据物品的相似度和用户的历史行为给用户生成推荐列表

有关算法的细节请参考:”Mahout In Action”和”推荐系统实践”两本书。

为开发方便,我们选择一组很小的测试数据集。

测试数据,来自于”Mahout In Action” P49
原第8行,3,101,2.5 改为 3,101,2.0
每行3个字段,依次是用户ID,物品ID,对物品的评分

代码部分:

在服务上创建测试数据文件small.csv

~ pwd

/root/R

~ vi small.csv

1,101,5.0
1,102,3.0
1,103,2.5
2,101,2.0
2,102,2.5
2,103,5.0
2,104,2.0
3,101,2.0
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0

~ ls

small.csv

2. R本地程序实现

首先,通过R语言实现基于物品的协同过滤算法,为和RHadoop实现进行对比。这里我使用”Mahout In Action”书里,第一章第六节介绍的分步式基于物品的协同过滤算法进行实现。Chapter 6: Distributing recommendation computations

算法的思想:
1. 建立物品的同现矩阵
2. 建立用户对物品的评分矩阵
3. 矩阵计算推荐结果

文字说明部分:

1. 建立物品的同现矩阵

按用户分组,找到每个用户所选的物品,单独出现计数,及两两一组计数。

例如:用户ID为3的用户,分别给101,104,105,107,这4个物品打分。
1) (101,101),(104,104),(105,105),(107,107),单独出现计算各加1。
2) (101,104),(101,105),(101,107),(104,105),(104,107),(105,107),两个一组计数各加1。
3) 把所有用户的计算结果求和,生成一个三角矩阵,再补全三角矩阵,就建立了物品的同现矩阵。

如下面矩阵所示:


      [101] [102] [103] [104] [105] [106] [107]
[101]   5     3     4     4     2     2     1
[102]   3     3     3     2     1     1     0
[103]   4     3     4     3     1     2     0
[104]   4     2     3     4     2     2     1
[105]   2     1     1     2     2     1     1
[106]   2     1     2     2     1     2     0
[107]   1     0     0     1     1     0     1

2. 建立用户对物品的评分矩阵

按用户分组,找到每个用户所选的物品及评分

例如:用户ID为3的用户,分别给(3,101,2.0),(3,104,4.0),(3,105,4.5),(3,107,5.0),这4个物品打分。
1) 找到物品评分(3,101,2.0),(3,104,4.0),(3,105,4.5),(3,107,5.0)
2) 建立用户对物品的评分矩阵


       U3
[101] 2.0
[102] 0.0
[103] 0.0
[104] 4.0
[105] 4.5
[106] 0.0
[107] 5.0

3. 矩阵计算推荐结果

同现矩阵*评分矩阵=推荐结果

alogrithm_1

图片摘自”Mahout In Action”

推荐给用户ID为3的用户的结果是(103,24.5),(102,18.5),(106,16.5)

代码部分:


#引用plyr包
library(plyr)

#读取数据集
train<-read.csv(file="small.csv",header=FALSE)
names(train)<-c("user","item","pref") 

> train
  user item pref
1 1 101 5.0
2 1 102 3.0
3 1 103 2.5
4 2 101 2.0
5 2 102 2.5
6 2 103 5.0
7 2 104 2.0
8 3 101 2.0
9 3 104 4.0
10 3 105 4.5
11 3 107 5.0
12 4 101 5.0
13 4 103 3.0
14 4 104 4.5
15 4 106 4.0
16 5 101 4.0
17 5 102 3.0
18 5 103 2.0
19 5 104 4.0
20 5 105 3.5
21 5 106 4.0

#计算用户列表
usersUnique<-function(){
  users<-unique(train$user)
  users[order(users)]
}

#计算商品列表方法
itemsUnique<-function(){
  items<-unique(train$item)
  items[order(items)]
}

# 用户列表
users<-usersUnique() 
> users
[1] 1 2 3 4 5

# 商品列表
items<-itemsUnique() 
> items
[1] 101 102 103 104 105 106 107

#建立商品列表索引
index<-function(x) which(items %in% x)
data<-ddply(train,.(user,item,pref),summarize,idx=index(item)) 

> data
 user item pref idx
1 1 101 5.0 1
2 1 102 3.0 2
3 1 103 2.5 3
4 2 101 2.0 1
5 2 102 2.5 2
6 2 103 5.0 3
7 2 104 2.0 4
8 3 101 2.0 1
9 3 104 4.0 4
10 3 105 4.5 5
11 3 107 5.0 7
12 4 101 5.0 1
13 4 103 3.0 3
14 4 104 4.5 4
15 4 106 4.0 6
16 5 101 4.0 1
17 5 102 3.0 2
18 5 103 2.0 3
19 5 104 4.0 4
20 5 105 3.5 5
21 5 106 4.0 6

#同现矩阵
cooccurrence<-function(data){
  n<-length(items)
  co<-matrix(rep(0,n*n),nrow=n)
  for(u in users){
    idx<-index(data$item[which(data$user==u)])
    m<-merge(idx,idx)
    for(i in 1:nrow(m)){
      co[m$x[i],m$y[i]]=co[m$x[i],m$y[i]]+1
    }
  }
  return(co)
}

#推荐算法
recommend<-function(udata=udata,co=coMatrix,num=0){
  n<-length(items)

  # all of pref
  pref<-rep(0,n)
  pref[udata$idx]<-udata$pref

  # 用户评分矩阵
  userx<-matrix(pref,nrow=n)

  # 同现矩阵*评分矩阵
  r<-co %*% userx

  # 推荐结果排序
   r[udata$idx]<-0
  idx<-order(r,decreasing=TRUE)
  topn<-data.frame(user=rep(udata$user[1],length(idx)),item=items[idx],val=r[idx])
  topn<-topn[which(topn$val>0),]

  # 推荐结果取前num个
  if(num>0){
    topn<-head(topn,num)
  }

  #返回结果
  return(topn)
}

#生成同现矩阵
co<-cooccurrence(data) 
> co
    [,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,]  5    3    4    4    2    2    1
[2,]  3    3    3    2    1    1    0
[3,]  4    3    4    3    1    2    0
[4,]  4    2    3    4    2    2    1
[5,]  2    1    1    2    2    1    1
[6,]  2    1    2    2    1    2    0
[7,]  1    0    0    1    1    0    1

#计算推荐结果
recommendation<-data.frame()
for(i in 1:length(users)){
  udata<-data[which(data$user==users[i]),]
  recommendation<-rbind(recommendation,recommend(udata,co,0)) 
} 

> recommendation
  user item val
1 1 104 33.5
2 1 106 18.0
3 1 105 15.5
4 1 107 5.0
5 2 106 20.5
6 2 105 15.5
7 2 107 4.0
8 3 103 24.5
9 3 102 18.5
10 3 106 16.5
11 4 102 37.0
12 4 105 26.0
13 4 107 9.5
14 5 107 11.5

3. R基于Hadoop分步式程序实现

R语言实现的MapReduce算法,可以基于R的数据对象实现,不必如JAVA一样使用文本存储。

算法思想同上面R语言实现思想,略有复杂。

算法的思想:
1. 建立物品的同现矩阵
1) 按用户分组,得到所有物品出现的组合列表。
2) 对物品组合列表进行计数,建立物品的同现矩阵
2. 建立用户对物品的评分矩阵
3. 合并同现矩阵和评分矩阵
4. 计算推荐结果列表
5. 按输入格式得到推荐评分列表

通过MapReduce实现时,所有操作都要使用Map和Reduce的任务完成,程序实现过程略有变化。

aglorithm_2

图片摘自”Mahout In Action”

文字说明部分:

1. 建立物品的同现矩阵

1) 按用户分组,得到所有物品出现的组合列表。

key:物品列表向量
val:物品组合向量


$key
[1] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 102 102 102 102
[20] 102 102 102 103 103 103 103 103 103 103 103 103 103 103 104 104 104 104 104
[39] 104 104 104 104 104 104 104 105 105 105 105 106 106 106 106 107 107 107 107
[58] 101 101 101 101 101 101 102 102 102 102 102 102 103 103 103 103 103 103 104
[77] 104 104 104 104 104 105 105 105 105 105 105 106 106 106 106 106 106

$val
[1] 101 102 103 101 102 103 104 101 104 105 107 101 103 104 106 101 102 103 101
[20] 102 103 104 101 102 103 101 102 103 104 101 103 104 106 101 102 103 104 101
[39] 104 105 107 101 103 104 106 101 104 105 107 101 103 104 106 101 104 105 107
[58] 101 102 103 104 105 106 101 102 103 104 105 106 101 102 103 104 105 106 101
[77] 102 103 104 105 106 101 102 103 104 105 106 101 102 103 104 105 106

2) 对物品组合列表进行计数,建立物品的同现矩阵

key:物品列表向量
val:同现矩阵的数据框值(item,item,Freq)
矩阵格式,要与”2. 建立用户对物品的评分矩阵”的格式一致,把异构的两种数据源,合并为同一种数据格式,为”3. 合并 同现矩阵 和 评分矩阵”做数据基础。


$key
[1] 101 101 101 101 101 101 101 102 102 102 102 102 102 103 103 103 103 103 103
[20] 104 104 104 104 104 104 104 105 105 105 105 105 105 105 106 106 106 106 106
[39] 106 107 107 107 107

$val
k v freq
1 101 101 5
2 101 102 3
3 101 103 4
4 101 104 4
5 101 105 2
6 101 106 2
7 101 107 1
8 102 101 3
9 102 102 3
10 102 103 3
11 102 104 2
12 102 105 1
13 102 106 1
14 103 101 4
15 103 102 3
16 103 103 4
17 103 104 3
18 103 105 1
19 103 106 2
20 104 101 4
21 104 102 2
22 104 103 3
23 104 104 4
24 104 105 2
25 104 106 2
26 104 107 1
27 105 101 2
28 105 102 1
29 105 103 1
30 105 104 2
31 105 105 2
32 105 106 1
33 105 107 1
34 106 101 2
35 106 102 1
36 106 103 2
37 106 104 2
38 106 105 1
39 106 106 2
40 107 101 1
41 107 104 1
42 107 105 1
43 107 107 1

2. 建立用户对物品的评分矩阵

key:物品列表
val:用户对物品打分矩阵
矩阵格式,要与”2) 对物品组合列表进行计数,建立物品的同现矩阵”的格式一致,把异构的两种数据源,合并为同一种数据格式,为”3. 合并 同现矩阵 和 评分矩阵”做数据基础


$key
[1] 101 101 101 101 101 102 102 102 103 103 103 103 104 104 104 104 105 105 106
[20] 106 107

$val
item user pref
1 101 1 5.0
2 101 2 2.0
3 101 3 2.0
4 101 4 5.0
5 101 5 4.0
6 102 1 3.0
7 102 2 2.5
8 102 5 3.0
9 103 1 2.5
10 103 2 5.0
11 103 4 3.0
12 103 5 2.0
13 104 2 2.0
14 104 3 4.0
15 104 4 4.5
16 104 5 4.0
17 105 3 4.5
18 105 5 3.5
19 106 4 4.0
20 106 5 4.0
21 107 3 5.0

3. 合并 同现矩阵 和 评分矩阵

这一步操作是MapReduce比较特殊的,因为数据源是两个异构数据源,进行MapReduce的操作。
在之前,我们已经把两种格式合并为一样的。使用equijoin这个rmr2包的函数,进行矩阵合并。
key:NULL
val:合并的数据框


$key
NULL

$val
k.l v.l freq.l item.r user.r pref.r
1 103 101 4 103 1 2.5
2 103 102 3 103 1 2.5
3 103 103 4 103 1 2.5
4 103 104 3 103 1 2.5
5 103 105 1 103 1 2.5
6 103 106 2 103 1 2.5
7 103 101 4 103 2 5.0
8 103 102 3 103 2 5.0
9 103 103 4 103 2 5.0
10 103 104 3 103 2 5.0
11 103 105 1 103 2 5.0
12 103 106 2 103 2 5.0
13 103 101 4 103 4 3.0
....

4. 计算推荐结果列表

把第三步中的矩阵,进行合并计算,得到推荐结果列表
key:物品列表
val:推荐结果数据框


$key
[1] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
[19] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 102
[37] 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 103
[55] 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103
[73] 103 103 103 103 103 104 104 104 104 104 104 104 104 104 104 104 104 104
[91] 104 104 104 104 104 104 104 104 104 104 104 104 104 104 104 105 105 105
[109] 105 105 105 105 105 105 105 105 105 105 105 106 106 106 106 106 106 106
[127] 106 106 106 106 106 107 107 107 107

$val
k.l v.l user.r v
1 101 101 1 25.0
2 101 101 2 10.0
3 101 101 3 10.0
4 101 101 4 25.0
5 101 101 5 20.0
6 101 102 1 15.0
7 101 102 2 6.0
8 101 102 3 6.0
9 101 102 4 15.0
10 101 102 5 12.0
11 101 103 1 20.0
12 101 103 2 8.0
13 101 103 3 8.0
14 101 103 4 20.0
15 101 103 5 16.0
16 101 104 1 20.0
17 101 104 2 8.0
18 101 104 3 8.0
....

5. 按输入格式得到推荐评分列表

对推荐结果列表,进行排序处理,输出排序后的推荐结果。
key:用户ID
val:推荐结果数据框


$key
[1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 5 5 5 5 5 5 5

$val
user item pref
1 1 101 44.0
2 1 103 39.0
3 1 104 33.5
4 1 102 31.5
5 1 106 18.0
6 1 105 15.5
7 1 107 5.0
8 2 101 45.5
9 2 103 41.5
10 2 104 36.0
11 2 102 32.5
12 2 106 20.5
13 2 105 15.5
14 2 107 4.0
15 3 101 40.0
16 3 104 38.0
17 3 105 26.0
18 3 103 24.5
19 3 102 18.5
20 3 106 16.5
21 3 107 15.5
22 4 101 63.0
23 4 104 55.0
24 4 103 53.5
25 4 102 37.0
26 4 106 33.0
27 4 105 26.0
28 4 107 9.5
29 5 101 68.0
30 5 104 59.0
31 5 103 56.5
32 5 102 42.5
33 5 106 34.5
34 5 105 32.0
35 5 107 11.5

rmr2使用提示:

1) rmr.options(backend = ‘hadoop’)

这里backend有两个值,hadoop,local。hadoop是默认值,使用hadoop环境运行程序。local是一个本地测试的设置,已经不建议再使用。我在开发时,试过local设置,运行速度非常快,模拟了hadoop的运行环境。但是,local模式下的代码,不能和hadoop模式下完全兼容,变动也比较大,因此不建议大家使用。

2) equijoin(…,outer=c(‘left’))

这里outer包括了4个值,c(“”, “left”, “right”, “full”),非常像数据库中两个表的join操作

3) keyval(k,v)

mapReduce的操作,需要key和valve保存数据。如果直接输出,或者输出的未加key,会有一个警告Converting to.dfs argument to keyval with a NULL key。再上一篇文章中,rmr2的例子中就有类似的情况,请大家注意修改代码。


> to.dfs(1:10)

Warning message:
In to.dfs(1:10) : Converting to.dfs argument to keyval with a NULL key

代码部分:

#加载rmr2包
library(rmr2)

#输入数据文件
train<-read.csv(file="small.csv",header=FALSE)
names(train)<-c("user","item","pref")

#使用rmr的hadoop格式,hadoop是默认设置。
rmr.options(backend = 'hadoop')

#把数据集存入HDFS
train.hdfs = to.dfs(keyval(train$user,train))
from.dfs(train.hdfs)

> from.dfs(train.hdfs)

    13/04/07 14:35:44 INFO util.NativeCodeLoader: Loaded the native-hadoop library
    13/04/07 14:35:44 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
    13/04/07 14:35:44 INFO compress.CodecPool: Got brand-new decompressor
    $key
     [1] 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5 5 5 5 5

    $val
       user item pref
    1     1  101  5.0
    2     1  102  3.0
    3     1  103  2.5
    4     2  101  2.0
    5     2  102  2.5
    6     2  103  5.0
    7     2  104  2.0
    8     3  101  2.0
    9     3  104  4.0
    10    3  105  4.5
    11    3  107  5.0
    12    4  101  5.0
    13    4  103  3.0
    14    4  104  4.5
    15    4  106  4.0
    16    5  101  4.0
    17    5  102  3.0
    18    5  103  2.0
    19    5  104  4.0
    20    5  105  3.5
    21    5  106  4.0

#STEP 1, 建立物品的同现矩阵
# 1) 按用户分组,得到所有物品出现的组合列表。
train.mr<-mapreduce(
  train.hdfs, 
  map = function(k, v) {
    keyval(k,v$item)
  }
  ,reduce=function(k,v){
    m<-merge(v,v)
    keyval(m$x,m$y)
  }
)

from.dfs(train.mr)

    $key
     [1] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 102 102 102 102
    [20] 102 102 102 103 103 103 103 103 103 103 103 103 103 103 104 104 104 104 104
    [39] 104 104 104 104 104 104 104 105 105 105 105 106 106 106 106 107 107 107 107
    [58] 101 101 101 101 101 101 102 102 102 102 102 102 103 103 103 103 103 103 104
    [77] 104 104 104 104 104 105 105 105 105 105 105 106 106 106 106 106 106

    $val
     [1] 101 102 103 101 102 103 104 101 104 105 107 101 103 104 106 101 102 103 101
    [20] 102 103 104 101 102 103 101 102 103 104 101 103 104 106 101 102 103 104 101
    [39] 104 105 107 101 103 104 106 101 104 105 107 101 103 104 106 101 104 105 107
    [58] 101 102 103 104 105 106 101 102 103 104 105 106 101 102 103 104 105 106 101
    [77] 102 103 104 105 106 101 102 103 104 105 106 101 102 103 104 105 106

# 2) 对物品组合列表进行计数,建立物品的同现矩阵
step2.mr<-mapreduce(
  train.mr,
  map = function(k, v) {
    d<-data.frame(k,v)
    d2<-ddply(d,.(k,v),count)

    key<-d2$k
    val<-d2
    keyval(key,val)
  }
)
from.dfs(step2.mr)

    $key
     [1] 101 101 101 101 101 101 101 102 102 102 102 102 102 103 103 103 103 103 103
    [20] 104 104 104 104 104 104 104 105 105 105 105 105 105 105 106 106 106 106 106
    [39] 106 107 107 107 107

    $val
         k   v freq
    1  101 101    5
    2  101 102    3
    3  101 103    4
    4  101 104    4
    5  101 105    2
    6  101 106    2
    7  101 107    1
    8  102 101    3
    9  102 102    3
    10 102 103    3
    11 102 104    2
    12 102 105    1
    13 102 106    1
    14 103 101    4
    15 103 102    3
    16 103 103    4
    17 103 104    3
    18 103 105    1
    19 103 106    2
    20 104 101    4
    21 104 102    2
    22 104 103    3
    23 104 104    4
    24 104 105    2
    25 104 106    2
    26 104 107    1
    27 105 101    2
    28 105 102    1
    29 105 103    1
    30 105 104    2
    31 105 105    2
    32 105 106    1
    33 105 107    1
    34 106 101    2
    35 106 102    1
    36 106 103    2
    37 106 104    2
    38 106 105    1
    39 106 106    2
    40 107 101    1
    41 107 104    1
    42 107 105    1
    43 107 107    1    

# 2. 建立用户对物品的评分矩阵

train2.mr<-mapreduce(
  train.hdfs, 
  map = function(k, v) {
    #df<-v[which(v$user==3),]
    df<-v
    key<-df$item
    val<-data.frame(item=df$item,user=df$user,pref=df$pref)
    keyval(key,val)
  }
)
from.dfs(train2.mr)

    $key
     [1] 101 101 101 101 101 102 102 102 103 103 103 103 104 104 104 104 105 105 106
    [20] 106 107

    $val
       item user pref
    1   101    1  5.0
    2   101    2  2.0
    3   101    3  2.0
    4   101    4  5.0
    5   101    5  4.0
    6   102    1  3.0
    7   102    2  2.5
    8   102    5  3.0
    9   103    1  2.5
    10  103    2  5.0
    11  103    4  3.0
    12  103    5  2.0
    13  104    2  2.0
    14  104    3  4.0
    15  104    4  4.5
    16  104    5  4.0
    17  105    3  4.5
    18  105    5  3.5
    19  106    4  4.0
    20  106    5  4.0
    21  107    3  5.0

#3. 合并同现矩阵 和 评分矩阵
eq.hdfs<-equijoin(
  left.input=step2.mr, 
  right.input=train2.mr,
  map.left=function(k,v){
    keyval(k,v)
  },
  map.right=function(k,v){
    keyval(k,v)
  },
  outer = c("left")
)
from.dfs(eq.hdfs)

    $key
    NULL

    $val
        k.l v.l freq.l item.r user.r pref.r
    1   103 101      4    103      1    2.5
    2   103 102      3    103      1    2.5
    3   103 103      4    103      1    2.5
    4   103 104      3    103      1    2.5
    5   103 105      1    103      1    2.5
    6   103 106      2    103      1    2.5
    7   103 101      4    103      2    5.0
    8   103 102      3    103      2    5.0
    9   103 103      4    103      2    5.0
    10  103 104      3    103      2    5.0
    11  103 105      1    103      2    5.0
    12  103 106      2    103      2    5.0
    13  103 101      4    103      4    3.0
    14  103 102      3    103      4    3.0
    15  103 103      4    103      4    3.0
    16  103 104      3    103      4    3.0
    17  103 105      1    103      4    3.0
    18  103 106      2    103      4    3.0
    19  103 101      4    103      5    2.0
    20  103 102      3    103      5    2.0
    21  103 103      4    103      5    2.0
    22  103 104      3    103      5    2.0
    23  103 105      1    103      5    2.0
    24  103 106      2    103      5    2.0
    25  101 101      5    101      1    5.0
    26  101 102      3    101      1    5.0
    27  101 103      4    101      1    5.0
    28  101 104      4    101      1    5.0
    29  101 105      2    101      1    5.0
    30  101 106      2    101      1    5.0
    31  101 107      1    101      1    5.0
    32  101 101      5    101      2    2.0
    33  101 102      3    101      2    2.0
    34  101 103      4    101      2    2.0
    35  101 104      4    101      2    2.0
    36  101 105      2    101      2    2.0
    37  101 106      2    101      2    2.0
    38  101 107      1    101      2    2.0
    39  101 101      5    101      3    2.0
    40  101 102      3    101      3    2.0
    41  101 103      4    101      3    2.0
    42  101 104      4    101      3    2.0
    43  101 105      2    101      3    2.0
    44  101 106      2    101      3    2.0
    45  101 107      1    101      3    2.0
    46  101 101      5    101      4    5.0
    47  101 102      3    101      4    5.0
    48  101 103      4    101      4    5.0
    49  101 104      4    101      4    5.0
    50  101 105      2    101      4    5.0
    51  101 106      2    101      4    5.0
    52  101 107      1    101      4    5.0
    53  101 101      5    101      5    4.0
    54  101 102      3    101      5    4.0
    55  101 103      4    101      5    4.0
    56  101 104      4    101      5    4.0
    57  101 105      2    101      5    4.0
    58  101 106      2    101      5    4.0
    59  101 107      1    101      5    4.0
    60  105 101      2    105      3    4.5
    61  105 102      1    105      3    4.5
    62  105 103      1    105      3    4.5
    63  105 104      2    105      3    4.5
    64  105 105      2    105      3    4.5
    65  105 106      1    105      3    4.5
    66  105 107      1    105      3    4.5
    67  105 101      2    105      5    3.5
    68  105 102      1    105      5    3.5
    69  105 103      1    105      5    3.5
    70  105 104      2    105      5    3.5
    71  105 105      2    105      5    3.5
    72  105 106      1    105      5    3.5
    73  105 107      1    105      5    3.5
    74  106 101      2    106      4    4.0
    75  106 102      1    106      4    4.0
    76  106 103      2    106      4    4.0
    77  106 104      2    106      4    4.0
    78  106 105      1    106      4    4.0
    79  106 106      2    106      4    4.0
    80  106 101      2    106      5    4.0
    81  106 102      1    106      5    4.0
    82  106 103      2    106      5    4.0
    83  106 104      2    106      5    4.0
    84  106 105      1    106      5    4.0
    85  106 106      2    106      5    4.0
    86  104 101      4    104      2    2.0
    87  104 102      2    104      2    2.0
    88  104 103      3    104      2    2.0
    89  104 104      4    104      2    2.0
    90  104 105      2    104      2    2.0
    91  104 106      2    104      2    2.0
    92  104 107      1    104      2    2.0
    93  104 101      4    104      3    4.0
    94  104 102      2    104      3    4.0
    95  104 103      3    104      3    4.0
    96  104 104      4    104      3    4.0
    97  104 105      2    104      3    4.0
    98  104 106      2    104      3    4.0
    99  104 107      1    104      3    4.0
    100 104 101      4    104      4    4.5
    101 104 102      2    104      4    4.5
    102 104 103      3    104      4    4.5
    103 104 104      4    104      4    4.5
    104 104 105      2    104      4    4.5
    105 104 106      2    104      4    4.5
    106 104 107      1    104      4    4.5
    107 104 101      4    104      5    4.0
    108 104 102      2    104      5    4.0
    109 104 103      3    104      5    4.0
    110 104 104      4    104      5    4.0
    111 104 105      2    104      5    4.0
    112 104 106      2    104      5    4.0
    113 104 107      1    104      5    4.0
    114 102 101      3    102      1    3.0
    115 102 102      3    102      1    3.0
    116 102 103      3    102      1    3.0
    117 102 104      2    102      1    3.0
    118 102 105      1    102      1    3.0
    119 102 106      1    102      1    3.0
    120 102 101      3    102      2    2.5
    121 102 102      3    102      2    2.5
    122 102 103      3    102      2    2.5
    123 102 104      2    102      2    2.5
    124 102 105      1    102      2    2.5
    125 102 106      1    102      2    2.5
    126 102 101      3    102      5    3.0
    127 102 102      3    102      5    3.0
    128 102 103      3    102      5    3.0
    129 102 104      2    102      5    3.0
    130 102 105      1    102      5    3.0
    131 102 106      1    102      5    3.0
    132 107 101      1    107      3    5.0
    133 107 104      1    107      3    5.0
    134 107 105      1    107      3    5.0
    135 107 107      1    107      3    5.0

#4. 计算推荐结果列表
cal.mr<-mapreduce(
  input=eq.hdfs,
  map=function(k,v){
    val<-v
    na<-is.na(v$user.r)
    if(length(which(na))>0) val<-v[-which(is.na(v$user.r)),]
    keyval(val$k.l,val)
  }
  ,reduce=function(k,v){
    val<-ddply(v,.(k.l,v.l,user.r),summarize,v=freq.l*pref.r)
    keyval(val$k.l,val)
  }
)
from.dfs(cal.mr)

    $key
      [1] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
     [19] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 102
     [37] 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 103
     [55] 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103 103
     [73] 103 103 103 103 103 104 104 104 104 104 104 104 104 104 104 104 104 104
     [91] 104 104 104 104 104 104 104 104 104 104 104 104 104 104 104 105 105 105
    [109] 105 105 105 105 105 105 105 105 105 105 105 106 106 106 106 106 106 106
    [127] 106 106 106 106 106 107 107 107 107

    $val
        k.l v.l user.r    v
    1   101 101      1 25.0
    2   101 101      2 10.0
    3   101 101      3 10.0
    4   101 101      4 25.0
    5   101 101      5 20.0
    6   101 102      1 15.0
    7   101 102      2  6.0
    8   101 102      3  6.0
    9   101 102      4 15.0
    10  101 102      5 12.0
    11  101 103      1 20.0
    12  101 103      2  8.0
    13  101 103      3  8.0
    14  101 103      4 20.0
    15  101 103      5 16.0
    16  101 104      1 20.0
    17  101 104      2  8.0
    18  101 104      3  8.0
    19  101 104      4 20.0
    20  101 104      5 16.0
    21  101 105      1 10.0
    22  101 105      2  4.0
    23  101 105      3  4.0
    24  101 105      4 10.0
    25  101 105      5  8.0
    26  101 106      1 10.0
    27  101 106      2  4.0
    28  101 106      3  4.0
    29  101 106      4 10.0
    30  101 106      5  8.0
    31  101 107      1  5.0
    32  101 107      2  2.0
    33  101 107      3  2.0
    34  101 107      4  5.0
    35  101 107      5  4.0
    36  102 101      1  9.0
    37  102 101      2  7.5
    38  102 101      5  9.0
    39  102 102      1  9.0
    40  102 102      2  7.5
    41  102 102      5  9.0
    42  102 103      1  9.0
    43  102 103      2  7.5
    44  102 103      5  9.0
    45  102 104      1  6.0
    46  102 104      2  5.0
    47  102 104      5  6.0
    48  102 105      1  3.0
    49  102 105      2  2.5
    50  102 105      5  3.0
    51  102 106      1  3.0
    52  102 106      2  2.5
    53  102 106      5  3.0
    54  103 101      1 10.0
    55  103 101      2 20.0
    56  103 101      4 12.0
    57  103 101      5  8.0
    58  103 102      1  7.5
    59  103 102      2 15.0
    60  103 102      4  9.0
    61  103 102      5  6.0
    62  103 103      1 10.0
    63  103 103      2 20.0
    64  103 103      4 12.0
    65  103 103      5  8.0
    66  103 104      1  7.5
    67  103 104      2 15.0
    68  103 104      4  9.0
    69  103 104      5  6.0
    70  103 105      1  2.5
    71  103 105      2  5.0
    72  103 105      4  3.0
    73  103 105      5  2.0
    74  103 106      1  5.0
    75  103 106      2 10.0
    76  103 106      4  6.0
    77  103 106      5  4.0
    78  104 101      2  8.0
    79  104 101      3 16.0
    80  104 101      4 18.0
    81  104 101      5 16.0
    82  104 102      2  4.0
    83  104 102      3  8.0
    84  104 102      4  9.0
    85  104 102      5  8.0
    86  104 103      2  6.0
    87  104 103      3 12.0
    88  104 103      4 13.5
    89  104 103      5 12.0
    90  104 104      2  8.0
    91  104 104      3 16.0
    92  104 104      4 18.0
    93  104 104      5 16.0
    94  104 105      2  4.0
    95  104 105      3  8.0
    96  104 105      4  9.0
    97  104 105      5  8.0
    98  104 106      2  4.0
    99  104 106      3  8.0
    100 104 106      4  9.0
    101 104 106      5  8.0
    102 104 107      2  2.0
    103 104 107      3  4.0
    104 104 107      4  4.5
    105 104 107      5  4.0
    106 105 101      3  9.0
    107 105 101      5  7.0
    108 105 102      3  4.5
    109 105 102      5  3.5
    110 105 103      3  4.5
    111 105 103      5  3.5
    112 105 104      3  9.0
    113 105 104      5  7.0
    114 105 105      3  9.0
    115 105 105      5  7.0
    116 105 106      3  4.5
    117 105 106      5  3.5
    118 105 107      3  4.5
    119 105 107      5  3.5
    120 106 101      4  8.0
    121 106 101      5  8.0
    122 106 102      4  4.0
    123 106 102      5  4.0
    124 106 103      4  8.0
    125 106 103      5  8.0
    126 106 104      4  8.0
    127 106 104      5  8.0
    128 106 105      4  4.0
    129 106 105      5  4.0
    130 106 106      4  8.0
    131 106 106      5  8.0
    132 107 101      3  5.0
    133 107 104      3  5.0
    134 107 105      3  5.0
    135 107 107      3  5.0

#5. 按输入格式得到推荐评分列表
result.mr<-mapreduce(
  input=cal.mr,
  map=function(k,v){
    keyval(v$user.r,v)
  }
  ,reduce=function(k,v){
    val<-ddply(v,.(user.r,v.l),summarize,v=sum(v))
    val2<-val[order(val$v,decreasing=TRUE),]
    names(val2)<-c("user","item","pref")
    keyval(val2$user,val2)
  }
)
from.dfs(result.mr)

    $key
     [1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 3 3 3 3 3 3 3 4 4 4 4 4 4 4 5 5 5 5 5 5 5

    $val
       user item pref
    1     1  101 44.0
    2     1  103 39.0
    3     1  104 33.5
    4     1  102 31.5
    5     1  106 18.0
    6     1  105 15.5
    7     1  107  5.0
    8     2  101 45.5
    9     2  103 41.5
    10    2  104 36.0
    11    2  102 32.5
    12    2  106 20.5
    13    2  105 15.5
    14    2  107  4.0
    15    3  101 40.0
    16    3  104 38.0
    17    3  105 26.0
    18    3  103 24.5
    19    3  102 18.5
    20    3  106 16.5
    21    3  107 15.5
    22    4  101 63.0
    23    4  104 55.0
    24    4  103 53.5
    25    4  102 37.0
    26    4  106 33.0
    27    4  105 26.0
    28    4  107  9.5
    29    5  101 68.0
    30    5  104 59.0
    31    5  103 56.5
    32    5  102 42.5
    33    5  106 34.5
    34    5  105 32.0
    35    5  107 11.5

文章中提供了R用MapReduce方法,实现协同过滤算法的一种思路。

算法可能不是最优的,希望大家有时间写出更好的算法来!随着R语言及Hadoop的发展,相信会有越来越多的算法应用会使用这种方式!

如有问题请给我留言,我很高兴与大家讨论。

######################################################
看文字不过瘾,作者视频讲解,请访问网站:http://onbook.me/video
######################################################

转载请注明出处:
http://blog.fens.me/rhadoop-mapreduce-rmr/

打赏作者