大数据时代的数据分析与数据挖掘 – 基于Hadoop实现¶
数据分析简介¶
1.1 什么是数据分析¶
1.2 为什么分析数据¶
1.3 怎么样分析数据¶
Date: 2013-04-28 10:38:31 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
Hadoop简介¶
3.1 什么是Hadoop¶
3.2 产生的原因¶
3.3 发展过程及展望¶
Date: 2013-04-28 10:38:26 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
Hadoop安装¶
4.1 系统要求¶
4.2 安装准备¶
4.2.1 创建hadoop用户¶
# 创建hadoop用户组
groupadd hadoop
# 创建hadoop用户
useradd hadoop
# 设置密码
passwd hadoop
# 添加用户到用户组
usermod -G hadoop hadoop
4.2.2 基本服务¶
- ssh&rsync
# 安装ssh服务
yum install ssh
# 安装数据同步工具
yum install rsync
# 设置ssh服务开机启动
systemctl enable sshd.service
# 启动ssh服务
systemctl start sshd.service
# 或者
service sshd start
4.2.3 JDK¶
- 安装
http://www.oracle.com/technetwork/java/javase/downloads/index.html
# 使用二进制版本安装
./jdk-6u39-linux-i586.bin
# 移动到专门的目录下
mkdir /usr/java
mv jdk1.6.0_39 /usr/java/
# 建立最新版本的软链接
cd /usr/java/
ln -s -f /usr/java/jdk1.6.0_39 latest
# 建立默认版本的软链接
ln -s -f /usr/java/latest default
# 重新设置Java的软链接
cd /usr/bin
ln -s -f /usr/java/default/bin/java
ln -s -f /usr/java/default/bin/javac
- 查看是否正确安装
# java -version
java version "1.6.0_39"
Java(TM) SE Runtime Environment (build 1.6.0_39-b04)
Java HotSpot(TM) Server VM (build 20.14-b01, mixed mode)
- 设置系统变量
export JAVA_HOME=/usr/java/default
export CLASSPATH=.:$JAVA_HOME/lib
export PATH=$JAVA_HOME/bin:$PATH
source /etc/profile
echo $JAVA_HOME
4.2.6 无密码登录¶
- 生成RSA格式的密钥对
# 切换到hadoop账户
cd
ssh-keygen -t rsa -P ""
- 设置自动登录
# 单机模式下
cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys
# 集群模式下
scp ~/.ssh/id_rsa.pub hadoop@slver:/home/hadoop/.ssh/authorized_keys
4.3 安装配置¶
4.3.1 目录规范¶
- 程序目录
mkdir /usr/local/cloud
tar -zxvf hadoop-1.0.4.tar.gz -C /usr/local/cloud/src/
cd /usr/local/cloud/
ln -s -f /usr/local/cloud/src/hadoop-1.0.4 hadoop
- 数据目录
# 设置目录所有者为hadoop
mkdir /data
chown hadoop:hadoop /data
# 切换到hadoop账户创建相关目录
su hadoop
mkdir hadoop
mkdir -p logs/hadoop
mkdir -p pids/hadoop
4.3.2 修改配置¶
- 系统变量设置
# vim /etc/profile
export HADOOP_HOME=/usr/local/cloud/hadoop
export PATH=$JAVA_HOME/bin:$HADOOP_HOME/bin:$PATH
source /etc/profile
- $HADOOP_HOME/conf/hadoop-env.sh
export JAVA_HOME=/usr/java/default
export HADOOP_LOG_DIR=/data/logs/hadoop
export HADOOP_PID_DIR=/data/pids/hadoop
- $HADOOP_HOME/conf/core-site.xml
<property>
<name>fs.default.name</name>
<value>hdfs://hadooptest:9000</value>
</property>
<property>
<name>hadoop.tmp.dir></name>
<value>/data/hadoop</value>
</property>
- $HADOOP_HOME/conf/mapred-site.xml
<property>
<name>mapred.job.tracker</name>
<value>hadooptest:9001</value>
</property>
- $HADOOP_HOME/conf/hdfs-site.xml
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>${hadoop.tmp.dir}/dfs/data</value>
</property>
<property>
<name>dfs.name.dir</name>
<value>${hadoop.tmp.dir}/dfs/name</value>
</property>
- $HADOOP_HOME/conf/masters
hadooptest
- $HADOOP_HOME/conf/slaves
hadooptest
4.3.3 启动服务¶
- 格式化文件系统
$HADOOP_HOME/bin/hadoop namenode -format
- 启动HDFS服务
$HADOOP_HOME/bin/start-dfs.sh
- 启动MR服务
$HADOOP_HOME/bin/start-mapred.sh
- WEB方式查看


- 相关进程
[hadoop@hadooptest ~]$ cd /usr/local/cloud/hadoop/bin/
[hadoop@hadooptest bin]$ ./start-all.sh
starting namenode, logging to /data/logs/hadoop/hadoop-hadoop-namenode-hadooptest.out
hadooptest: starting datanode, logging to /data/logs/hadoop/hadoop-hadoop-datanode-hadooptest.out
hadooptest: starting secondarynamenode, logging to /data/logs/hadoop/hadoop-hadoop-secondarynamenode-hadooptest.out
starting jobtracker, logging to /data/logs/hadoop/hadoop-hadoop-jobtracker-hadooptest.out
hadooptest: starting tasktracker, logging to /data/logs/hadoop/hadoop-hadoop-tasktracker-hadooptest.out
[hadoop@hadooptest bin]$ jps
2542 SecondaryNameNode
2282 NameNode
2764 TaskTracker
2819 Jps
2634 JobTracker
2409 DataNode
[hadoop@hadooptest bin]$
Date: 2013-04-28 10:38:29 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
分布式文件系统¶
Date: 2013-04-28 10:38:30 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
分布式并行计算模型¶
Date: 2013-04-28 10:38:26 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
分布式日志收集系统¶
7.1 安装部署¶
7.1.1 环境要求¶
7.1.2 版本选择¶
7.1.3 目录规范¶
- 程序目录
tar -zxvf chukwa-incubating-0.5.0.tar.gz -C /usr/local/cloud/src/ cd /usr/local/cloud/ ln -s -f /usr/local/cloud/src/chukwa-incubating-0.5.0 chukua
- 数据目录
mkdir /data/logs/chukwa mkdir /data/pids/chukwa
7.1.4 修改配置¶
- 系统变量设置
vim /etc/profile export CHUKWA_HOME=/usr/local/cloud/chukwa export PATH=$JAVA_HOME/bin:$HADOOP_HOME/bin:$CHUKWA_HOME/bin:$PATH source /etc/profile
- 代理器配置
- 使用 $CHUKWAHOME/etc/chukwa/agents 指定代理器地址
localhost
- 使用 $CHUKWAHOME/etc/chukwa/chukwa-agent-conf.xml 配置代理器参数
<!-- 设置轮询检测文件内容变化的间隔时间 --> <property> <name>chukwaAgent.adaptor.context.switch.time</name> <value>5000</value> </property> <!-- 设置读取文件增量内容的最大值 --> <property> <name>chukwaAgent.fileTailingAdaptor.maxReadSize</name> <value>2097152</value> </property>
- 收集器配置
- 使用 $CHUKWAHOME/etc/chukwa/collectors 指定收集器地址
# 单机部署的情况下与agents相同 localhost
- 使用 $CHUKWAHOME/etc/chukwa/chukwa-collector-conf.xml 配置收集器参数
<!-- Chukwa 0.5 版本添加了写入到HBase的实现, 如果不需要则应恢复默认 --> <!-- Sequence File Writer parameters --> <property> <name>chukwaCollector.pipeline</name> <value>org.apache.hadoop.chukwa.datacollection.writer.SocketTeeWriter,org.apache.hadoop.chukwa.datacollection.writer.Se# </property> <!-- 设置服务端地址 --> <property> <name>writer.hdfs.filesystem</name> <value>hdfs://hadooptest:9000</value> </property>
- 全局配置
# 在 $CHUKWA_HOME/etc/chukwa/chukwa-env.sh 添加或修改如下项 export JAVA_HOME=/usr/java/default export CLASSPATH=.:$JAVA_HOME/lib export HADOOP_HOME=/usr/local/cloud/hadoop export CHUKWA_HOME=/usr/local/cloud/chukua export CHUKWA_CONF_DIR=${CHUKWA_HOME}/etc/chukwa export CHUKWA_PID_DIR=/data/pids/chukwa export CHUKWA_LOG_DIR=/data/logs/chukwa
- 监测文件设置
# 在 $CHUKWA_HOME/etc/chukwa/initial_adaptors 中添加要监测的日志文件, 但一般使用 telnet 链接到服务端的方式添加 # 格式为 add [name =] <adaptor_class_name> <datatype> <adaptor specific params> <initial offset> # 依次为: 监测接口的实现类 数据类型 起始点 日志文件 已收集的文件大小 add filetailer.CharFileTailingAdaptorUTF8 typeone 0 /data/logs/web/typeone.log 0 add filetailer.CharFileTailingAdaptorUTF8 typetwo 0 /data/logs/web/typetwo.log 0
7.2 启动服务¶
7.2.3 启动数据处理进程¶
sbin/start-data-processors.sh
[hadoop@hadooptest chukua]$ sbin/start-collectors.sh
localhost: starting collector, logging to /data/logs/chukwa/chukwa-hadoop-collector-hadooptest.out
localhost: WARN: option chukwa.data.dir may not exist; val = /chukwa
localhost: Guesses:
localhost: chukwaRootDir null
localhost: fs.default.name URI
localhost: nullWriter.dataRate Time
localhost: WARN: option chukwa.tmp.data.dir may not exist; val = /chukwa/temp
localhost: Guesses:
localhost: chukwaRootDir null
localhost: nullWriter.dataRate Time
localhost: chukwaCollector.tee.port Integral
[hadoop@hadooptest chukua]$ sbin/start-agents.sh
localhost: starting agent, logging to /data/logs/chukwa/chukwa-hadoop-agent-hadooptest.out
localhost: OK chukwaAgent.adaptor.context.switch.time [Time] = 5000
localhost: OK chukwaAgent.checkpoint.dir [File] = /data/logs/chukwa/
localhost: OK chukwaAgent.checkpoint.interval [Time] = 5000
localhost: WARN: option chukwaAgent.collector.retries may not exist; val = 144000
localhost: Guesses:
localhost: chukwaAgent.connector.retryRate Time
localhost: chukwaAgent.sender.retries Integral
localhost: chukwaAgent.control.remote Boolean
localhost: WARN: option chukwaAgent.collector.retryInterval may not exist; val = 20000
localhost: Guesses:
[hadoop@hadooptest chukua]$ sbin/start-data-processors.sh
starting archive, logging to /data/logs/chukwa/chukwa-hadoop-archive-hadooptest.out
starting demux, logging to /data/logs/chukwa/chukwa-hadoop-demux-hadooptest.out
starting dp, logging to /data/logs/chukwa/chukwa-hadoop-dp-hadooptest.out
[hadoop@hadooptest chukua]$
7.3 收集测试¶
7.3.1 构造测试数据¶
# 在 /data/logs/web/webone 中写入如下测试日志
- 10.0.0.10 [17/Oct/2011:23:20:40 +0800] GET /img/chukwa0.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.11 [17/Oct/2011:23:20:41 +0800] GET /img/chukwa1.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.12 [17/Oct/2011:23:20:42 +0800] GET /img/chukwa2.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.13 [17/Oct/2011:23:20:43 +0800] GET /img/chukwa3.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.14 [17/Oct/2011:23:20:44 +0800] GET /img/chukwa4.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.15 [17/Oct/2011:23:20:45 +0800] GET /img/chukwa5.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.16 [17/Oct/2011:23:20:46 +0800] GET /img/chukwa6.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.17 [17/Oct/2011:23:20:47 +0800] GET /img/chukwa7.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.18 [17/Oct/2011:23:20:48 +0800] GET /img/chukwa8.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 10.0.0.19 [17/Oct/2011:23:20:49 +0800] GET /img/chukwa9.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
# 在 /data/logs/web/webtwo 中写入如下测试日志
- 192.168.0.10 [17/Oct/2011:23:20:40 +0800] GET /img/chukwa0.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.11 [17/Oct/2011:23:21:40 +0800] GET /img/chukwa1.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.12 [17/Oct/2011:23:22:40 +0800] GET /img/chukwa2.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.13 [17/Oct/2011:23:23:40 +0800] GET /img/chukwa3.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.14 [17/Oct/2011:23:24:40 +0800] GET /img/chukwa4.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.15 [17/Oct/2011:23:25:40 +0800] GET /img/chukwa5.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.16 [17/Oct/2011:23:26:40 +0800] GET /img/chukwa6.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.17 [17/Oct/2011:23:27:40 +0800] GET /img/chukwa7.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.18 [17/Oct/2011:23:28:40 +0800] GET /img/chukwa8.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
- 192.168.0.19 [17/Oct/2011:23:29:40 +0800] GET /img/chukwa9.jpg HTTP/1.0 "404" "16" "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1;)"
7.3.2 模拟WEB日志¶
# 在 /data/logs/web/weblogadd.sh 中写入如下内容
#!/bin/bash
cat /data/logs/web/webone >> /data/logs/web/typeone.log
cat /data/logs/web/webtwo >> /data/logs/web/typetwo.log
# 设置脚本文件可执行
chmod +x weblogadd.sh
# 在 /etc/crontab 中添加定时任务以模拟WEB日志生成
*/1 * * * * hadoop /data/logs/web/weblogadd.sh
7.3.3 添加日志监控¶
# 链接到服务端的 telnet 服务
telnet hadooptest 9093
add org.apache.hadoop.chukwa.datacollection.adaptor.filetailer.CharFileTailingAdaptorUTF8 typeone 0 /data/logs/web/typeone.log 0
add org.apache.hadoop.chukwa.datacollection.adaptor.filetailer.CharFileTailingAdaptorUTF8 typetwo 0 /data/logs/web/typetwo.log 0
数据仓库工具¶
9.1 安装部署¶
9.1.1 环境要求¶
- 安装MySQL
sudo yum install -y mysql mysql-server mysql-devel # vim /etc/my.cnf # 在[mysqld]下添加 character_set_server=utf8 # 启动服务 sudo service mysqld start
- 添加hive用户
# 设置root密码 sudo mysqladmin -u root password 'rootadmin' # 以root登录 mysql -u root -prootadmin # 创建hive数据库 create database hive; alter database hive character set latin1; # 创建hive用户 GRANT ALL PRIVILEGES ON hive.* TO 'hive'@'localhost' IDENTIFIED BY 'hive' WITH GRANT OPTION; GRANT ALL PRIVILEGES ON hive.* TO 'hive'@'%' IDENTIFIED BY 'hive' WITH GRANT OPTION; # 退出后以hive用户测试 mysql -u hive -phive
- 下载驱动在
http://www.mysql.com/downloads/connector/j/ 下载最新的MySQL的Java驱动, 这里是
tar -zxvf mysql-connector-java-5.1.24.tar.gz cd mysql-connector-java-5.1.24/ cp mysql-connector-java-5.1.24-bin.jar /usr/local/cloud/hive/lib/
9.1.2 版本选择¶
9.1.3 目录规范¶
- 程序目录
tar -zxvf hive-0.10.0.tar.gz -C /usr/local/cloud/src/ cd /usr/local/cloud/ ln -s -f /usr/local/cloud/src/hive-0.10.0 hive
- 数据目录
# 创建存储查询日志的目录 # 每个用户的查询日志在 /data/logs/hive 中 mkdir -p /data/logs/hive/query
9.1.4 修改配置¶
- 系统设置
vim /etc/profile export HIVE_HOME=/usr/local/cloud/hive export PATH=$JAVA_HOME/bin:$HADOOP_HOME/bin:$CHUKWA_HOME/bin:$HIVE_HOME/bin:$PATH source /etc/profile
- 全局配置
- 使用 $HIVEHOME/conf/hive-env.sh 进行环境变量配置
# 配置项参见同目录下的 hive-env.sh.template export JAVA_HOME=/usr/java/default export HADOOP_HOME=/usr/local/cloud/hadoop export HIVE_HOME=/usr/local/cloud/hive export HIVE_CONF_DIR=$HIVE_HOME/conf export HADOOP_HEAPSIZE=1024
- 使用 $HIVEHOME/conf/hive-site.xml 进行参数配置
<!-- 添加hdfs设置 --> <property> <name>default.fs.name</name> <value>hdfs://hadooptest:9000</value> </property> <!-- 修改一下配置项 --> <!-- 临时存储目录设置 --> <property> <name>hive.exec.scratchdir</name> <value>/user/${user.name}/hive/scratchdir</value> <description>Scratch space for Hive jobs</description> </property> <property> <name>hive.exec.local.scratchdir</name> <value>/data/logs/hive/scratch/${user.name}</value> <description>Local scratch space for Hive jobs</description> </property> <!-- 数据文件存储目录 --> <property> <name>hive.metastore.warehouse.dir</name> <value>/hive/warehouse</value> <description>location of default database for the warehouse</description> </property> <!-- 查询日志存储目录 --> <property> <name>hive.querylog.location</name> <value>/data/logs/hive/query/${user.name}</value> <description>Location of Hive run time structured log file</description> </property> <!-- 使用MySQL存储元数据 --> <!-- MySQL服务器地址 --> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://hadooptest:3306/hive?createDatabaseIfNotExist=true&characterEncoding=UTF-8</value> <description>JDBC connect string for a JDBC metastore</description> </property> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> </property> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>hive</value> <description>username to use against metastore database</description> </property> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>hive</value> <description>password to use against metastore database</description> </property>
- 日志设置
# 在 $HIVE_HOME/conf/hive-log4j.properties 中设置日志数据目录 hive.log.dir=/data/logs/hive/${user.name}
9.2 使用方式¶
9.3 数据测试¶
9.4 处理流程¶
Date: 2013-04-28 10:38:30 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
高级数据分析语言¶
Date: 2013-04-28 10:38:26 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
分布式存储系统¶
Date: 2013-04-28 10:38:30 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24
Mahout¶
12.2 安装¶
12.2.1 要求¶
12.2.2 配置¶
tar -zxvf mahout-distribution-0.7.tar.gz -C /usr/local/cloud/src/
cd /usr/local/cloud/
ln -s -f /usr/local/cloud/src/mahout-distribution-0.7 mahout
12.3 测试¶
12.3.1 获取测试数据¶
wget http://archive.ics.uci.edu/ml/databases/synthetic_control/synthetic_control.data
12.3.3 测试各种算法¶
cd /usr/local/cloud/mahout/
# canopy
hadoop jar mahout-examples-0.7-job.jar org.apache.mahout.clustering.syntheticcontrol.canopy.Job
# kmeans
hadoop jar mahout-examples-0.7-job.jar org.apache.mahout.clustering.syntheticcontrol.kmeans.Job
12.4 推荐¶
12.4.1 协同过滤¶
- Taste简介
Taste 是 Apache Mahout
提供的一个协同过滤算法的高效实现,它是一个基于 Java 实现的可扩展的,高效的推荐引擎。Taste 既实现了最基本的基于用户的和基于内容的推荐算法,同时也提供了扩展接口,使用户可以方便的定义和实现自己的推荐算法。同时,Taste 不仅仅只适用于 Java 应用程序,它可以作为内部服务器的一个组件以 HTTP 和 Web Service 的形式向外界提供推荐的逻辑。Taste 的设计使它能满足企业对推荐引擎在性能、灵活性和可扩展性等方面的要求。
Taste原理
- 系统架构
接口设计
- DataModel
DataModel
是用户喜好信息的抽象接口,它的具体实现可能来自任意类型的数据源以抽取用户喜好信息。Taste提供了MySQLDataModel,方便用户通过JDBC和MySQL访问数据, 此外还通过FileDataModel提供了对文件数据源的支持。
- UserSimilarity 和 ItemSimilarity
UserSimilarity
用于定义两个用户间的相似度,它是基于协同过滤的推荐引擎的核心部分,可以用来计算用户的“邻居”,这里我们将与当前用户口味相似的用户称为他的邻居。ItemSimilarity 类似的,定义内容之间的相似度。
UserNeighborhood
用于基于用户相似度的推荐方法中,推荐的内容是基于找到与当前用户喜好相似的“邻居用户”的方式产生的。UserNeighborhood 定义了确定邻居用户的方法,具体实现一般是基于 UserSimilarity 计算得到的。
- Recommender
Recommender 是推荐引擎的抽象接口,Taste
中的核心组件。程序中,为它提供一个DataModel,它可以计算出对不同用户的推荐内容。实际应用中,主要使用它的实现类 GenericUserBasedRecommender 或者 GenericItemBasedRecommender,分别实现基于用户相似度的推荐引擎或者基于内容的推荐引擎。
Taste演示
- 拷贝到指定目录
cp ml-1m.zip /usr/local/cloud/mahout/ cd /usr/local/cloud/mahout/ unzip ml-1m.zip # 电影信息文件 格式为MovieID::MovieName::MovieTags cp movies.dat integration/src/main/resources/org/apache/mahout/cf/taste/example/grouplens/ # 打分信息文件 格式为UserID::MovieID::Rating::Timestamp cp ratings.dat integration/src/main/resources/org/apache/mahout/cf/taste/example/grouplens/ mvn install -DskipTests
- 修改pom文件添加对mahout-examples的依赖
<dependency> <groupId>${project.groupId}</groupId> <artifactId>mahout-examples</artifactId> <version>0.7</version> </dependency>
- 使用jetty进行测试
cd integration mvn jetty:run
访问如下地址查看效果http://hadooptest:8080/mahout-integration/RecommenderServlet?userID=1
- 命令行方式测试
mvn -q exec:java -Dexec.mainClass="org.apache.mahout.cf.taste.example.grouplens.GroupLensRecommenderEvaluatorRunner" -Dexec.args="-i /home/hadoop/cloud/ml-1m/ratings.dat"
- Taste示例
// 1. 选择数据源 // 数据源格式为UserID,MovieID,Ratings // 使用文件型数据接口 DataModel model = new FileDataModel(new File("/Users/matrix/Documents/plan/test/ratings.txt")); // 2. 实现相似度算法 // 使用PearsonCorrelationSimilarity实现UserSimilarity接口, 计算用户的相似度 // 其中PearsonCorrelationSimilarity是基于皮尔逊相关系数计算相似度的实现类 // 其它的还包括 // EuclideanDistanceSimilarity:基于欧几里德距离计算相似度 // TanimotoCoefficientSimilarity:基于 Tanimoto 系数计算相似度 // UncerteredCosineSimilarity:计算 Cosine 相似度 UserSimilarity similarity = new PearsonCorrelationSimilarity(model); // 可选项 similarity.setPreferenceInferrer(new AveragingPreferenceInferrer(model)); // 3. 选择邻居用户 // 使用NearestNUserNeighborhood实现UserNeighborhood接口, 选择最相似的三个用户 // 选择邻居用户可以基于'对每个用户取固定数量N个最近邻居'和'对每个用户基于一定的限制,取落在相似度限制以内的所有用户为邻居' // 其中NearestNUserNeighborhood即基于固定数量求最近邻居的实现类 // 基于相似度限制的实现是ThresholdUserNeighborhood UserNeighborhood neighborhood = new NearestNUserNeighborhood(3, similarity, model); // 4. 实现推荐引擎 // 使用GenericUserBasedRecommender实现Recommender接口, 基于用户相似度进行推荐 Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity); Recommender cachingRecommender = new CachingRecommender(recommender); List<RecommendedItem> recommendations = cachingRecommender.recommend(1234, 10); // 输出推荐结果 for (RecommendedItem item : recommendations) { System.out.println(item.getItemID() + "\t" + item.getValue()); }
12.4.2 聚类分析¶
框架设计
针对分组需求,Mahout的聚类算法将对象表示成一种简单的数据模型:向量,然后通过计算各向量间的相似度进行分组。
- 数据模型
在Mahout中向量(Vector)有多种实现.
- DenseVector
它的实现就是一个浮点数数组, 对向量里所有维度进行存储,
适合用于存储密集向量。
- RandomAccessSparseVector
基于浮点数的HashMap实现, key是整数类型, value是浮点数类型,
只存储向量中不为空的值, 并提供随机访问。
- SequentialAccessVector
实现为整数类型和浮点数类型的并行数组, 同样只存储不为空的值,
但只提供顺序访问
- 数据建模
Mahout为实现将数据建模成向量, 提供了对数据进行向量化的各种方法。
- 简单的整数类型或浮点型数据这种数据因为本身就被描述成一个向量, 因此可以直接存为向量。
// 创建一个二维点集的向量组 public static final double[][] points = { { 1, 1 }, { 2, 1 }, { 1, 2 }, { 2, 2 }, { 3, 3 }, { 8, 8 }, { 9, 8 }, { 8, 9 }, { 9, 9 }, { 5, 5 }, { 5, 6 }, { 6, 6 }}; public static List<Vector> getPointVectors(double[][] raw) { List<Vector> points = new ArrayList<Vector>(); for (int i = 0; i < raw.length; i++) { double[] fr = raw[i]; // 这里选择创建 RandomAccessSparseVector Vector vec = new RandomAccessSparseVector(fr.length); // 将数据存放在创建的 Vector 中 vec.assign(fr); points.add(vec); } return points; }
- 枚举类型数据这类数据是对物体的描述, 只是取值范围有限,
比如苹果的颜色数据包括: 红色、黄色和绿色, 则在数据建模时可以用数字表示颜色。 | 红色=1, 黄色=2, 绿色=3
// 创建苹果信息数据的向量组 public static List<Vector> generateAppleData() { List<Vector> apples = new ArrayList<Vector>(); // 这里创建的是 NamedVector,其实就是在上面几种 Vector 的基础上, // 为每个 Vector 提供一个可读的名字 NamedVector apple = new NamedVector(new DenseVector(new double[] {0.11, 510, 1}), "Small round green apple"); apples.add(apple); apple = new NamedVector(new DenseVector(new double[] {0.2, 650, 3}), "Large oval red apple"); apples.add(apple); apple = new NamedVector(new DenseVector(new double[] {0.09, 630, 1}), "Small elongated red apple"); apples.add(apple); apple = new NamedVector(new DenseVector(new double[] {0.18, 520, 2}), "Medium oval green apple"); apples.add(apple); return apples; }
- 文本信息
在信息检索领域中最常用的是向量空间模型,
文本的向量空间模型就是将文本信息建模成一个向量, 其中每个维度是文本中出现的一个词的权重。
常用算法
K均值聚类算法
- 原理
给定一个N个对象的数据集, 构建数据的K个划分,
每个划分就是一个聚类, K<=N, 需要满足两个要求:1.每个划分至少包含一个对象; 2. 每个对象必须属于且仅属于一个组。
- 过程
首先创建一个初始划分, 随机的选择K个对象,
每个对象初始的代表了一个划分的中心, 对于其它的对象, 根据其与各个划分的中心的距离, 把它们分给最近的划分。
然后使用迭代进行重定位,
尝试通过对象在划分间移动以改进划分。所谓重定位, 就是当有新的对象被分配到了某个划分或者有对象离开了某个划分时, 重新计算这个划分的中心。这个过程不断重复, 直到各个划分中的对象不再变化。
- 优缺点
当划分结果比较密集, 且划分之间的区别比较明显时,
- K均值的效果比较好。K均值算法复杂度为O(NKt), 其中t为迭代次数。
但其要求用户必须事先给出K值,
而K值的选择一般都基于一些经验值或多次实验的结果。而且, K均值对孤立点数据比较敏感, 少量这类的数据就能对评价值造成极大的影响。
示例
- 基于内存的单机应用(0.5版)
/** * 基于内存的K均值聚类算法实现 */ public static void kMeansClusterInMemoryKMeans(){ // 指定需要聚类的个数 int k = 2; // 指定K均值聚类算法的最大迭代次数 int maxIter = 3; // 指定K均值聚类算法的最大距离阈值 double distanceThreshold = 0.01; // 声明一个计算距离的方法,这里选择了欧几里德距离 DistanceMeasure measure = new EuclideanDistanceMeasure(); // 构建向量集,使用的是二维点集 List<Vector> pointVectors = getPointVectors(points); // 从点集向量中随机的选择k个向量作为初始分组的中心 List<Vector> randomPoints = chooseRandomPoints(pointVectors, k); // 基于前面选中的中心构建分组 List<Cluster> clusters = new ArrayList<Cluster>(); int clusterId = 0; for(Vector v : randomPoints){ clusters.add(new Cluster(v, clusterId ++, measure)); } // 调用 KMeansClusterer.clusterPoints 方法执行K均值聚类 List<List<Cluster>> finalClusters = KMeansClusterer.clusterPoints(pointVectors, clusters, measure, maxIter, distanceThreshold); // 打印最终的聚类结果 for(Cluster cluster : finalClusters.get(finalClusters.size() -1)) { System.out.println("Cluster id: " + cluster.getId() + " center: " + cluster.getCenter().asFormatString()); System.out.println("\tPoints: " + cluster.getNumPoints()); } }
- 基于Hadoop的集群应用(0.5版)注意:首先需要在MVN工程中添加如下依赖
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-core</artifactId> <version>1.0.4</version> </dependency> <dependency> <groupId>org.apache.mahout</groupId> <artifactId>mahout-core</artifactId> <version>0.5</version> </dependency> <dependency> <groupId>org.apache.mahout</groupId> <artifactId>mahout-utils</artifactId> <version>0.5</version> </dependency> <dependency> <groupId>org.apache.mahout</groupId> <artifactId>mahout-math</artifactId> <version>0.5</version> </dependency>
其次在集群上运行前需要进行相关配置# 需要在$HADOOP_HOME/conf/hadoop-env.sh中设置CLASSPATH export MAHOUT_HOME=/usr/local/cloud/mahout for f in $MAHOUT_HOME/lib/*.jar; do HADOOP_CLASSPATH=${HADOOP_CLASSPATH}:$f; done for f in $MAHOUT_HOME/*.jar; do HADOOP_CLASSPATH=$(HADOOP_CLASSPATH):$f; done
然后即可测试如下代码/** * 基于 Hadoop 的K均值聚类算法实现 * @throws Exception */ public static void kMeansClusterUsingMapReduce () throws Exception{ Configuration conf = new Configuration(); // 声明一个计算距离的方法,这里选择了欧几里德距离 DistanceMeasure measure = new EuclideanDistanceMeasure(); // 指定输入路径,基于 Hadoop 的实现是通过指定输入输出的文件路径来指定数据源的。 Path testpoints = new Path("testpoints"); Path output = new Path("output"); // 清空输入输出路径下的数据 HadoopUtil.delete(conf, testpoints); HadoopUtil.delete(conf, output); RandomUtils.useTestSeed(); // 在输入路径下生成点集,与内存的方法不同,这里需要把所有的向量写进文件 writePointsToFile(testpoints); // 指定需要聚类的个数,这里选择 2 类 int k = 2; // 指定 K 均值聚类算法的最大迭代次数 int maxIter = 3; // 指定 K 均值聚类算法的最大距离阈值 double distanceThreshold = 0.01; // 随机的选择k个作为簇的中心 Path clusters = RandomSeedGenerator.buildRandom(conf, testpoints, new Path(output, "clusters-0"), k, measure); // 调用 KMeansDriver.runJob 方法执行 K 均值聚类算法 KMeansDriver.run(testpoints, clusters, output, measure, distanceThreshold, maxIter, true, true); // 调用 ClusterDumper 的 printClusters 方法将聚类结果打印出来。 ClusterDumper clusterDumper = new ClusterDumper(new Path(output, "clusters-" + (maxIter - 1)), new Path(output, "clusteredPoints")); clusterDumper.printClusters(null); }
- 基于Hadoop的集群应用(0.7版)
public static void kMeansClusterUsingMapReduce() throws IOException, InterruptedException, ClassNotFoundException { Configuration conf = new Configuration(); // 声明一个计算距离的方法,这里选择了欧几里德距离 DistanceMeasure measure = new EuclideanDistanceMeasure(); File testData = new File("input"); if (!testData.exists()) { testData.mkdir(); } // 指定输入路径,基于 Hadoop 的实现是通过指定输入输出的文件路径来指定数据源的。 Path samples = new Path("input/file1"); // 在输入路径下生成点集,这里需要把所有的向量写进文件 List<Vector> sampleData = new ArrayList<Vector>(); RandomPointsUtil.generateSamples(sampleData, 400, 1, 1, 3); RandomPointsUtil.generateSamples(sampleData, 300, 1, 0, 0.5); RandomPointsUtil.generateSamples(sampleData, 300, 0, 2, 0.1); ClusterHelper.writePointsToFile(sampleData, conf, samples); // 指定输出路径 Path output = new Path("output"); HadoopUtil.delete(conf, output); // 指定需要聚类的个数,这里选择3 int k = 3; // 指定 K 均值聚类算法的最大迭代次数 int maxIter = 10; // 指定 K 均值聚类算法的最大距离阈值 double distanceThreshold = 0.01; // 随机的选择k个作为簇的中心 Path clustersIn = new Path(output, "random-seeds"); RandomSeedGenerator.buildRandom(conf, samples, clustersIn, k, measure); // 调用 KMeansDriver.run 方法执行 K 均值聚类算法 KMeansDriver.run(samples, clustersIn, output, measure, distanceThreshold, maxIter, true, 0.0, true); // 输出结果 List<List<Cluster>> Clusters = ClusterHelper.readClusters(conf, output); for (Cluster cluster : Clusters.get(Clusters.size() - 1)) { System.out.println("Cluster id: " + cluster.getId() + " center: " + cluster.getCenter().asFormatString()); } }
输出结果为:Cluster id: 997 center: {1:3.6810451340150467,0:3.8594229542914538} Cluster id: 998 center: {1:2.068611196044424,0:-0.5471173292759096} Cluster id: 999 center: {1:-0.6392433868275759,0:1.2972649625289365}
12.4.3 分类分析¶
Date: 2013-04-28 10:38:28 CST
Author: Cloud&Matrix
Org version 7.8.11 with Emacs version 24