Spark日志分析案例

绪论


  学大数据的初衷就是在海量的数据中挑选出我们需要的有价值的数据。今天这个例子就是模仿这个场景。海量数据下如何筛选并计算出我们需要的数据???

  前提:500w条记录环境下(可以更多,视计算机性能而定),统计每天最热门的top3板块。

1、PageView和UserView

  我们要统计的是最热门的top3板块,而热门如果只是简单地通过页面浏览量(PV)或者用户浏览量(UV)来决定都显得比较片面,这里我们综合这两者(0.3PV+0.7UV)来获取我们的需求。

 1.1、PageView(PV)

  PageView:浏览量。(有几次浏览就算几次)
  在这里插入图片描述

 1.2、UserView(UV)

  UserView:用户量。(同一个用户同一天浏览一个模块多次,只能算一次)
  在这里插入图片描述

 1.3、PV+UV


  通过上面的分析已经解释了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
  }
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值