我有一个RDD[Log]
文件,其中包含各种字段(username,content,date,bytes
),我希望为每个字段/列找到不同的内容。
例如,我想获得RDD中找到的最小/最大和平均字节数。当我这样做时:
val q1 = cleanRdd.filter(x => x.bytes != 0)
我得到了带有字节的RDD的完整行!= 0.但是我怎样才能实际求和它们,计算平均值,找到最小值/最大值等?如何从RDD中只选择一列并在其上应用转换?
编辑:普拉萨德告诉我有关更改类型数据帧时,他就如何使虽然没有做说明,而我不能在网站上找到了坚实的答案。任何帮助都会很棒。
编辑:LOG类:
case class Log (username: String, date: String, status: Int, content: Int)
使用cleanRdd.take(5).foreach(println)给出类似这样的东西
Log(199.72.81.55 ,01/Jul/1995:00:00:01 -0400,200,6245)
Log(unicomp6.unicomp.net ,01/Jul/1995:00:00:06 -0400,200,3985)
Log(199.120.110.21 ,01/Jul/1995:00:00:09 -0400,200,4085)
Log(burger.letters.com ,01/Jul/1995:00:00:11 -0400,304,0)
Log(199.120.110.21 ,01/Jul/1995:00:00:11 -0400,200,4179)
答案 0 :(得分:2)
嗯......你有很多问题。
所以...你有一个日志的抽象
case class Log (username: String, date: String, status: Int, content: Int, byte: Int)
Que - 如何从RDD中只选择一列。
答案 - 你有一个map
函数与RDD' s。因此,对于RDD[A]
,map
会使用A => B
类型的地图/转换函数将其转换为RDD[B]
。
val logRdd: RDD[Log] = ...
val byteRdd = logRdd
.filter(l => l.bytes != 0)
.map(l => l.byte)
阙 - 我怎么能真正总结它们呢?
答案 - 您可以使用reduce
/ fold
/ aggregate
来完成。
val sum = byteRdd.reduce((acc, b) => acc + b)
val sum = byteRdd.fold(0)((acc, b) => acc + b)
val sum = byteRdd.aggregate(0)(
(acc, b) => acc + b,
(acc1, acc2) => acc1 + acc2
)
注意::这里需要注意的一点是,Int
的总和可能会比Int
能够处理的更大。因此,在大多数现实生活中,我们应该至少使用Long
作为累加器,而不是Int
,这实际上会删除reduce
和fold
作为选项。而且我们只剩下聚合。
val sum = byteRdd.aggregate(0l)(
(acc, b) => acc + b,
(acc1, acc2) => acc1 + acc2
)
现在,如果您必须计算多个内容,例如min,max,avg,那么我建议您使用单个aggregate
而不是像这样的多个来计算它们,
// (count, sum, min, max)
val accInit = (0, 0, Int.MaxValue, Int.MinValue)
val (count, sum, min, max) = byteRdd.aggregate(accInit)(
{ case ((count, sum, min, max), b) =>
(count + 1, sum + b, Math.min(min, b), Math.max(max, b)) },
{ case ((count1, sum1, min1, max1), (count2, sum2, min2, max2)) =>
(count1 + count2, sum1 + sum2, Math.min(min1, min2), Math.max(max1, max2)) }
})
val avg = sum.toDouble / count
答案 1 :(得分:0)
查看DataFrame
API。您需要将RDD转换为DataFrame,然后您可以使用如下所示的min,max,avg函数:
val rdd = cleanRdd.filter(x => x.bytes != 0)
val df = sparkSession.sqlContext.createDataFrame(rdd, classOf[Log])
假设您想要对列bytes
进行操作,那么
import org.apache.spark.sql.functions._
df.select(avg("bytes")).show
df.select(min("bytes")).show
df.select(max("bytes")).show
在spark-shell中尝试以下内容。检查结果截图...
case class Log (username: String, date: String, status: Int, content: Int)
val inputRDD = sc.parallelize(Seq(Log("199.72.81.55","01/Jul/1995:00:00:01 -0400",200,6245), Log("unicomp6.unicomp.net","01/Jul/1995:00:00:06 -0400",200,3985), Log("199.120.110.21","01/Jul/1995:00:00:09 -0400",200,4085), Log("burger.letters.com","01/Jul/1995:00:00:11 -0400",304,0), Log("199.120.110.21","01/Jul/1995:00:00:11 -0400",200,4179)))
val rdd = inputRDD.filter(x => x.content != 0)
val df = rdd.toDF("username", "date", "status", "content")
df.printSchema
import org.apache.spark.sql.functions._
df.select(avg("content")).show
df.select(min("content")).show
df.select(max("content")).show