Spark流计算课程设计----帮助新手入门实践

一、概述

1.1 问题背景

某网站系统实时产生日志信息,记录用户对系统的访问信息,例如:IP地址,用户名称,访问时间,请求和响应信息,其中IP地址信息是表示全国各地用户的访问情况,对IP地址的详细分析,可以了解各个地区对该网站系统访问的活跃度,用以判断该网站公司对区域活动的推广情况和投入成本。本项目为网站运营方向常用技术案例。

1.2 本组完成的任务

  1. 对日志进行清洗。
  2. 统计24小时内的访问量Top10。
  3. 统计该时间段内的PV。
  4. 统计该时间段内的UV。
  5. 统计该时间段跳出用户信息
  6. 将获取到的结果存为本地文件result,并进行了可视化。

1.3 数据下载地址

https://download.csdn.net/download/zhiyeegao/12251446

 

二、数据格式分析

所给的数据文件名为access.log。其中每列的内容如下:

第一列:客户端用户的IP地址。

第二列:客户端用户名称,默认为- -。

第三列:客户端访问的时间与时区。例如:[04/Jan/2012:19:57:09 +0800]代表中国东8区2012年1月4号19点57分9秒。

第四列:记录请求的url和http协议。例如:GET /thread-1459739-1-1.html HTTP/1.1

第五列:记录请求状态,成功是200。

第六列:记录发给客户端的字节数。

第七列:记录从哪个页面链接访问过来的。

第八列:记录客户端浏览器相关信息。

三、数据处理方案

图-1 数据处理方案图

 

四、源码(scala)


import java.text._
import java.util._
import java.lang._
import java.io._
import org.apache.spark._
import scala.util.control._
object Clean {
  /**
  * 自定义数据预处理函数
  * @param line:String (line是access.log文件的每一行)
  * @return (IP+" "+d1)
  */
  def find_IP_Date(line:String):String={
    var IP:String = "";//字符串IP存储IP地址
    var d1:String = "";//字符串d1存储时间和时区
    try{
	//分割字符串得到IP字符串
    IP = line.split(" - ")(0).trim()
	//日期字符串的起点
    val left = line.indexOf("[")
	//日期字符串的终点
    val right = line.indexOf("]")
	//截取字符串得到日期字符串
    val date = line.substring(left + 1, right).trim()
    d1 = date
    }catch{
      case e:Exception=>println(e)//输出异常
    }
	//返回IP和日期
    return (IP+" "+d1)
  }
  /**
  * 自定义跳出用户判断函数
  * @param line:Array[Int] (line中是排好序的访问时间)
  * @return flag:Boolean
  */
  def choose(line:Array[Int]):Boolean={
	//flag标记选择结果
    var flag:Boolean = false
    for(i <- 1 until line.length){
	//如果时差大于1小时则认为用户跳出
      if(line(i)-line(i-1)>1)
        flag = true
    }
    return flag
  }

  def main(args:Array[String]){
	//创建文件输出流,将结果写入result文件
    val writer = new PrintWriter(new File("/root/result"))
	//创建SparkConf
    val conf = new SparkConf().setMaster("local[2]").setAppName("IP_Date_Clean")
	//创建SparkContext
    val sc = new SparkContext(conf);
	//创建lines RDD
    val lines = sc.textFile("/root/access.log")
	//数据预处理
    val words = lines.map(line=>find_IP_Date(line)).distinct()
    //words.take(10).foreach(println) //查看前10个,进行输出测试
      
    //统计PV
    println("total pv = " + words.count())//pv总数量等于日志的行数
    writer.println("total pv = " + words.count())//写入文件
	//创建hour_pv RDD存放每小时的pv数量
    val hour_pv = words.map(line=>(line.split(":")(1).toInt,1)).reduceByKey((a,b)=>a+b)
    println("one hour pv:")
    writer.println("one hour pv:")//写入文件
    hour_pv.foreach(println) //输出每小时的pv数量
    hour_pv.collect.map{line=>writer.println(line)}//写入文件
    
    //统计UV
	//创建ips RDD存放所有的IP地址
    val ips = words.map(line => line.split(" ")(0))
	//创建dips RDD存放去重后的IP地址
    val dips = ips.distinct()
    println("uv = " + dips.count())
    writer.println("uv = " + dips.count().toString())//写入文件

    //统计top10的IP (就是简单的IP计数和排序,然后取前10个)
    val pairs = ips.map { ip  => (ip,1) }
    val ipCounts = pairs.reduceByKey(_+_)
    val countips = ipCounts.map(ipCount  => (ipCount._2,ipCount._1))
    val sortedCountips = countips.sortByKey(false)
    val sortedipCounts = sortedCountips.map(sortedCountip =>(sortedCountip._2,sortedCountip._1))
    println("top 10 ip:")
    writer.println("top 10 ip:")//写入文件
    sortedipCounts.take(10).foreach(println)
    sortedipCounts.take(10).map{line=>writer.println(line.toString())}//写入文件
    
    //统计跳出数
    //time_interval等于1代表以一个小时作为用户跳出判断标准
    val time_interval = 1
	//创建time RDD存放IP和其对应小时
    val time = words.map(line => (line.split(" ")(0),line.split(":")(time_interval).toInt))
	//创建ip_time RDD对time进行分组,并存放IP和其对应时间数组
    val ip_time = time.groupByKey().map(line => (line._1,line._2.toArray.sorted))
    //ip_time.take(2).map(line => line._2.foreach(println)) //查看前2个,进行输出测试
	//创建jump_ip RDD存放跳出用户
    val jump_ip = ip_time.filter(line => choose(line._2))
    println("jump = " + jump_ip.count())
    writer.println("jump = " + jump_ip.count())//写入文件
    println("jump probability = " + jump_ip.count()*100.0/dips.count()+"%")
    writer.println("jump probability = " + jump_ip.count()*100.0/dips.count()+"%")//写入文件
    writer.close()//关闭文件输出流
  }  
}

 

五、总结

通过分析课设要求和日志文件,我主要使用了IP和time两个字段,围绕这两个字段的数据进行了一系列的RDD操作,提取了PV、UV、访问量TOP10和跳出数、跳出率等数据。

其中我遇到了两个问题:

(1)问题:在提取IP和time字段时,程序运行中断了。

   原因:文件中有一部分噪音数据,在提取字段时遇到异常,程序中止。

   解决方法:加上了try-catch,跳过异常就可以正常运行了。

(2)问题:在对(IP,Iterable)中的Iterable进行排序时报错。

   原因:我对Iterable的排序方法不熟悉。

   解决方法:将Iterable转换为Array。

 

六、结果展示

total pv = 344129
one hour pv:
(0,41)
(20,79107)
(21,90885)
(22,89733)
(19,3780)
(23,80583)
uv = 8549
top 10 ip:
(114.112.141.6,9364)
(113.31.47.158,7817)
(199.255.44.5,5744)
(111.13.8.250,4353)
(61.177.46.238,4124)
(203.80.118.166,2775)
(61.135.248.199,2626)
(124.16.186.16,2232)
(218.25.117.235,1936)
(203.208.60.175,1913)
jump_hour = 439
jump_hour probability = 5.135103520879635%
jump_minute = 3352
jump_minute probability = 39.20926424143175%
jump_second = 6282
jump_second probability = 73.48227862907943%
 

 

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一个可能的Spark课程设计项目是构建一个基于Spark的推荐系统。该系统可以接受用户的历史浏览记录和评分,然后使用协同过滤算法来生成每个用户的推荐列表。以下是该项目的一些主要组成部分: 1. 数据集:选择一个适当的数据集,例如MovieLens或Amazon电子商务数据集。数据集应包括用户的浏览历史记录和评分。 2. 数据清洗:清洗数据集以删除无效或不必要的数据,并将其转换为适合Spark处理的格式。 3. 特征工程:根据数据集的特点,选择适当的特征来表示每个用户和物品。这可以包括基本特征,例如用户和物品的ID,以及其他可能有用的特征,例如年龄,性别,品牌偏好等。 4. 模型训练:使用Spark ML库中的协同过滤算法(如ALS)来训练推荐模型。训练过程需要指定用户和物品特征向量的维度,以及其他参数。 5. 推荐生成:根据训练好的模型,为每个用户生成推荐列表。可以使用Spark的分布式计算能力,以最大化推荐的效率。 6. 评估:使用预留的测试数据来评估推荐系统的性能,并对系统进行优化和改进。 7. 用户界面:为该系统构建一个用户友好的界面,以便用户可以方便地使用它。 这个项目涉及到许多Spark的核心概念,包括数据清洗,特征工程,模型训练和推荐生成。它还需要一些机器学习和数据科学的知识,例如协同过滤算法和评估方法。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值