在scala中按2列值的范围将1行拆分为多行

时间:2019-09-04 22:06:39

标签: scala dataframe apache-spark

有人知道在Scala中基于两列范围将行爆炸成多行的好方法吗?

例如,对于输入数据框:

start_ip_int | end_ip_int | country | city
100          | 105        | USA     | Boston

预期的输出数据帧为:

start_ip_int | end_ip_int | country | city   | ip
100          | 105        | USA     | Boston | 100
100          | 105        | USA     | Boston | 101
100          | 105        | USA     | Boston | 102
100          | 105        | USA     | Boston | 103
100          | 105        | USA     | Boston | 104
100          | 105        | USA     | Boston | 105

因此,根据列start_ip_intend_ip_int的范围,将一行分为6行。

1 个答案:

答案 0 :(得分:3)

如果您使用的是Spark 2.4+,请使用带有IP整数范围的sequence作为参数来生成ArrayType列,然后explode对其进行输入:

val df = Seq((100, 105, "USA", "Boston")).
  toDF("start_ip_int", "end_ip_int", "country", "city")

df.withColumn("ip", explode(sequence($"start_ip_int", $"end_ip_int"))).show
// +------------+----------+-------+------+---+                                    
// |start_ip_int|end_ip_int|country|  city| ip|
// +------------+----------+-------+------+---+
// |         100|       105|    USA|Boston|100|
// |         100|       105|    USA|Boston|101|
// |         100|       105|    USA|Boston|102|
// |         100|       105|    USA|Boston|103|
// |         100|       105|    USA|Boston|104|
// |         100|       105|    USA|Boston|105|
// +------------+----------+-------+------+---+

对于较旧的Spark版本,请考虑创建一个简单的UDF来模仿sequence函数:

val rangeSequence = udf{ (lower: Int, upper: Int) =>
  Seq.iterate(lower, upper - lower + 1)(_ + 1)
}

// Applying the UDF, followed by `explode`
df.withColumn("ip", explode(rangeSequence($"start_ip_int", $"end_ip_int")))