现有如下数据文件需要处理
格式:CSV
位置:hdfs://myhdfs/input.csv
大小:100GB
字段:用户ID,位置ID,开始时间,停留时长(分钟)

4行样例:

UserA,LocationA,2018-01-01 08:00:00,60
UserA,LocationA,2018-01-01 09:00:00,60
UserA,LocationB,2018-01-01 10:00:00,60
UserA,LocationA,2018-01-01 11:00:00,60

解读:

样例数据中的数据含义是:
用户UserA,在LocationA位置,从8点开始,停留了60分钟
用户UserA,在LocationA位置,从9点开始,停留了60分钟
用户UserA,在LocationB位置,从10点开始,停留了60分钟
用户UserA,在LocationA位置,从11点开始,停留了60分钟

该样例期待输出:
UserA,LocationA,2018-01-01 08:00:00,120
UserA,LocationB,2018-01-01 10:00:00,60
UserA,LocationA,2018-01-01 11:00:00,60

处理逻辑:
1 对同一个用户,在同一个位置,连续的多条记录进行合并
2 合并原则:开始时间取最早时间,停留时长加和

要求:请使用Spark、MapReduce或其他分布式计算引擎处理

思路:按照按照用户ID和位置ID分组,分组之后按照时间列排序,由于数据之间的存在依赖关系,并且依赖关系比较连续,满足某种关系的数据要进行合并操作,因此使用sql部分的代码很难实现。在这使用的是将Dataset转化为RDD之后使用基于分区进行操作的方法处理数据。拿到相关的数据,按照时间顺序读取,判断,累加等进行处理。

 package com.zhf.streaming

 import java.text.SimpleDateFormat

 import org.apache.spark.Partitioner
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{Dataset, SparkSession} import scala.collection.mutable.ArrayBuffer
case class ResultData(userID:String,locationID:String,startTime:String,endTime:String,stayTime:Long)
object Test {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("test").master("local[*]").getOrCreate()
import spark.implicits._
import org.apache.spark.sql.functions._
val info = spark.read
.format("csv")
.option("path", "src/data/user.csv")
.load()
.toDF("userID", "locationID", "startTimes", "stayMinutes")
.as[(String, String, String, String)] val ds: Dataset[((String, String, String), ResultData)] = info.map {
case (userID, locationID, startTimes, stayMinutes) =>
//让起始时间+停留时间=结束时间
val sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date = sd.parse(startTimes)
val endTime = sd.format(date.getTime + (stayMinutes.trim.toInt * 60 * 1000))
((userID, locationID, startTimes), ResultData(userID, locationID, startTimes, endTime, stayMinutes.trim.toLong))
}.as[((String, String, String), ResultData)] //按照用户ID和位置ID分组,分组之后按照时间列排序
val newDS: RDD[((String, String, String), ResultData)] = ds.rdd.repartitionAndSortWithinPartitions(new Partitioner {
override def numPartitions: Int = 4 override def getPartition(key: Any): Int = key match {
case (userID, locationID, _) => (userID.hashCode + locationID.hashCode) % numPartitions
case _ => 0
}
})
val result = newDS.mapPartitions(iter => {
val listBuffer = iter.toBuffer
val buffer = ArrayBuffer.empty[ResultData]
var resultData: ResultData = null;
//分区内只有一个元素的情况
if (listBuffer.size == 1) {
resultData = listBuffer(0)._2;
buffer += resultData
} else {
//分区内有多个元素
listBuffer.foreach {
case ((userID, locationID, startTimes), currentData) =>
//初始化赋值
if (resultData == null) {
resultData = ResultData(userID, locationID, startTimes, currentData.endTime, currentData.stayTime)
} else {
//如果当前行的起始时间与上一行的结束时间相同
if (currentData.startTime == resultData.endTime) {
//合并 修改初始值
resultData = ResultData(currentData.userID, currentData.locationID, resultData.startTime, currentData.endTime, resultData.stayTime + currentData.stayTime)
} else {
//不相同的情况下,将上一行结果添加到结果集,并修改初始值
buffer += resultData
resultData = currentData
}
}
}
//最后一个元素对象
if (resultData != null) {
buffer += resultData
}
}
buffer.toIterator
})
result.collect()
.sortBy(_.startTime)
.foreach(println)
}
}

使用spark dataSet 和rdd 解决 某个用户在某个地点待了多长时间的更多相关文章

  1. 解决使用Touch ID API在回调时界面“长时间卡住”的问题

    Touch ID是iOS8上新公开的API,关于详细介绍和用法可以看CocoaChina的这两篇文章:上 和 下,在此篇文章中不再赘述. 我在app中需要的效果是如果touch id验证通过,则页面p ...

  2. Spark SQL 之 RDD、DataFrame 和 Dataset 如何选择

    引言 Apache Spark 2.2 以及以上版本提供的三种 API - RDD.DataFrame 和 Dataset,它们都可以实现很多相同的数据处理,它们之间的性能差异如何,在什么情况下该选用 ...

  3. Spark计算模型-RDD介绍

    在Spark集群背后,有一个非常重要的分布式数据架构,即弹性分布式数据集(Resilient Distributed DataSet,RDD),它是逻辑集中的实体,在集群中的多台集群上进行数据分区.通 ...

  4. Spark学习之RDD编程总结

    Spark 对数据的核心抽象——弹性分布式数据集(Resilient Distributed Dataset,简称 RDD).RDD 其实就是分布式的元素集合.在 Spark 中,对数据的所有操作不外 ...

  5. 使用Scala编写Spark程序求基站下移动用户停留时长TopN

    使用Scala编写Spark程序求基站下移动用户停留时长TopN 1. 需求:根据手机基站日志计算停留时长的TopN 我们的手机之所以能够实现移动通信,是因为在全国各地有许许多多的基站,只要手机一开机 ...

  6. Spark深入之RDD

    目录 Part III. Low-Level APIs Resilient Distributed Datasets (RDDs) 1.介绍 2.RDD代码 3.KV RDD 4.RDD Join A ...

  7. Spark学习之RDD

    RDD概述 什么是RDD RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的集合 ...

  8. spark教程(三)-RDD认知与创建

    RDD 介绍 spark 最重要的一个概念叫 RDD,Resilient Distributed Dataset,弹性分布式数据集,它是 spark 的最基本的数据(也是计算)抽象. 代码中是一个抽象 ...

  9. Spark——DataFrames,RDD,DataSets、广播变量与累加器

    Spark--DataFrames,RDD,DataSets 一.弹性数据集(RDD) 创建RDD 1.1RDD的宽依赖和窄依赖 二.DataFrames 三.DataSets 四.什么时候使用Dat ...

随机推荐

  1. micropython TPYBoard v201 简易的web服务器的实现过程

    转载请注明文章来源,更多教程可自助参考docs.tpyboard.com,QQ技术交流群:157816561,公众号:MicroPython玩家汇 前言 TPYBoard v201开发板上搭载了以太网 ...

  2. 个人用户永久免费,可自动升级版Excel插件,使用VSTO开发,Excel催化剂安装过程详解及安装失败解决方法

    因Excel催化剂用了VSTO的开发技术,并且为了最好的用户体验,用了Clickonce的布署方式(无需人工干预自动更新,让用户使用如浏览器访问网站一般,永远是最新的内容和功能).对安装过程有一定的难 ...

  3. 基于ng-zorro的ASP.NET ZERO前端实现之代码生成器

    上一篇介绍了集成ng-zorro的过程,本篇我们来看下如何用abp官方的生成器来生成前端代码. Abp官方提供了一个强大的代码生成器 ASP.NET Zero Power Tools,它的Visual ...

  4. Android系列教程之前言

    内容转载自我自己的博客 目前安卓的主流开发语言是Java,在正式开始Android系列的教程之前,需要知道一些基本内容 Android介绍 Android['ændrɔid] 是一个基于Linux 内 ...

  5. nginx 301跳转https后post请求失效问题解决

    app本地请求是http端口,后来升级https强制301跳转,设置如下 server { listen 80; server name www.XXX.com; rewrite ^/(.*)$ ht ...

  6. ubuntu/deepin 下下载wxpython

    1 输入apt-cache search wxpython 如果有返回信息 则输入 sudo apt-get install python-tools 2 否则 1.添加软件源地址到apt列表中.输入 ...

  7. 利用Idea重构功能及Java8语法特性——优化深层嵌套代码

    当遇到深层嵌套代码,如for,if,lambda表达式或内部类及这些代码的组合,这时我们可以通过Java 8的语法特性来进行优化. 下面的代码是一个嵌套循环的示例. public MappedFiel ...

  8. Linux基础文件查找

    一.文件查找 (一).命令文件 [root@linux ~]# chich ls //从PATH环境变量 [root@linux ~]# chereis vim [root@linux ~]# ech ...

  9. java常见面试题目(二)

    部分没有答案可以自行百度. 1.myeclipse与eclipse的区别. 2.说说对maven或者SVN的理解. 3.类的加载过程 (创建对象的过程)  1)子父类里静态属性 赋上默认初始值 如果有 ...

  10. 8、JAVA中的用户输入(I/0交互过程)

    这里在数组的学习中用到了用户输入,也就是交互模式,日常的数据,不可能每一次都是程序员定义好的,终究需要用户与程序之间进行交互,机器等待用户输入,用户通过键盘输入所需数据(数据包括,字符,字串,数值等) ...