scala spark如何获取最新一天&x27;s记录
如果我有上述数据,如何获取每个用户最近一天的记录? 我试着使用groupByKey,但不知道scala spark如何获取最新一天&x27;s记录,scala,apache-spark,Scala,Apache Spark,如果我有上述数据,如何获取每个用户最近一天的记录? 我试着使用groupByKey,但不知道 data= """ user date item1 item2 1 2015-12-01 14 5.6 1 2015-12-01 10 0.6 1 2015-12-02 8 9.4 1 2015-12-02 90 1.3 2 2015-12-01 30 0.3 2 2015-12-01 89 1.2 2 2015-12-30 70 1.
data=
"""
user date item1 item2
1 2015-12-01 14 5.6
1 2015-12-01 10 0.6
1 2015-12-02 8 9.4
1 2015-12-02 90 1.3
2 2015-12-01 30 0.3
2 2015-12-01 89 1.2
2 2015-12-30 70 1.9
2 2015-12-31 20 2.5
3 2015-12-01 19 9.3
3 2015-12-01 40 2.3
3 2015-12-02 13 1.4
3 2015-12-02 50 1.0
3 2015-12-02 19 7.8
"""
然后我就不知道该怎么处理了。谁能给我一些建议吗?非常感谢:)
更新:
我更改了数据,现在用户在最近一天有几条记录,我想获取所有记录。Thx:)
第二次更新:
我想得到的结果是:
val user = data.map{
case(user,date,item1,item2)=>((user,date),Array(item1,item2))
}.groupByKey()
val data2=data.trim.split("\\n").map(_split("\\s+")).map{
f=>{(f(0),ArrayBuffer(
f(1),
f(2).toInt,
f(3).toDouble)
)}
}
val data3 = sc.parallelize(data2)
data3.reduceByKey((x,y)=>
if(x(0).toString.compareTo(y(0).toString)>=0) x++=y
else y).foreach(println)
现在我写了一些代码:
user1 (2015-12-02,Array(8,9.4),Array(90,1.3))
user2 (2015-12-31,Array(20,2.5))
user3 (2015-12-02,Array(13,1.4),Array(50,1.0),Array(19,7,8))
结果是:
val user = data.map{
case(user,date,item1,item2)=>((user,date),Array(item1,item2))
}.groupByKey()
val data2=data.trim.split("\\n").map(_split("\\s+")).map{
f=>{(f(0),ArrayBuffer(
f(1),
f(2).toInt,
f(3).toDouble)
)}
}
val data3 = sc.parallelize(data2)
data3.reduceByKey((x,y)=>
if(x(0).toString.compareTo(y(0).toString)>=0) x++=y
else y).foreach(println)
有什么可以改进的吗?:) 我认为最好的方法是将输入数据映射到元组的RDD,元组为
(user,(date,item1,item2))
,因此RDD将是userRdd:RDD[(Int,(date,Int,Double))]
从这里,您可以创建一个减缩器,该减缩器将接受两个元组,并生成另一个相同格式的元组,即日期值较大的元组:
(2,ArrayBuffer(2015-12-31, 20, 2.5))
(1,ArrayBuffer(2015-12-02, 8, 9.4, 2015-12-02, 90, 1.3))
(3,ArrayBuffer(2015-12-02, 13, 1.4, 2015-12-02, 50, 1.0, 2015-12-02, 19, 7.8))
从这里,您可以通过调用以下命令找到每个用户的最大值:
reduceMaxDate(a: (Date, Int, Double), b: (Date, Int, Double)) : (Date, Int, Double) = {
if(a._1 > b._1) a else b
}
这将为每个用户生成具有最大时间戳的元组。假设此数据集更大,如果数据检索模式是按日期键入的,则可能需要按日期进行分区 这将避免在读取时对所有数据进行完全扫描/洗牌,而是在写入时将行保留在正确的分区中。以下是脚本 斯卡拉
userRdd.reduceByKey(reduceMaxDate).
为了Pypark
val data = sc.textFile("file:///home/cloudera/data.txt")
val dataMap = data.map(x => (x.split(" +")(0), x))
val dataReduce = dataMap.reduceByKey((x, y) =>
if(x.split(" +")(1) >= y.split(" +")(1)) x
else y)
val dataUserAndDateKey = data.map(rec => ((rec.split(" +")(0), rec.split(" +")(1)), rec))
val dataReduceUserAndDateKey = dataReduce.map(rec => ((rec._2.split(" +")(0), rec._2.split(" +")(1)), rec(1)))
val joinData = dataUserAndDateKey.join(dataReduceUserAndDateKey)
joinData.map(rec => rec._2._1).foreach(println)
以下是输出:
import re
data = sc.textFile("file:///home/cloudera/data.txt")
dataMap = data.map(lambda rec: (re.split('\s+', rec)[0], rec))
dataReduce = dataMap.reduceByKey(lambda x, y: x if(re.split('\s+', x)[1] >= re.split('\s+', y)[1]) else y)
dataUserAndDateKey = data.map(lambda rec: ((re.split('\s+', rec)[0], re.split('\s+', rec)[1]), rec))
dataReduceUserAndDateKey = dataReduce.map(lambda rec: ((re.split('\s+', rec[1])[0], re.split('\s+', rec[1])[1]), rec[1]))
joinData = dataUserAndDateKey.join(dataReduceUserAndDateKey)
for i in joinData.collect(): print(i[1][0])
您还可以使用数据帧在SparkContext的HiveContext中使用SQL。以下是我的解决方案,共分4步。将其复制/粘贴到shell中,以查看每个步骤的输出
3 2015-12-02 13 1.4
3 2015-12-02 50 1.0
3 2015-12-02 19 7.8
2 2015-12-31 20 2.5
1 2015-12-02 8 9.4
1 2015-12-02 90 1.3
问题出在传统的窗口小说概念中。您的问题的答案是使用秩函数按用户划分和按日期排序。如果您在同一天对所有记录进行排名,则获得相同的排名,然后您可以使用rank=1过滤器简单地筛选出最新的记录
//Step 1. Prepare data
val input="""user date item1 item2
1 2015-12-01 14 5.6
1 2015-12-01 10 0.6
1 2015-12-02 8 9.4
1 2015-12-02 90 1.3
2 2015-12-01 30 0.3
2 2015-12-01 89 1.2
2 2015-12-30 70 1.9
2 2015-12-31 20 2.5
3 2015-12-01 19 9.3
3 2015-12-01 40 2.3
3 2015-12-02 13 1.4
3 2015-12-02 50 1.0
3 2015-12-02 19 7.8
"""
val inputLines=sc.parallelize(input.split("\\r?\\n"))
//filter the header row
val data=inputLines.filter(l=> !l.startsWith("user") )
data.foreach(println)
//Step 2. Find the latest date of each user
val keyByUser=data.map(line => { val a = line.split("\\s+"); ( a(0), line ) })
//For each user, find his latest date
val latestByUser = keyByUser.reduceByKey( (x,y) => if(x.split("\\s+")(1) > y.split("\\s+")(1)) x else y )
latestByUser.foreach(println)
//Step 3. Join the original data with the latest date to get the result
val latestKeyedByUserAndDate = latestByUser.map( x => (x._1 + ":"+x._2.split("\\s+")(1), x._2))
val originalKeyedByUserAndDate = data.map(line => { val a = line.split("\\s+"); ( a(0) +":"+a(1), line ) })
val result=latestKeyedByUserAndDate.join(originalKeyedByUserAndDate)
result.foreach(println)
//Step 4. Transform the result into the format you desire
def createCombiner(v:(String,String)):List[(String,String)] = List[(String,String)](v)
def mergeValue(acc:List[(String,String)], value:(String,String)) : List[(String,String)] = value :: acc
def mergeCombiners(acc1:List[(String,String)], acc2:List[(String,String)]) : List[(String,String)] = acc2 ::: acc1
//use combineByKey
val transformedResult=result.mapValues(l=> { val a=l._2.split(" +"); (a(2),a(3)) } ).combineByKey(createCombiner,mergeValue,mergeCombiners)
transformedResult.foreach(println)
现在,您可以过滤rank=1记录。我假设您有一些文本解析代码,您没有在示例中看到,对吗?您有时间吗?否则,你怎么知道哪一条是最新的?@JustinPihony我只想得到最近一天的记录,不需要具体时间:)问题是,在最近一天,用户有几条记录,我想得到所有记录。你的“第二次更新”reduceByKey中的x++是什么意思?我尝试了你的代码,但结果并不是我预期的。你的代码得到最近一天的记录,我想得到所有的记录。有点不同。:)根据您的要求进行更新,欢迎光临。我使用pyspark和spark shell在我的youtube频道itversity上传了很多spark的内容。也请接受这个作为答案。Thx,我已经根据你的指南写了一些代码,你能给我的代码提供宝贵的建议吗,提前谢谢!)