文章目录
- 绪论
- 1、PageView和UserView
- 1.1、PageView(PV)
- 1.2、UserView(UV)
- 1.3、PV+UV
- 2、生成数据
- 3、代码
绪论
学大数据的初衷就是在海量的数据中挑选出我们需要的有价值的数据。今天这个例子就是模仿这个场景。海量数据下如何筛选并计算出我们需要的数据???
前提:500w条记录环境下(可以更多,视计算机性能而定),统计每天最热门的top3板块。
1、PageView和UserView
我们要统计的是最热门的top3板块,而热门如果只是简单地通过页面浏览量(PV)或者用户浏览量(UV)来决定都显得比较片面,这里我们综合这两者(0.3PV+0.7UV)来获取我们的需求。
PageView:浏览量。(有几次浏览就算几次)
UserView:用户量。(同一个用户同一天浏览一个模块多次,只能算一次)
通过上面的分析已经解释了PV和UV的含义,以及获取这两个值的具体操作思路。下面探讨一下,如何在这两个值的基础上,求出每天最热门的top3板块。
按照前面的操作已经获得了两个RDD,PVRDD、UVRDD。在这两个RDD上使用join连接,在join算子里面通过(0.3PV+0.7UV)可以获得每天的各个模块的一个热度值。将这个值排序。取前三名,就是我们要求的每天最热top3板块了。
2、生成数据
由于没有获取大量数据的条件,这里我们通过代码自己制造一部分数据来进行相关操作。我模仿的数据结构是:UUID 用户id 时间戳 页面id 模块名(中间用\t制表符分隔)
生成代码如下(请更换自己的包名):
package com.hpe.data;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.UUID;
/**
* seesionId userid time pageId channelId
* @author eversec
*/
public class MakeLogData {
public static void main(String[] args) throws Exception {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/logdata")));
Random random = new Random();
int logNUm = 5000000;
StringBuilder stringBuilder = new StringBuilder();
List<String> channelList = Arrays.asList("spark","hdfs","mr","yarn","hive","scala","python");
for (int i = 0; i < logNUm; i++) {
String sessionId = UUID.randomUUID().toString();
int userId = random.nextInt(10000);
int year = 2018;
int month = random.nextInt(12) + 1;
int day = random.nextInt(30) + 1;
int hour = random.nextInt(24);
int minute = random.nextInt(60);
int second = random.nextInt(60);
String dateTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
SimpleDateFormat form = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long time = form.parse(dateTime).getTime();
int pageId = random.nextInt(100);
String channel = channelList.get(i % channelList.size() );
stringBuilder.append(sessionId + "\t" + userId + "\t" + time + "\t" + pageId + "\t" + channel + "\n");
bw.write(stringBuilder.toString());
stringBuilder.delete(0, stringBuilder.length());
}
bw.flush();
bw.close();
}
}
3、代码
package com.hpe.spark.loganalyse
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import java.util.Date
import java.text.SimpleDateFormat
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions
import org.apache.spark.rdd.RDD
object PVAndUV {
def main(args: Array[String]): Unit = {
//配置信息
val conf = new SparkConf();
conf.setAppName("UV + PV")
conf.setMaster("local")
val sc = new SparkContext(conf)
//加载数据
val rdd = sc.textFile("d:/data/logdata")
//调用方法
val rdd2 = first(rdd)
//rdd2.saveAsTextFile("d:/data/Log2")
sc.stop()
}
//封装方法
def first(rdd:RDD[String]) = {
//切割字符串
val splitRDD = rdd.map { _.split("\t") }
//过滤,去除脏数据
val filterRDD = splitRDD.filter { _.length == 5 }
//PV model
val reduceRDD = pv(filterRDD)
//UV model
val reduceRDD2 = uv(filterRDD)
//jion 合并两个RDD
val unionRDD = reduceRDD.join(reduceRDD2)
//返回 时间_模块
//(时间_模块,(a,b))
val endRDD = unionRDD
.map(x =>{
val value = x._2._1 *0.3 + x._2._2 *0.7
(x._1,value)
})
.sortBy(_._2,false)
.map(x =>{
val day = x._1.split("_")(0)
val model = x._1.split("_")(1)
(day,model)
})
.groupByKey()
.map(x => {
val list = x._2.take(3)
(x._1,list)
}).foreach { println }
endRDD
}
//pv操作
def pv(filterRDD:RDD[Array[String]]) = {
val mapRDD = filterRDD.map { x => {
val time = x(2).toLong
val date = new Date(time)
val format = new SimpleDateFormat("yyyy-MM-dd")
val dateStr = format.format(date)
x(2) = dateStr
//返回 时间_模块
(x(2) + "_" + x(4),1)
} }
val reduceRDD=mapRDD.reduceByKey(_+_)
reduceRDD
}
//uv操作
def uv(filterRDD:RDD[Array[String]]) = {
val mapRDD2 = filterRDD.map { x => {
val time = x(2).toLong
val date = new Date(time)
val format = new SimpleDateFormat("yyyy-MM-dd")
val dateStr = format.format(date)
x(2) = dateStr
//返回 用户id_模块_时间
(x(1) + "_" + x(2) + "_" + x(4),null)
} }
//去重
val disRDD = mapRDD2.distinct()
//只需要key,组装二元组
val tupleRDD = disRDD.map(x =>{
val key = x._1
//key:会员id_时间_板块id
//把会员id切掉
val newKey = key.substring(key.indexOf("_")+1, key.length())
(newKey,1)
})
//累加
val reduceRDD2=tupleRDD.reduceByKey(_+_)
reduceRDD2
}
}