Scala 将数据帧的一行拆分为多行
我想将数据帧中的一行转换为多行。如果小时数相同,则行不会被拆分,但如果小时数不同,则行将根据小时数的差异拆分为多行。我擅长使用dataframe函数或配置单元查询解决方案 输入表或数据帧 预期的输出表或数据帧Scala 将数据帧的一行拆分为多行,scala,apache-spark,dataframe,Scala,Apache Spark,Dataframe,我想将数据帧中的一行转换为多行。如果小时数相同,则行不会被拆分,但如果小时数不同,则行将根据小时数的差异拆分为多行。我擅长使用dataframe函数或配置单元查询解决方案 输入表或数据帧 预期的输出表或数据帧 请帮助我找到预期输出的解决方案。对于这种简单模式,最简单的解决方案是在为输入和输出模式定义case类之后使用 一个简单的UDF解决方案将返回一个序列,然后您可以使用functions.explode。远不如使用flatMap干净高效 最后但并非最不重要的一点是,您可以创建自己的表来生
请帮助我找到预期输出的解决方案。对于这种简单模式,最简单的解决方案是在为输入和输出模式定义case类之后使用 一个简单的UDF解决方案将返回一个序列,然后您可以使用functions.explode。远不如使用flatMap干净高效
最后但并非最不重要的一点是,您可以创建自己的表来生成UDF,但对于这个问题来说,这太过分了。您可以在映射操作中实现自己的逻辑,并使用flatMap来实现这一点 以下是我实施解决方案的粗略方式,您可以根据需要即兴创作
你能分享你已经尝试过的东西吗?用scala准备一个数据样本,而不是别人会用的屏幕截图,并尝试给出答案。如果你使用excel或屏幕截图,回答者会加倍努力。希望你能理解。非常感谢。它几乎没有改动。
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import java.time.{Duration, LocalDateTime}
import org.apache.spark.sql.Row
import scala.collection.mutable.ArrayBuffer
import sparkSession.sqlContext.implicits._
val df = Seq(("john", "2/9/2018", "2/9/2018 5:02", "2/9/2018 5:12"),
("smit", "3/9/2018", "3/9/2018 6:12", "3/9/2018 8:52"),
("rick", "4/9/2018", "4/9/2018 23:02", "5/9/2018 2:12")
).toDF("UserName", "Date", "start_time", "end_time")
val rdd = df.rdd.map(row => {
val result = new ArrayBuffer[Row]()
val formatter1 = DateTimeFormatter.ofPattern("d/M/yyyy H:m")
val formatter2 = DateTimeFormatter.ofPattern("d/M/yyyy H:mm")
val d1 = LocalDateTime.parse(row.getAs[String]("start_time"), formatter1)
val d2 = LocalDateTime.parse(row.getAs[String]("end_time"), formatter1)
if (d1.getHour == d2.getHour) result += row
else {
val hoursDiff = Duration.between(d1, d2).toHours.toInt
result += Row.fromSeq(Seq(
row.getAs[String]("UserName"),
row.getAs[String]("Date"),
row.getAs[String]("start_time"),
d1.plus(1, ChronoUnit.HOURS).withMinute(0).format(formatter2)))
for (index <- 1 until hoursDiff) {
result += Row.fromSeq(Seq(
row.getAs[String]("UserName"),
row.getAs[String]("Date"),
d1.plus(index, ChronoUnit.HOURS).withMinute(0).format(formatter1),
d1.plus(1 + index, ChronoUnit.HOURS).withMinute(0).format(formatter2)))
}
result += Row.fromSeq(Seq(
row.getAs[String]("UserName"),
row.getAs[String]("Date"),
d2.withMinute(0).format(formatter2),
row.getAs[String]("end_time")))
}
result
}).flatMap(_.toIterator)
rdd.collect.foreach(println)
[john,2/9/2018,2/9/2018 5:02,2/9/2018 5:12]
[smit,3/9/2018,3/9/2018 6:12,3/9/2018 7:00]
[smit,3/9/2018,3/9/2018 7:0,3/9/2018 8:00]
[smit,3/9/2018,3/9/2018 8:00,3/9/2018 8:52]
[rick,4/9/2018,4/9/2018 23:02,5/9/2018 0:00]
[rick,4/9/2018,5/9/2018 0:0,5/9/2018 1:00]
[rick,4/9/2018,5/9/2018 1:0,5/9/2018 2:00]
[rick,4/9/2018,5/9/2018 2:00,5/9/2018 2:12]