Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
scala spark如何获取最新一天&x27;s记录_Scala_Apache Spark - Fatal编程技术网

scala spark如何获取最新一天&x27;s记录

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.

如果我有上述数据,如何获取每个用户最近一天的记录? 我试着使用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.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,我已经根据你的指南写了一些代码,你能给我的代码提供宝贵的建议吗,提前谢谢!)