实验目的
1、了解Scala语言的基本语法
2、了解Spark Shell数据处理的原理
3、了解Spark 算子的使用
4、了解Spark shell和Mapreduce对数据处理的不同点
实验环境
1、Linux Ubuntu 14.04
2、jdk1.7
3、scala-2.10.4
4、hadoop-2.6.0-cdh5.4.5
5、spark-1.6.0-bin-hadoop2.6
实验内容
使用spark对数据进行WordCount统计、去重、排序、求平均值以及Join操作。
实验步骤
WordCount统计:
某电商网站数据文件/data/mydata/sparkshell/buyer_favorite,记录了用户对商品的收藏数据,数据及数据格式如下:
用户id(buyer_id),商品id(goods_id),收藏日期(dt)
- 用户id 商品id 收藏日期
- 10181 1000481 2010-04-04 16:54:31
- 20001 1001597 2010-04-07 15:07:52
- 20001 1001560 2010-04-07 15:08:27
- 20042 1001368 2010-04-08 08:20:30
- 20067 1002061 2010-04-08 16:45:33
- 20056 1003289 2010-04-12 10:50:55
- 20056 1003290 2010-04-12 11:57:35
- 20056 1003292 2010-04-12 12:05:29
- 20054 1002420 2010-04-14 15:24:12
- 20055 1001679 2010-04-14 19:46:04
- 20054 1010675 2010-04-14 15:23:53
- 20054 1002429 2010-04-14 17:52:45
- 20076 1002427 2010-04-14 19:35:39
- 20054 1003326 2010-04-20 12:54:44
- 20056 1002420 2010-04-15 11:24:49
- 20064 1002422 2010-04-15 11:35:54
- 20056 1003066 2010-04-15 11:43:01
- 20056 1003055 2010-04-15 11:43:06
- 20056 1010183 2010-04-15 11:45:24
- 20056 1002422 2010-04-15 11:45:49
- 20056 1003100 2010-04-15 11:45:54
- 20056 1003094 2010-04-15 11:45:57
- 20056 1003064 2010-04-15 11:46:04
- 20056 1010178 2010-04-15 16:15:20
- 20076 1003101 2010-04-15 16:37:27
- 20076 1003103 2010-04-15 16:37:05
- 20076 1003100 2010-04-15 16:37:18
- 20076 1003066 2010-04-15 16:37:31
- 20054 1003103 2010-04-15 16:40:14
- 20054 1003100 2010-04-15 16:40:16
现要求统计用户收藏数据中,每个用户收藏商品数量。
1、存储有用户收藏数据的用户文件buyer_favorite,放在/data/mydata/sparkshell目录下。
2、使用jps查看Hadoop以及spark的相关进程是否已经启动,若未启动则执行启动命令。
- cd /data/mydata/sparkshell/
- jps
- /apps/hadoop/sbin/start-all.sh
- /apps/spark/sbin/start-all.sh
将/data/mydata/sparkshell/buyer_favorite文件,上传到HDFS上的/mysparkshell目录下。若hdfs目录不存在则创建。
- hadoop fs -mkdir /mysparkshell
- hadoop fs -put /data/mydata/sparkshell/buyer_favorite /mysparkshell
3、启动spark-shell
- spark-shell
4、编写scala语句,统计用户收藏数据中,每个用户收藏商品数量。
先在spark-shell中,加载数据
- val rdd = sc.textFile("hdfs://localhost:9000/mysparkshell/buyer_favorite");
编写算子,执行统计,并输出
- rdd.map(line=> (line.split('\t')(0),1)).reduceByKey(_+_).collect
去重:
使用spark-shell,对上述实验中,用户收藏数据文件,进行统计。根据商品id进行去重,统计用户收藏数据中,都有哪些商品被收藏。
1、保证hadoop、spark框架相关进程为已启动状态,且保证所使用的数据,存放位置和上述实验一致。
2、编写scala语句,统计用户收藏数据中,都有哪些商品被收藏。
先加载数据,创建RDD
- val rdd = sc.textFile("hdfs://localhost:9000/mysparkshell/buyer_favorite");
使用算子,对RDD进行统计,并将结果打印输出
- rdd.map(line => line.split('\t')(1)).distinct.collect
排序:
电商网站一般都会对商品的访问情况,进行统计,现有一个文件/data/mydata/sparkshell/goods_visit文件,存储了各种商品,以及此商品的点击次数。
商品id(goods_id) 点击次数(click_num)
- 商品id 点击次数
- 1010037 100
- 1010102 100
- 1010152 97
- 1010178 96
- 1010280 104
- 1010320 103
- 1010510 104
- 1010603 96
- 1010637 97
- ... ...
现根据商品的点击次数进行排序,并输出所有商品
输出结果样式
- 点击次数 商品ID
- 96 1010603
- 96 1010178
- 97 1010637
- 97 1010152
- 100 1010102
- 100 1010037
- 103 1010320
- 104 1010510
- 104 1010280
1、商品点击数据goods_visit,放在/data/mydata/sparkshell/目录下。将数据,上传到HDFS的 /mysparkshell目录下
- cd /data/mydata/sparkshell
- hadoop fs -put /data/mydata/sparkshell/goods_visit /mysparkshell
2、启动spark-shell
- spark-shell
将测试数据变成RDD
- val rdd = sc.textFile("hdfs://localhost:9000/mysparkshell/goods_visit");
使用算子,对RDD进行统计,并将结果打印输出
- rdd.map(line => ( line.split('\t')(1).toInt, line.split('\t')(0) ) ).sortByKey(true).collect
3、输出结果样式为:
- scala> rdd.map(line => ( line.split('\t')(1).toInt, line.split('\t')(0) ) ).sortByKey(true).collect
- res8: Array[(Int, String)] = Array((96,1010178), (96,1010603), (97,1010152), (97,1010637), (100,1010037), (100,1010102), (103,1010320), (104,1010280), (104,1010510))
Join:
现有某电商在2011年12月15日的部分交易数据。数据有订单表orders和订单明细表order_items,表结构及数据分别为:
orders表:(订单id order_id, 订单号 order_number, 买家ID buyer_id, 下单日期 create_dt)
- 订单ID 订单号 买家ID 下单日期
- 52304 111215052630 176474 2011-12-15 04:58:21
- 52303 111215052629 178350 2011-12-15 04:45:31
- 52302 111215052628 172296 2011-12-15 03:12:23
- 52301 111215052627 178348 2011-12-15 02:37:32
- 52300 111215052626 174893 2011-12-15 02:18:56
- 52299 111215052625 169471 2011-12-15 01:33:46
- 52298 111215052624 178345 2011-12-15 01:04:41
- 52297 111215052623 176369 2011-12-15 01:02:20
- 52296 111215052622 178343 2011-12-15 00:38:02
- 52295 111215052621 178342 2011-12-15 00:18:43
order_items表:(明细ID item_id, 订单ID order_id, 商品ID goods_id )
- 明细ID 订单ID 商品ID
- 252578 52293 1016840
- 252579 52293 1014040
- 252580 52294 1014200
- 252581 52294 1001012
- 252582 52294 1022245
- 252583 52294 1014724
- 252584 52294 1010731
- 252586 52295 1023399
- 252587 52295 1016840
- 252592 52296 1021134
- 252593 52296 1021133
- 252585 52295 1021840
- 252588 52295 1014040
- 252589 52296 1014040
- 252590 52296 1019043
orders表和order_items表,通过订单id进行关联,是一对多的关系。
下面,请使用spark-shell,查询在当天该电商网站,都有哪些用户又购买了什么商品。
1、电商数据orders订单数据及order_items明细数据,放在/data/mydata/sparkshell/join目录下
2、将/data/mydata/sparkshell/join目录下的数据,上传到HDFS的/mysparkshell目录下
- hadoop fs -put /data/mydata/sparkshell/join/orders /mysparkshell
- hadoop fs -put /data/mydata/sparkshell/join/order_items /mysparkshell
3、检查HDFS及spark服务是否已经启动,然后启动spark-shell
- spark-shell
4、创建两个rdd,分别加载orders文件以及order_items文件中的数据。
- val rdd1 = sc.textFile("hdfs://localhost:9000/mysparkshell/orders");
- val rdd2 = sc.textFile("hdfs://localhost:9000/mysparkshell/order_items");
我们的目的是查询都有哪些用户购买了什么商品。所以对rdd1和rdd2进行map映射,得出关键的两个列的数据。
- val rdd11 = rdd1.map(line=> (line.split('\t')(0), line.split('\t')(2)) )
- val rdd22 = rdd2.map(line=> (line.split('\t')(1), line.split('\t')(2)) )
将rdd11以及rdd22中的数据,根据key值,进行join关联,得到最终结果
- val rddresult = rdd11 join rdd22
最后将结果输出,查看输出效果。
- rddresult.collect
最终的执行结果为:
- scala> rddresult.collect
- res6: Array[(String, (String, String))] = Array((52296,(178343,1021134)), (52296,(178343,1021133)), (52296,(178343,1014040)), (52296,(178343,1019043)), (52295,(178342,1023399)), (52295,(178342,1016840)), (52295,(178342,1021840)), (52295,(178342,1014040)))
将输出数据进行格式化
- (52296,(178343,1021134)),
- (52296,(178343,1021133)),
- (52296,(178343,1014040)),
- (52296,(178343,1019043)),
- (52295,(178342,1023399)),
- (52295,(178342,1016840)),
- (52295,(178342,1021840)),
- (52295,(178342,1014040))
可以看到上面数据关联后一共有3列,分别为订单id,用户id,商品id。
求平均值:电商网站一般都会对商品的访问情况,进行统计,现有一个文件goods_visit文件,存储了各种商品,以及此商品的点击次数。另外还有一张商品表(goods)记录了商品的基本信息。两张表的表结构如下:
goods表:商品ID(goods_id),商品状态(goods_status),商品分类id(cat_id),评分(goods_score)
goods_visit表:商品ID(goods_id),商品点击次数(click_num)
并且,商品表(goods)及商品访问情况(goods_visit),可以根据商品id进行关联。
现统计每个分类下,商品的平均点击次数是多少?
1、电商数据goods及goods_visit文件数据,放在/data/mydata/sparkshell/avg目录下
2、将/data/mydata/sparkshell/avg目录下的数据,上传到HDFS的/mysparkshell目录下
- hadoop fs -mkdir -p /mysparkshell/avg
- hadoop fs -put /data/mydata/sparkshell/avg/goods /mysparkshell/avg
- hadoop fs -put /data/mydata/sparkshell/avg/goods_visit /mysparkshell/avg
3、检查HDFS及spark服务是否已经启动,然后启动spark-shell
- spark-shell
4、创建两个rdd,分别加载goods文件以及goods_visit文件中的数据。
- val rdd1 = sc.textFile("hdfs://localhost:9000/mysparkshell/avg/goods");
- val rdd2 = sc.textFile("hdfs://localhost:9000/mysparkshell/avg/goods_visit");
我们的目的是统计每个分类下,商品的平均点击次数,我们可以分三步来做。
首先,对rdd1和rdd2进行map映射,得出关键的两个列的数据。
- val rdd11 = rdd1.map(line=> (line.split('\t')(0), line.split('\t')(2)) )
- val rdd22 = rdd2.map(line=> (line.split('\t')(0), line.split('\t')(1)) )
rdd11的样式
- scala> rdd11.collect
- res2: Array[(String, String)] = Array((1000002,52137), (1000003,52137), (1000004,52137), (1000006,52137), (1000007,52137), (1000008,52137), (1000010,52137), (1000011,52137), (1000015,52137), (1000018,52137), (1000020,52137), (1000021,52137), (1000025,52137), (1000028,52137), (1000030,52137), (1000033,52137), (1000035,52137), (1000037,52137), (1000041,52137), (1000044,52137), (1000048,52137), (1000050,52137), (1000053,52137), (1000057,52137), (1000059,52137), (1000063,52137), (1000065,52137), (1000067,52137), (1000071,52137), (1000073,52137), (1000076,52137), (1000078,52137), (1000080,52137), (1000082,52137), (1000084,52137), (1000086,52137), (1000087,52137), (1000088,52137), (1000090,52137), (1000091,52137), (1000094,52137), (1000098,52137), (1000101,52137), (1000103,52137), (1000106,52...
rdd22的样式
- scala> rdd22.collect
- res3: Array[(String, String)] = Array((1010000,4), (1010001,0), (1010002,0), (1010003,0), (1010004,0), (1010005,0), (1010006,74), (1010007,0), (1010008,0), (1010009,1081), (1010010,0), (1010011,0), (1010012,0), (1010013,44), (1010014,1), (1010018,0), (1010019,542), (1010020,1395), (1010021,18), (1010022,13), (1010023,27), (1010024,22), (1010025,295), (1010026,13), (1010027,1), (1010028,410), (1010029,2), (1010030,8), (1010031,6), (1010032,729), (1010033,72), (1010034,3), (1010035,328), (1010036,153), (1010037,100), (1010038,4), (1010039,3), (1010040,69), (1010041,1), (1010042,1), (1010043,21), (1010044,268), (1010045,11), (1010046,1), (1010047,1), (1010048,59), (1010049,15), (1010050,19), (1010051,424), (1010052,462), (1010053,9), (1010054,41), (1010055,64), (1010056,10), (1010057,3), (...
其次,将rdd11以及rdd22中的数据,根据商品id,也就是key值进行关联,得到一张大表。表结构变为:(商品id,(商品分类,商品点击次数))
- val rddjoin = rdd11 join rdd22
rddjoin的样式
- scala> rddjoin.collect
- res4: Array[(String, (String, String))] = Array((1013900,(52137,0)), (1010068,(52007,1316)), (1018970,(52006,788)), (1020975,(52091,68)), (1019960,(52111,0)), (1019667,(52045,16)), (1010800,(52137,6)), (1019229,(52137,20)), (1022649,(52119,90)), (1020382,(52137,0)), (1022667,(52021,150)), (1017258,(52086,0)), (1021963,(52072,83)), (1015809,(52137,285)), (1024340,(52084,0)), (1011043,(52132,0)), (1011762,(52137,2)), (1010976,(52132,34)), (1010512,(52090,8)), (1023965,(52095,0)), (1017285,(52069,41)), (1020212,(52026,46)), (1010743,(52137,0)), (1020524,(52064,52)), (1022577,(52090,13)), (1021974,(52069,22)), (1010543,(52137,0)), (1010598,(52136,53)), (1017212,(52108,45)), (1010035,(52006,328)), (1010947,(52089,8)), (1020964,(52071,86)), (1024001,(52063,0)), (1020191,(52046,0)), (1015739,(...
最后,在大表的基础上,进行统计。得到每个分类,商品的平均点击次数。
- rddjoin.map(x=>{(x._2._1, (x._2._2.toLong, 1))}).reduceByKey((x,y)=>{(x._1+y._1, x._2+y._2)}).map(x=>{(x._1, x._2._1*1.0/x._2._2)}).collect
将结果输出,查看输出效果。
- scala> rddjoin.map(x=>{(x._2._1, (x._2._2.toLong, 1))}).reduceByKey((x,y)=>{(x._1+y._1, x._2+y._2)}).map(x=>{(x._1, x._2._1*1.0/x._2._2)}).collect
- res40: Array[(String, Double)] = Array((52009,463.3642857142857), (52135,36.69230769230769), (52128,9.0), (52072,42.8), (52078,16.5), (52137,34.735241502683365), (52047,20.96551724137931), (52050,0.0), (52056,24.57894736842105), (52087,17.008928571428573), (52085,31.17142857142857), (52007,547.3076923076923), (52052,19.6), (52081,50.833333333333336), (52016,106.75), (52058,34.23170731707317), (52124,0.0), (52092,28.453703703703702), (52065,8.644444444444444), (52106,22.5), (52120,96.7843137254902), (52027,114.7), (52089,17.81159420289855), (52098,57.793103448275865), (52038,74.2), (52061,52.609375), (52104,49.0), (52014,45.4), (52012,53.26), (52100,22.0), (52043,23.0), (52030,532.48), (52023,150.0), (52083,57.857142857142854), (52041,40.0), (52049,18.058823529411764), (52074,33.17647058...
- scala>