Scala进阶之路-统计商家id的标签数以及TopN示例案例分析
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.项目需求
将“temptags.txt”中的数据进行分析,统计出商家id的评论标签数量,由于博客园无法上传大文件的文本,因此我把该文本的内容放在博客园的另一个链接了(需要的戳我),如果网页打不开的话也就可以去百度云盘里下载副本,链接:https://pan.baidu.com/s/1daRiwOVe6ohn42fTv6ysJg 密码:h6er。
我之前使用Hadoop的MapReduce实现过,详情请参考:https://www.cnblogs.com/yinzhengjie/p/9332761.html,但是实在过于繁琐,在学习Scala的时候发现它实现起来更简单。
二.代码实现
1 /*
2 @author :yinzhengjie
3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
4 EMAIL:y1053419035@qq.com
5 */
6
7 package cn.org.yinzhengjie.scala
8
9 /**
10 * 单例模式
11 */
12 object TaggenDemo {
13 //从json中抽取出所有评论,形成list返回
14 def extractTags(json:String) :List[String] = {
15 var list:List[String] = Nil
16 /**
17 * 注意这两个判断条件 :json != null && !json.equals("")
18 * 1>.json != null:
19 * 首先先说说null,这个null不管是在java还是Scala中它可以赋值给任意的引用数据类型。在调用toString方法时,都会抛
20 * 空指针异常,即“java.lang.NullPointerException”。
21 * 2>.!json.equals("")
22 * 接下来我们说说空字符串(""),这个空字符串("")它的长度为多少呢?很显然空字符串的长度为“0”,那么问题来了,它和null
23 * 有啥区别呢?打个简单的比方哈,在Java代码中,"String[] arr1 = null;"与"String[] arr2 = new String[0];"的区别你知道吗?
24 * 估计看到这两句话很多小伙伴已经不需要我多做解释了吧,没错,变量arr1是没有被初始化的,而arr2是被初始化且其长度为0.
25 */
26 if(json != null && !json.equals("")){
27 import com.alibaba.fastjson.JSON
28 //构造json对象
29 val obj = JSON.parseObject(json)
30 //提取数组属性
31 val arr = obj.getJSONArray("extInfoList")
32 if(arr != null && arr.size() > 0){
33 //提取数组一个json对象
34 val first = arr.getJSONObject(0)
35 //标签集合
36 val tags = first.getJSONArray("values")
37 if(tags != null && tags.size() > 0){
38 for(i <- 0 until tags.size()){
39 list = tags.getString(i) :: list
40 }
41 }
42 }
43 }
44 list
45 }
46 def main(args: Array[String]): Unit = {
47 /**
48 * 读取文件
49 */
50 import scala.io.Source
51 val f = Source.fromFile("D:\\BigData\\JavaSE\\yinzhengjieData\\temptags.txt")
52 val lines = f.getLines().toList
53 /**
54 * 切割每一行,提取busid ->tags
55 */
56 val var2 = lines.map(line=>{
57 val arr = line.split("\t")
58 val busid = arr(0)
59 val json = arr(1)
60 (busid , extractTags(json))
61 })
62 /**
63 * 过滤集合的空评论
64 */
65 val var3 = var2.filter(!_._2.isEmpty)
66 /**
67 * 压扁var3 , 形成 : (busid,tag)
68 */
69 val var4 = var3.flatMap(t=>{
70 var l:List[(String,String)] = Nil
71 for(tag <- t._2){
72 l = (t._1 , tag) :: l
73 }
74 l
75 })
76 /**
77 * 分组统计每个商家每条评论的数量,Map
78 */
79 var var5 = var4.groupBy(t=>t)
80 /**
81 * 统计每条评论个数,例如((75144086 , 环境优雅) , 22)
82 */
83 var var6 = var5.toList.map(t=>{
84 (t._1._1, (t._1._2 ,t._2.size))
85 })
86 /**
87 * 分组,将同一商家的所有评论聚在一起
88 */
89 var var7= var6.groupBy(t=>t._1)
90
91 /**
92 * mapValues方法只对value进行变换
93 */
94 var var8 = var7.mapValues(t=>{
95 t.map(t=>t._2)
96 })
97 /**
98 * 对每个商家的所有评论按照数量倒排序
99 */
100 var var9= var8.mapValues(t=>{
101 t.sortBy(t=> -t._2 )
102 })
103 /**
104 * 按照上架第一个标签的评论数进行排序
105 */
106 var var10 = var9.toList.sortBy(t=>{
107 -t._2(0)._2
108 })
109 /**
110 * 取出前10个元素,有两种方式,即take或者slice.是不是发现Scala中实现topN要比Java中的MapReduce要简单的多?
111 */
112 val res = var10.take(10) //当然我们也可以用切片的方式取出该元素: val res = var10.slice(0,10)
113
114 /**
115 * 打印我们得到的数据
116 */
117 for(e <- res){
118 println(e)
119 }
120 }
121 }
122
123
124
125 /*
126 以上代码执行结果如下:
127 (75144086,List((8239,60), (服务热情,38), (8241,31), (效果赞,30), (环境优雅,22), (无办卡,22), (性价比高,21), (技师专业,21), (无推销,19), (价格实惠,18), (干净卫生,13), (体验好,12), (韩系风格,10), (美发师手艺好,3), (服务差,2), (美发效果好,1), (效果差,1)))
128 (77287793,List((干净卫生,29), (音响效果好,26), (环境优雅,26), (价格实惠,25), (交通便利,25), (性价比高,19), (服务热情,18), (高大上,16), (停车方便,13), (体验好,13), (服务一般,1), (音响效果差,1), (朋友聚会,1), (服务差,1)))
129 (74145782,List((服务热情,18), (味道赞,14), (干净卫生,13), (上菜快,13), (菜品不错,12), (分量足,11), (回头客,11), (环境优雅,11), (性价比高,6), (停车方便,5), (体验好,4), (不推荐,3), (服务差,2), (菜品差,2), (分量少,1), (6,1), (价格实惠,1), (体验差,1)))
130 (85648235,List((味道赞,17), (服务热情,15), (干净卫生,13), (上菜快,12), (回头客,11), (性价比高,10), (体验好,9), (价格实惠,8), (环境优雅,8), (分量足,7), (情侣约会,1)))
131 (83073343,List((干净卫生,17), (味道赞,16), (环境优雅,15), (菜品不错,11), (服务热情,11), (肉类好,9), (性价比高,8), (体验好,7), (分量足,7), (回头客,6), (价格实惠,4), (味道一般,1), (分量少,1), (5,1), (服务差,1), (上菜慢,1), (2,1)))
132 (73607905,List((菜品不错,16), (干净卫生,15), (回头客,15), (味道赞,14), (服务热情,14), (分量足,13), (性价比高,11), (肉类好,11), (环境优雅,7), (体验好,5), (上菜快,5), (体验差,2), (羊蝎子,1), (价格实惠,1)))
133 (73963176,List((味道赞,15), (价格实惠,12), (分量足,11), (菜品不错,10), (肉类好,7), (干净卫生,7), (服务热情,7), (环境优雅,6), (回头客,4), (性价比高,3), (价格高,1), (服务差,1), (味道一般,1)))
134 (78824187,List((价格实惠,13), (回头客,11), (分量足,10), (环境优雅,8), (性价比高,8), (干净卫生,7), (上菜快,6), (2,6), (服务热情,5), (主食赞,5), (味道赞,4), (1,1), (3,1), (服务差,1)))
135 (87994574,List((无推销,12), (价格实惠,8), (干净卫生,7), (服务热情,7), (效果赞,5), (无办卡,5), (环境优雅,4), (技师专业,3), (体验好,2), (没有异味,2), (韩系风格,1), (效果差,1)))
136 (76893145,List((服务热情,10), (环境优雅,7), (高大上,5), (味道赞,5), (咖啡厅,5), (回头客,4), (温馨浪漫,3), (服务一般,2), (体验好,2), (味道一般,2), (饮品赞,1), (性价比高,1)))
137 */