import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._
//2023年12月22日
// bylee
//邮箱:matrix70@163.com
object 跨本初子午线_添加点v1 {
def main(args: Array[String]): Unit = {
//创建样例数据集,包含id、lon、lat和time四列
// 计算每个id下相邻两个点的lon差值,
// 如果差值大于180度,则记录该位置。接着在这些位置插入新的数据行,将lon设置为180,将lat设置为相邻两点lat的平均值,
// 将time设置为相邻两点时间的平均值。最后将原始数据和新添加的数据合并,并按id和time排序展示。
// 创建SparkSession
val spark = SparkSession.builder.appName("PointDataProcessing").getOrCreate()
// 创建样例数据
val data = Seq(
(1, 100.0, 50.0, "2022-01-01 12:00:00"),
(1, -100.0, 55.0, "2022-01-01 12:30:00"),
(2, 80.0, 40.0, "2022-01-01 13:00:00"),
(2, 100.0, 45.0, "2022-01-01 14:00:00"),
(3, 170.0, 60.0, "2022-01-01 15:00:00"),
(3, -170.0, 65.0, "2022-01-01 16:00:00")
)
// 将数据转换为DataFrame
val df = data.toDF("id", "lon", "lat", "time")
// 注册DataFrame为临时表
df.createOrReplaceTempView("point_data")
// 定义处理函数
def processPointData(inputDf: DataFrame): DataFrame = {
import spark.implicits._
// 计算连续两个点的lon差值
val lonDiffColumn = lag($"lon", 1).over(Window.partitionBy("id").orderBy("time")).as("prev_lon")
val dfWithLonDiff = inputDf.withColumn("lon_diff", when(abs($"lon" - $"prev_lon") > 180, true).otherwise(false))
// 添加新数据行
val interpolatedData = dfWithLonDiff.filter($"lon_diff" === true)
.withColumn("lon", lit(180)) // 新lon值设为180
.withColumn("lat", (lag($"lat", 1).over(Window.partitionBy("id").orderBy("time")) + $"lat") / 2) // 新lat值为相邻两点的平均值
.withColumn("time", (unix_timestamp($"time") + unix_timestamp(lag($"time", 1).over(Window.partitionBy("id").orderBy("time")))) / 2) // 新time值为相邻两点时间的平均值
// 合并原始数据和新添加的数据
val resultDf = inputDf.union(interpolatedData).orderBy("id", "time")
return resultDf
}
// 调用处理函数并显示处理结果
val processedDf = processPointData(df)
processedDf.show()
//v2版本:使用DataFrame API的join操作来实现相同的逻辑。这种方法避免了使用窗口函数,因此在数据量较大时可能具有更好的性能
// 定义处理函数
/* def processPointDataWithJoin(inputDf: DataFrame): DataFrame = {
import spark.implicits._
// 计算连续两个点的lon差值
val dfWithLeadLon = inputDf.withColumn("lead_lon", lead($"lon", 1).over(Window.partitionBy("id").orderBy("time")))
val dfWithLonDiff = dfWithLeadLon.withColumn("lon_diff", when(abs($"lead_lon" - $"lon") > 180, true).otherwise(false))
// 添加新数据行
val interpolatedData = dfWithLonDiff.filter($"lon_diff" === true)
.withColumn("lon", lit(180)) // 新lon值设为180
.withColumn("lat", (lead($"lat", 1).over(Window.partitionBy("id").orderBy("time")) + $"lat") / 2) // 新lat值为相邻两点的平均值
.withColumn("time", (unix_timestamp($"time") + unix_timestamp(lead($"time", 1).over(Window.partitionBy("id").orderBy("time")))) / 2) // 新time值为相邻两点时间的平均值
// 合并原始数据和新添加的数据
val resultDf = inputDf.join(interpolatedData, Seq("id", "lon", "lat", "time"), "outer").orderBy("id", "time")
return resultDf
}
// 调用使用join的处理函数并显示处理结果
val processedDfUsingJoin = processPointDataWithJoin(df)
processedDfUsingJoin.show()*/
}
}
轨迹大数据分析:革命性的地理空间分析与Apache Spark:处理空间不连续的点数据
于 2023-12-22 20:21:47 首次发布