赞
踩
本文章学习的是厦门大学大数据课程的实验案例——网站用户行为分析,着重于Hadoop平台的操作,而不是数据的分析
Linux系统:Ubuntu 14.04
Hadoop:2.7.7
MySQL:5.7.16
HBase:1.3.6
Hive:1.2.2
Sqoop:1.4.7
R:3.0.2
Eclipse:3.8
首先把数据集下载到Ubuntu的Download
目录中,然后把数据集存放到专门的位置/usr/local/bigdatacase/dataset
cd /usr/local ls sudo mkdir bigdatacase //这里会提示你输入当前用户(本教程是hadoop用户名)的密码 //下面给hadoop用户赋予针对bigdatacase目录的各种操作权限 sudo chown -R hadoop:hadoop ./bigdatacase cd bigdatacase //下面创建一个dataset目录,用于保存数据集 mkdir dataset //下面就可以解压缩user.zip文件 cd ~ //表示进入hadoop用户的目录 cd 下载 ls unzip user.zip -d /usr/local/bigdatacase/dataset cd /usr/local/bigdatacase/dataset ls
数据说明:
user_id(用户id)
item_id(商品id)
behaviour_type(包括浏览、收藏、加购物车、购买,对应取值分别是1、2、3、4)
user_geohash(用户地理位置哈希值,有些记录中没有这个字段值,所以后面我们会用脚本做数据预处理时把这个字段全部删除)
item_category(商品分类)
time(该记录产生时间)
文件第一行记录是每个字段的名称,对我们的分析没有用,故删除文件第一行的记录
cd /usr/local/bigdatacase/dataset
//下面删除raw_user中的第1行
sed -i '1d' raw_user //1d表示删除第1行,同理,3d表示删除第3行,nd表示删除第n行
//下面删除small_user中的第1行
sed -i '1d' small_user
//下面再用head命令去查看文件的前5行记录,就看不到字段名称这一行了
head -5 raw_user.csv
head -5 small_user.csv
接着丢弃user_geohash
字段,因为对我们的分析没有用。然后为每一行记录增加一个省份字段,用于后面的可视化分析。这里需要创建一个shell脚本来处理。
cd /usr/local/bigdatacase/dataset
vim pre_deal.sh
pre_deal.sh
的内容:
#!/bin/bash #下面设置输入文件,把用户执行pre_deal.sh命令时提供的第一个参数作为输入文件名称 infile=$1 #下面设置输出文件,把用户执行pre_deal.sh命令时提供的第二个参数作为输出文件名称 outfile=$2 #注意!!最后的$infile > $outfile必须跟在}’这两个字符的后面 awk -F "," 'BEGIN{ srand(); id=0; Province[0]="山东";Province[1]="山西";Province[2]="河南";Province[3]="河北";Province[4]="陕西";Province[5]="内蒙古";Province[6]="上海市"; Province[7]="北京市";Province[8]="重庆市";Province[9]="天津市";Province[10]="福建";Province[11]="广东";Province[12]="广西";Province[13]="云南"; Province[14]="浙江";Province[15]="贵州";Province[16]="新疆";Province[17]="西藏";Province[18]="江西";Province[19]="湖南";Province[20]="湖北"; Province[21]="黑龙江";Province[22]="吉林";Province[23]="辽宁"; Province[24]="江苏";Province[25]="甘肃";Province[26]="青海";Province[27]="四川"; Province[28]="安徽"; Province[29]="宁夏";Province[30]="海南";Province[31]="香港";Province[32]="澳门";Province[33]="台湾"; } { id=id+1; value=int(rand()*34); print id"\t"$1"\t"$2"\t"$3"\t"$5"\t"substr($6,1,10)"\t"Province[value] }' $infile > $outfile
代码解释:
第一行注释#!/bin/bash
:#!
是特殊的表示符,其后跟的是解释这个脚本的shell路径。有的是#!/bin/ba
,两者没有太大不同,只是有一些不同标准。#!/bin/sh
是#!/bin/bash
的缩减版。
上面代码的基本逻辑是:awk -F "," '处理逻辑' $infile>$outfile
。awk
命令对输入的文本逐行读取。-F
参数表示每一行记录的不同字段用什么分隔符,这里用的是逗号。
srand();
用来生成随机数的种子,id
用来为每一条数据添加一个唯一的身份值,rand
函数用来生成一个随机数,value
的值在0-33之间。substr($6,1,10)
是为了截取时间字段的年月日,参数含义是:$6
:表示第6个字段;1,10
:表示截取前十个字符。第6个字段类似于“2014-12-08 12”
,这样前十个字符就是年月日了。
put
语句:用"\t"
分割每一个字段,这里只选取第1、2、3、5、6字段
执行代码:
cd /usr/local/bigdatacase/dataset
bash ./pre_deal.sh small_user.csv user_table.txt
这里先处理这个小的数据文件small_user.csv
,等到在小的文件上运行成功后再用大的文件row_user.csv
启动HDFS,上传数据文件
cd /usr/local/hadoop
./sbin/start-all.sh
./bin/hdfs dfs -mkdir -p /bigdatacase/dataset
./bin/hdfs dfs -put /usr/local/bigdatacase/dataset/user_table.txt /bigdatacase/dataset
./bin/hdfs dfs -cat /bigdatacase/dataset/user_table.txt | head -10
代码逻辑:
HDFS中上传文件用-put
,后面接源文件和HDFS上的目的路径
首先启动mysql服务,再启动Hive,然后创建表格并导入数据
service mysql start
cd /usr/local/hive
./bin/hive
create database dblab;
use dblab;
#Hive中创建表格并从HDFS中导入数据的命令格式
CREATE EXTERNAL TABLE dblab.bigdata_user(id INT,uid STRING,item_id STRING,behavior_type INT,item_category STRING,visit_date DATE,province STRING) COMMENT 'Welcome to xmu dblab!' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE LOCATION '/bigdataset/dataset';
代码解释:
这里创建的是外部表,用EXTERNAL
参数表示,ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
指明文件的行分隔符,STORED AS TEXTFILE
指明文件存储形式,LOCATION '/bigdatacase/dataset';
指明文件在HDFS中的存储路径。
hive> use dblab;//切换数据库
hive> show tables;//显示数据库中的所有吧表
hive> show create table bigdata_user;//创建并查看表格的属性
hive> desc bigdata_user;//查看表的结构
//查看表中的内容
hive> select * from bigdata_user limit 10;
hive> select behavior_type from bigdata_user limit 10;
//嵌套查询
hive> select e.bh,e.it from (select behavior_type as bh,item_category as it from bigdata_user) as e limit 10;
hive> select count(*) from bigdata_user;
//查询uid不重复的数据有多少条
hive> select count(distinct uid) from bigdata_user;//distinct表示分离出每个不同的uid
hive> select count(*) from (select uid,item_id,behavior_type,item_category,visit_date,province from bigdata_user group by uid,item_id,behavior_type,item_category,visit_date,province having count(*)=1)a;//a是嵌套语句的别名
//查询2014-12-10到2014-12-13日有多少用户浏览了商品
hive> select count(*) from bigdata_user where behavior_type='1' and visit_date>'2014-12-10' and visit_date<'2014-12-13';
//以月的第n天为统计,显示第n天网站卖出去的商品个数
hive> select count(distinct uid),day(visit_date) from bigdata_user where behavior_type='4' group by day(visit_date);
//取给定时间和给定地点,求当天发出到该地点的货物的数量
hive> select count(*) from bigdata_user where visit_date='2014-12-12' and province='江西' and behavior_type='4';
//查询一件商品在某天的购买比例或浏览比例
hive> select count(*) from bigdata_user where visit_date='2014-12-12';
hive> select count(*) from bigdata_user where visit_date='2014-12-12' and behavior_type='4';
//查询某个用户在某一天点击网站占该天所有点击行为的比例(点击行为包括浏览,加入购物车,收藏,购买
hive> select count(*) from bigdata_user where uid=xxxxxxxx and visit_date='2014-12-12';
hive> select count(*) from bigdata_user where visit_date='2014-12-12';
//给定购买商品的数量范围,查询某一天在该网站的购买该数量商品的用户id
hive> select uid from bigdata_user where behavior_type='4' and visit_date='2014-12-12' group by uid having count(behavior_type='4')>5;
//某个地区的用户当天浏览网站的次数
hive> create table scan(province STRING,scan INT) COMMENT 'This is the search of bigdataday' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE;
hive> insert overwrite table scan select province,count(*) from bigdata_user where behavior_type='1' group by province;
//或者下面的语句结果也一样
hive> insert overwrite table scan select province,count(behavior_type) from bigdata_user where behavior_type='1' group by province;
hive> select * from scan;
//启动mysql服务
$ service mysql start
//启动Hadoop
$ cd /usr/local/hadoop
$ sbin/start-all.sh
//查看Hadoop启动的进程
$ jps
//启动Hive
$ cd /usr/local/hive
$ bin/hive
//创建临时表
hive> create table dblab.user_action(id STRING,uid STRING, item_id STRING, behavior_type STRING, item_category STRING, visit_date DATE, province STRING) COMMENT 'Welcome to xmu dblab!' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE;
创建完临时表后Hive会在HDFS文件系统中创建对应的数据文件,可以通过以下命令查看:
cd /usr/local/hadoop
./bin/hdfs dfs -ls /usr/hive/warehouse/dblab.db/user_action
结果如下:
-rwxr-xr-x 1 hadoop supergroup 15590786 2016-11-27 21:57 /user/hive/warehouse/dblab.db/user_action/000000_0
接下来将Hive中bigdata_user中的内容插入user_action:
hive> insert overwrite table user_action select * from bigdata_user;
首先在mysql中创建一个用来存放数据的表格:
$ mysql -u root -p
//显示所有数据库
mysql> show databases;
mysql> create database dblab;
mysql> use dblab;
mysql> create table `dblab`.`user_action` (`id` varchar(50),`uid` varchar(50),`item_id` varchar(50),`behavior_type` varchar(10),`item_category` varchar(50), `visit_date` DATE,`province` varchar(20)) ENGINE=InnoDB DEFAULT CHARSET=utf8;//engine参数设置表格的默认存储引擎,后面的参数设置表格的编码
mysql> exit
注意:要导入中文的话必须确保mysql的
character_set_server
的编码是utf8
而不是latin1
,可以通过命令show variables like "char%";
查看。like "char%"
表示要查看的变量长什么样子。修改方法:http://dblab.xmu.edu.cn/blog/install-mysql/。查看结果如下:
然后就可以用sqoop从Hive导入数据到mysql中了。
cd /usr/local/sqoop
./bin/sqoop export --connect jdbc:mysql://localhost:3306/dblab --username root --password mysql --table user_action --export-dir '/user/hive/warehouse/dblab.db/user_action' --fields-terminated-by '\t';
代码解释:
export
:从hive导入到mysql中
--connect jdbc:mysql://localhost:3306/dblab --username root --password mysql
:连接mysql的地址以及mysql用户的账号密码
—table
:mysql中的数据表格
—export-dir
:导入源的路径,这里是HDFS上hive表格的路径
—field-terminated-by
:行分隔符
执行完之后可以在mysql中查看导入的数据:
$ mysql -u root -p
mysql> use dblab;
mysql> select * from user_action limit 10;
首先启动HBase服务和HBase的shell命令,然后在HBase中创建表格,最后使用sqoop导入数据
cd /usr/local/hbase
./bin/start-hbase.sh
./bin/hbase shell
hbase> create 'user_action',{NAME=>'f1',VERSIONS=5}
代码解释:HBase中的SQL语句跟mysql的差别比较大,属性用
{}
括起来,赋值符号是⇒
,而且不用以分号结束。NAME
是列族名称,HBase是以列族为单位的一个NoSQL数据库,VERSIONS
是历史版本保留数量。
cd /usr/local/sqoop
./bin/sqoop import --connect jdbc:mysql://localhost:3306 --username root --password hadoop --table user_action --hbase-table user_action --column-family f1 --hbase-row-key id --hbase-create-table -m 1;
代码解释:
–hbase-table user_action #HBase中表名称
–column-family f1 #列簇名称
–hbase-row-key id #HBase 行键
–hbase-create-table #是否在不存在情况下创建表
-m 1 #启动 Map 数量
现在可以在HBase中查看导入的数据了:
hbase> scan 'user_action',{LIMIT=>10}
注:上面的命令是显示前10行数据,但是执行结果看起来却远不止10行。是因为HBase中每行显示的不是一行记录,而是一个单元格。
除了使用sqoop导入数据到HBase外,还可以用Java API把数据从本地导入到HBase中。Java代码如下:
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; public class HBaseImportTest extends Thread { public Configuration config; public HTable table; public HBaseAdmin admin; /** * 构造函数: * 构造一个实例需要指定这个HBase实例用到的表格和配置 **/ public HBaseImportTest() { config = HBaseConfiguration.create(); // config.set("hbase.master", "master:60000"); // config.set("hbase.zookeeper.quorum", "master"); try { table = new HTable(config, Bytes.toBytes("user_action")); admin = new HBaseAdmin(config); } catch (IOException e) { e.printStackTrace(); } } /** * 主函数 **/ public static void main(String[] args) throws Exception { if (args.length == 0) { //第一个参数是该jar所使用的类,第二个参数是数据集所存放的路径 throw new Exception("You must set input path!"); } String fileName = args[args.length-1]; //输入的文件路径是最后一个参数 HBaseImportTest test = new HBaseImportTest(); test.importLocalFileToHBase(fileName); } /** * 创建一个缓冲阅读器,逐行读取文件内容,将它上传到HBase中。结束时关闭缓冲阅读器和HBase表格,然后打印出执行时间。 **/ public void importLocalFileToHBase(String fileName) { long st = System.currentTimeMillis(); BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(new FileInputStream( fileName))); String line = null; int count = 0; while ((line = br.readLine()) != null) { count++; put(line); if (count % 10000 == 0) System.out.println(count); } } catch (IOException e) { e.printStackTrace(); } finally { if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } try { table.flushCommits(); table.close(); // must close the client } catch (IOException e) { e.printStackTrace(); } } long en2 = System.currentTimeMillis(); System.out.println("Total Time: " + (en2 - st) + " ms"); } /** * 将每一行的内容分割后与列名称一起上传 **/ @SuppressWarnings("deprecation") public void put(String line) throws IOException { String[] arr = line.split("\t", -1); String[] column = {"id","uid","item_id","behavior_type","item_category","date","province"}; if (arr.length == 7) { Put put = new Put(Bytes.toBytes(arr[0]));// rowkey for(int i=1;i<arr.length;i++){ put.add(Bytes.toBytes("f1"), Bytes.toBytes(column[i]),Bytes.toBytes(arr[i])); } table.put(put); // put to server } } /** * **/ public void get(String rowkey, String columnFamily, String column, int versions) throws IOException { long st = System.currentTimeMillis(); Get get = new Get(Bytes.toBytes(rowkey)); get.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column)); Scan scanner = new Scan(get); scanner.setMaxVersions(versions); ResultScanner rsScanner = table.getScanner(scanner); for (Result result : rsScanner) { final List<KeyValue> list = result.list(); for (final KeyValue kv : list) { System.out.println(Bytes.toStringBinary(kv.getValue()) + "\t" + kv.getTimestamp()); // mid + time } } rsScanner.close(); long en2 = System.currentTimeMillis(); System.out.println("Total Time: " + (en2 - st) + " ms"); } }
把上面代码打包成jar包,放到/usr/local/bigdatacase/hbase/
目录下,然后在HBase中创建一个user_action
表格,就可以用下面命令导入数据了。
/usr/local/hadoop/bin/hadoop jar /usr/local/bigdatacase/hbase/ImportHBase.jar HBaseImportTest /usr/local/bigdatacase/dataset/user_action.output
$ sudo apt-get install r-base
//进入R语言:
$ R
//退出R语言:
> q()
安装依赖库:
> install.package('RMySQL')
> install.package('gglot2')
> install.package('devtools')
> devtools::install_github('taiyun/recharts')
代码解释:
包的名称用单引号或者双引号包起来都可以。RMySQL
是一个提供了访问MySQL数据库的R语言程序接口;ggplot
和recharts
是提供绘图可视化的库。
安装R语言依赖包的过程中可能会有以下错误:
Configuration failed because libmysqlclient was not found. Try installing:
* deb: libmariadb-client-lgpl-dev (Debian, Ubuntu 16.04)
libmariadbclient-dev (Ubuntu 14.04)
* rpm: mariadb-devel | mysql-devel (Fedora, CentOS, RHEL)
* csw: mysql56_dev (Solaris)
* brew: mariadb-connector-c (OSX)
.................
ERROR: configuration failed for package ‘RMySQL’
* removing ‘/home/hadoop/R/x86_64-pc-linux-gnu-library/3.3/RMySQL’
下载的程序包在
‘/tmp/RtmpvEArxz/downloaded_packages’里
Warning message:
In install.packages("RMySQL") : 安装程序包‘RMySQL’时退出狀態的值不是0
这是由于用户系统所拥有的构件不一定都齐全,这里提示缺少libmysqlclient
,所以只需要按照提示在Linux中安装即可。如下:
sudo apt-get install libmariadb-client-lgpl-dev
在Linux系统中新建另外一个终端,然后执行下面命令启动MySQL数据库:
$ service mysql start
$ mysql -u root -p
mysql> use dblab;
再在R语言中创建表格并导入:
//查询R中的命令,如sort
?sort
library(RMySQL)//使用RMySQL库
conn <- dbConnect(MySQL(),dbname='dblab',username='root',password='mysql',host='127.0.0.1',port=3306)//R语言中的赋值符号是'<-'。连接MySQL,给出数据库名称、MySQL用户账号密码、地址和端口
user_action <- dbGetQuenry(conn,'select * from user_action')//使用dbGetQuenry函数查询MySQL中的数据并赋值给R语言中的表。传入的参数是连接信息和MySQL查询语句
分析消费者对商品的行为
summary(user_action$behavior_type)
//把消费者行为的数据类型转换为数值型
summary(as.numeric(user_action$behavior_type))
代码解释:summary()函数可以得到样本数据类型和长度,如果样本是数值型,我们还能得到样本数据的最小值、最大值、四分位数以及均值信息。
R语言中查询某个表格中的某个属性的代码格式是:表名$属性名
绘柱状图:
library(ggplot2)//导入ggplot库
ggplot(user_action,aes(as.numeric(behavior_type)))+geom_histogram()
代码解释:ggplot()绘制时,创建绘图对象,即第一个图层,包含两个参数(数据与变量名称映射).变量名称需要被包含aes函数里面。ggplot2的图层与图层之间用“+”进行连接。ggplot2包中的geom_histogram()可以很方便的实现直方图的绘制。
分析被购买总量前十的商品机器购买总量
temp <- subset(user_action,as.numeric(behavior_type)==4)
count <- sort(table(temp$item_category),decreasing = T)
print(count[1:10])
代码解释:首先创建一个只包含被购买商品的表格temp,然后对temp的中的商品种类进行从大到小的排序,再打印出前十的商品种类。
绘制散点图:
result <- as.data.frame(count[1:10])
ggplot(result,aes(Var1,Freq,col=factor(Var1)))+geom_point()
分析每年哪个月份购买数量最多:
month <- substr(user_action$visit_date,6,7)//截取出月份
user_action <- cbind(user_action,month)//增加一列月份的数据
ggplot(user_action,aes(as.numeric(behavior_type),col=factor(month)))+geom_histogram()+facet_grid(.~month)
aes()函数中的col属性可以用来设置颜色。factor()函数则是把数值变量转换成分类变量,作用是以不同的颜色表示。如果不使用factor()函数,颜色将以同一种颜色渐变的颜色表现。 facet_grid(.~month)表示柱状图按照不同月份进行分区。
由于MySQL获取的数据中只有11月份和12月份的数据,所以上图只有显示两个表格。
分析哪个省份的消费者购买欲望最强:
library(recharts)
rel <- as.data.frame(table(temp$province))
provinces <- rel$Var1
x = c()
for(n in provinces){
x[length(x)+1] = nrow(subset(temp,(province==n)))}
mapData <- data.frame(province=rel$Var1,count=x,stringsAsFactors=F)
eMap(mapData,namevar=~province,datavar=~count)
绘出中国地图大致如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。