Spark SQL:如何减少一对多关系

时间:2015-11-11 21:44:58

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

我有以下数据框/表:

id|counter
23534074|1
23534074|2
23534074|3
24142005|1
24142005|2

我希望将其缩小为只有不同的ID(例如,通过获取第一个id行)。因此,结果数据框应如下所示:

id|counter
23534074|1
24142005|1

这是我到目前为止所做的:

我用以下内容阅读数据:

val tf = sqlContext.read.format("com.databricks.spark.csv")
  .option("header", "true")
  .option("delimiter", "|")
  .load("test.csv")

使用

创建一个tempTable
tf.registerTempTable("TF")

这就是我试图获得一个独特的" id"

sqlContext.sql("select distinct(id),counter from TF group by id,counter").show

但它没有给我预期的结果:

+--------+-------+
|      id|counter|
+--------+-------+
|23534074|      1|
|23534074|      2|
|23534074|      3|
|24142005|      1|
|24142005|      2|
+--------+-------+

有关如何使用Spark SQL执行此操作的任何想法? 谢谢!

1 个答案:

答案 0 :(得分:1)

目前还不清楚您的要求是什么,所以这里有几个选项:

  • counter列上的简单过滤,假设计数器是唯一的,1是您想要的值

    tf.where($"counter" === 1)
    

    相当于:

    SELECT * FROM tf WHERE counter = 1
    
  • 首先使用groupBy(此处没有订单保证,您获得的只是第一个遇到的值):

    tf.groupBy($"id").agg(first($"counter")).show
    

    相当于:

    SELECT id, FIRST(counter) AS counter FROM tf GROUP BY id
    
  • 窗口函数,当计数器提供一些排序并且您想要最低/最高值时,这很有用

    import org.apache.spark.sql.expressions.Window
    import org.apache.spark.sql.functions.rowNumber
    
    val w = Window.partitionBy($"id").orderBy($"counter")
    tf.withColumn("rn", rowNumber.over(w)).where($"rn" === 1).drop("rn")
    

    相当于

    SELECT id, counter FROM (
      SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY counter) rn FROM tf
    ) tmp WHERE rn = 1