如何计算匹配相关条件的行?

时间:2017-05-03 19:40:33

标签: apache-spark apache-spark-sql

我的表格看起来像这样:

TripID    | Name | State  
    1     | John |  OH       
    2     | John |  OH  
    3     | John |  CA  
    4     | John |  OH  
    1     | Mike |  CA  
    2     | Mike |  CA  
    3     | Mike |  OH

我想先计算一下前往OH的人,然后是CA.

在上述情况下,它只是约翰,所以答案应该是1。

所以我想知道如何在SQL过滤中设置某个顺序来过滤结果?

1 个答案:

答案 0 :(得分:2)

我或许可能误解了你的问题,但如果你问的是:

  

有多少人首先前往OH,然后前往CA.

(草图)查询可以如下:

scala> trips.show
+------+----+-----+
|tripid|name|state|
+------+----+-----+
|     1|John|   OH|
|     2|John|   OH|
|     3|John|   CA|
|     4|John|   OH|
|     1|Mike|   CA|
|     2|Mike|   CA|
|     3|Mike|   OH|
+------+----+-----+

scala> trips.orderBy("name", "tripid").groupBy("name").agg(collect_list("state")).show
+----+-------------------+
|name|collect_list(state)|
+----+-------------------+
|John|   [OH, OH, CA, OH]|
|Mike|       [CA, CA, OH]|
+----+-------------------+

我现在看到,你有两个选择:

  1. (hard)编写一个用户定义的聚合函数(UDAF)来进行聚合(并将collect_list替换为包含不同状态的行程。)

  2. (更简单)编写一个用户定义的函数(UDF),它可以完成与上面的UDAF类似的工作(但collect_list收集了值之后)。

  3. (简单)使用functions(例如explode和/或window

  4. 让我们做一个简单的解决方案(不一定最有效!)。

    事实证明前面的groupBy并不是必需的(!)你可以单独使用窗口聚合来处理它(使用两次)。

    import org.apache.spark.sql.expressions.Window
    val byName = Window.partitionBy("name").orderBy("tripid")
    
    val distinctStates = trips.withColumn("rank", rank over byName).dropDuplicates("name", "state").orderBy("name", "rank")
    
    scala> distinctStates.show
    +------+----+-----+----+
    |tripid|name|state|rank|
    +------+----+-----+----+
    |     1|John|   OH|   1|
    |     3|John|   CA|   3|
    |     1|Mike|   CA|   1|
    |     3|Mike|   OH|   3|
    +------+----+-----+----+
    
    // rank again but this time use the pre-calculated distinctStates dataset
    val distinctStatesRanked = distinctStates.withColumn("rank", rank over byName).orderBy("name", "rank")
    
    scala> distinctStatesRanked.show
    +------+----+-----+----+
    |tripid|name|state|rank|
    +------+----+-----+----+
    |     1|John|   OH|   1|
    |     3|John|   CA|   2|
    |     1|Mike|   CA|   1|
    |     3|Mike|   OH|   2|
    +------+----+-----+----+
    
    val left = distinctStatesRanked.filter($"state" === "OH").filter($"rank" === 1)
    val right = distinctStatesRanked.filter($"state" === "CA").filter($"rank" === 2)
    scala> left.join(right, "name").show
    +----+------+-----+----+------+-----+----+
    |name|tripid|state|rank|tripid|state|rank|
    +----+------+-----+----+------+-----+----+
    |John|     1|   OH|   1|     3|   CA|   2|
    +----+------+-----+----+------+-----+----+