代码之家  ›  专栏  ›  技术社区  ›  Pramod Kumar

带列表和返回字符串的Spark“join”数据框

  •  0
  • Pramod Kumar  · 技术社区  · 6 年前

    我有以下数据框:

    DF1:
    +------+---------+
    |key1  |Value    |
    +------+---------+
    |[k, l]|      1  |
    |[m, n]|      2  |
    |[o]   |      3  |
    +------+---------+
    

    需要与另一个数据帧“连接”

    DF2:
    +----+
    |key2|
    +----+
    |k   |
    |l   |
    |m   |
    |n   |
    |o   |
    +----+
    

    因此输出如下所示:

    DF3:
    +--------------------+---------+
    |key3                |Value    |
    +--------------------+---------+
    |k:1 l:1 m:0 n:0 o:0 |      1  |
    |k:0 l:0 m:1 n:1 o:0 |      2  |
    |k:0 l:0 m:0 n:0 o:1 |      3  |
    +--------------------+---------+
    

    换句话说,输出数据帧应该有一个列,该列是DF2中所有行的字符串,每个元素后面应该跟一个1或0,指示该元素是否存在于DF1的key1列的列表中。

    我不知道该怎么办。有没有一个简单的自定义项可以让我完成我想要的?

    1 回复  |  直到 5 年前
        1
  •  3
  •   Alper t. Turker    6 年前

    这样的操作是可能的 DF2 所以你可以使用 udf :

    import spark.implicits._
    import org.apache.spark.sql.functions._
    
    val df1 = Seq(
      (Seq("k", "l"), 1), (Seq("m", "n"), 2), (Seq("o"), 3)
    ).toDF("key1", "value")
    val df2 = Seq("k", "l", "m", "n", "o").toDF("key2")
    
    val keys = df2.as[String].collect.map((_, 0)).toMap
    
    val toKeyMap = udf((xs: Seq[String]) => 
       xs.foldLeft(keys)((acc, x) => acc + (x -> 1)))
    
    
    df1.select(toKeyMap($"key1").alias("key3"), $"value").show(false)
    
    // +-------------------------------------------+-----+
    // |key3                                       |value|
    // +-------------------------------------------+-----+
    // |Map(n -> 0, m -> 0, l -> 1, k -> 1, o -> 0)|1    |
    // |Map(n -> 1, m -> 1, l -> 0, k -> 0, o -> 0)|2    |
    // |Map(n -> 0, m -> 0, l -> 0, k -> 0, o -> 1)|3    |
    // +-------------------------------------------+-----+
    

    如果只需要一个字符串:

    val toKeyMapString = udf((xs: Seq[String]) => 
       xs.foldLeft(keys)((acc, x) => acc + (x -> 1))
         .map { case (k, v) => s"$k: $v" }
         .mkString(" ")
    )
    
    
    df1.select(toKeyMapString($"key1").alias("key3"), $"value").show(false)
    // +------------------------+-----+
    // |key3                    |value|
    // +------------------------+-----+
    // |n: 0 m: 0 l: 1 k: 1 o: 0|1    |
    // |n: 1 m: 1 l: 0 k: 0 o: 0|2    |
    // |n: 0 m: 0 l: 0 k: 0 o: 1|3    |
    // +------------------------+-----+