分组和过滤scala中数据框中的最高值

时间:2017-07-10 06:49:28

标签: sql scala apache-spark apache-spark-sql

我有一些这样的数据:

a,timestamp,list,rid,sbid,avgvalue
1,1011,1001,4,4,1.20
2,1000,819,2,3,2.40
1,1011,107,1,3,5.40
1,1021,819,1,1,2.10

在上面的数据中,我想根据标签找到哪个标记具有最高标记值(平均值)。像这样。

对于时间戳1011和1:

1,1011,1001,4,4,1.20
1,1011,107,1,3,5.40

输出结果为:

1,1011,107,1,3,5.40  //because for timestamp 1011 and tag 1 the higest avg value is 5.40

所以我需要选择这一栏。

我尝试了这个声明,但它仍然无法正常工作:

val highvaluetable = df.registerTempTable("high_value")
val highvalue = sqlContext.sql("select a,timestamp,list,rid,sbid,avgvalue  from high_value")   highvalue.select($"a",$"timestamp",$"list",$"rid",$"sbid",$"avgvalue".cast(IntegerType).as("higher_value")).groupBy("a","timestamp").max("higher_value")
 highvalue.collect.foreach(println)

任何帮助将不胜感激。

在我提出一些建议之后,我的数据仍然是重复的。

+---+----------+----+----+----+----+
|a| timestamp| list|rid|sbid|avgvalue|
+---+----------+----+----+----+----+
|  4|1496745915| 718|   4|   3|0.30|
|  4|1496745918| 362|   4|   3|0.60|
|  4|1496745913| 362|   4|   3|0.60|
|  2|1496745918| 362|   4|   3|0.10|
|  3|1496745912| 718|   4|   3|0.05|
|  2|1496745918| 718|   4|   3|0.30|
|  4|1496745911|1901|   4|   3|0.60|
|  4|1496745912| 718|   4|   3|0.60|
|  2|1496745915| 362|   4|   3|0.30|
|  2|1496745915|1901|   4|   3|0.30|
|  2|1496745910|1901|   4|   3|0.30|
|  3|1496745915| 362|   4|   3|0.10|
|  4|1496745918|3878|   4|   3|0.10|
|  4|1496745915|1901|   4|   3|0.60|
|  4|1496745912| 362|   4|   3|0.60|
|  4|1496745914|1901|   4|   3|0.60|
|  4|1496745912|3878|   4|   3|0.10|
|  4|1496745912| 718|   4|   3|0.30|
|  3|1496745915|3878|   4|   3|0.05|
|  4|1496745914| 362|   4|   3|0.60|
+---+----------+----+----+----+----+

 4|1496745918| 362|   4|   3|0.60|  
 4|1496745918|3878|   4|   3|0.10|

具有相同标签的相同时间戳。这被视为重复。

这是我的代码:

rdd.createTempView("v1")
val rdd2=sqlContext.sql("select max(avgvalue) as max from v1 group by  (a,timestamp)")
rdd2.createTempView("v2")
val rdd3=sqlContext.sql("select a,timestamp,list,rid,sbid,avgvalue from v1  join v2 on v2.max=v1.avgvalue").show()

4 个答案:

答案 0 :(得分:1)

您可以使用dataframe api查找max,如下所示:

df.groupBy("timestamp").agg(max("avgvalue"))

这将为您输出

+---------+-------------+
|timestamp|max(avgvalue)|
+---------+-------------+
|1021     |2.1          |
|1000     |2.4          |
|1011     |5.4          |
+---------+-------------+

不包含您​​需要的其他字段。所以你可以先用作

df.groupBy("timestamp").agg(max("avgvalue") as "avgvalue", first("a") as "a", first("list") as "list", first("rid") as "rid", first("sbid") as "sbid") 

你应该输出

+---------+--------+---+----+---+----+
|timestamp|avgvalue|a  |list|rid|sbid|
+---------+--------+---+----+---+----+
|1021     |2.1     |1  |819 |1  |1   |
|1000     |2.4     |2  |819 |2  |3   |
|1011     |5.4     |1  |1001|4  |4   |
+---------+--------+---+----+---+----+

上面的解决方案仍然不会给你正确的行输出,所以你可以做的是使用窗口函数并选择正确的行

import org.apache.spark.sql.functions._

val windowSpec = Window.partitionBy("timestamp").orderBy("a")

df.withColumn("newavg", max("avgvalue") over windowSpec)
  .filter(col("newavg") === col("avgvalue"))
  .drop("newavg").show(false)

这将给出行正确的数据

+---+---------+----+---+----+--------+
|a  |timestamp|list|rid|sbid|avgvalue|
+---+---------+----+---+----+--------+
|1  |1021     |819 |1  |1   |2.1     |
|2  |1000     |819 |2  |3   |2.4     |
|1  |1011     |107 |1  |3   |5.4     |
+---+---------+----+---+----+--------+

答案 1 :(得分:0)

您可以使用groupBy并找到该特定组的最大值

//If you have the dataframe as df than 

df.groupBy("a", "timestamp").agg(max($"avgvalue").alias("maxAvgValue"))

希望这有帮助

答案 2 :(得分:0)

我看到了上面的答案。下面是你可以尝试的那个

val sqlContext=new SQLContext(sc)
case class Tags(a:Int,timestamp:Int,list:Int,rid:Int,sbid:Int,avgvalue:Double)
val rdd=sc.textFile("file:/home/hdfs/stackOverFlow").map(x=>x.split(",")).map(x=>Tags(x(0).toInt,x(1).toInt,x(2).toInt,x(3).toInt,x(4).toInt,x(5).toDouble)).toDF
rdd.createTempView("v1")
val rdd2=sqlContext.sql("select max(avgvalue) as max from v1 group by (a,timestamp)")
rdd2.createTempView("v2")
val rdd3=sqlContext.sql("select a,timestamp,list,rid,sbid,avgvalue from v1 join v2 on v2.max=v1.avgvalue").show()

输出

+---+---------+----+---+----+--------+
|  a|timestamp|list|rid|sbid|avgvalue|
+---+---------+----+---+----+--------+
|  2|     1000| 819|  2|   3|     2.4|
|  1|     1011| 107|  1|   3|     5.4|
|  1|     1021| 819|  1|   1|     2.1|
+---+---------+----+---+----+--------+

答案 3 :(得分:0)

此处提供的所有其他解决方案都没有给我正确的答案,因此这就是 row_number() 的工作方式:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window

val windowSpec = Window.partitionBy("timestamp").orderBy(desc("avgvalue"))

df.select("a", "timestamp", "list", "rid", "sbid", "avgvalue")
  .withColumn("largest_avgvalue", row_number().over( windowSpec ))
  .filter($"largest_avgvalue" === 1)
  .drop("largest_avgvalue")

其他解决方案在我的测试中存在以下问题:

  • 使用.agg( max(x).as(x), first(y).as(y), ... )的解决方案不起作用,因为根据documentationfirst()函数“ 将返回它看到的第一个值”,这意味着非确定性的
  • 使用.withColumn("x", max("y") over windowSpec.orderBy("m") )的解决方案不起作用,因为max的结果将与为该行选择的值相同。我相信问题出在orderBy()"

因此,以下内容也给出了正确的答案,并使用 max()

val windowSpec = Window.partitionBy("timestamp").orderBy(desc("avgvalue"))
    
df.select("a", "timestamp", "list", "rid", "sbid", "avgvalue")
  .withColumn("largest_avgvalue", max("avgvalue").over( windowSpec ))
  .filter($"largest_avgvalue" === $"avgvalue")
  .drop("largest_avgvalue")