原意是想存档一份spark的wordcount的代码,但觉得wordcount能体现出的东西少了一些,再加上写成spark遇到了各种各样的坑,索性就把之前一个用java mapreduce写的用户行为日志统计的代码用scala的spark逻辑上大致实现了一次(不完全一致,有实现的细节差别),以证明初步写成一个spark程序。代码仅供参考map,reduce文件读写过程,由于缺少引用的相关包,单独的代码是不能直接运行的。两份代码都是在maven框架下写的,注意pom中的依赖,其中的spark版本最好要与集群配置的spark版本一致。
无论mapreduce, 还是写spark。给我感觉对于读入文件实际上是已经分了一个初始的<K,V>的,其中的K可能是一个void之类的,而每一个value对应的就是输入文件的每一行(可以自己修改规则)。
java mapreduce大致的逻辑比较简单,spark注意一下flatmap与map的区别。flatmap是将每一行的数据作了map后再做一个扁平化操作。比如做wordcount,输入文件是
123 456 123
123 456
如果直接对该文件进行map得到的结果是
Array[Array[(K,V)]]] = {
Array[(K,V)] = { (123,1), (456,1), (123, 1) }
Array[(K,V)] = { (123,1), (456,1) }
}
对其做flatmap可以得到
Array[(K,V)] = { (123,1), (456,1), (123, 1), (123,1), (456,1) }
方便下一步的shuffle与reduce操作。
而对于spark的reduce操作,除了可以写成下述的reduceByKey之外,还可以写成reduce根据key来定制对value的操作。这里一般是带入两个值进去然后写该两个value变为一个value的逻辑,暂时不知道是否能写成Java mapreduce中foreach求和之类的过程。
注意spark在map的时候不要随便返回一个null,可能会导致程序运行失败,返回一个该类型的空对象就好。
总的来说spark代码比mapreduce的短,并且扩展性更强(比如可以很方便的在做完一次mapreduce之后再接着做mapreduce)。当然只算是第一个spark代码,要学的东西还有很多。
Java mapreduce:
package com.news.rec.monitor;
import com.newsRec.model.UserActionLog;
import com.sohu.newsRec.parser.UserLogParser;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.