如何使用(Py)Spark汇总数据集中数据点之间的距离?

时间:2016-08-17 11:07:00

标签: apache-spark pyspark apache-spark-sql

我有一个时间段内用户的Lat / Lon格式的位置数据集。我想计算这些用户旅行的距离。样本数据集:

  

|时间戳|用户|纬度|经度|   | 1462838468 | 49B4361512443A4DA ... | 39.777982 | -7.054599 |   | 1462838512 | 49B4361512443A4DA ... | 39.777982 | -7.054599 |   | 1462838389 | 49B4361512443A4DA ... | 39.777982 | -7.054599 |   | 1462838497 | 49B4361512443A4DA ... | 39.777982 | -7.054599 |   | 1465975885 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |   | 1457723815 | 405C238E25FE0B9E7 ... | 37.177322 | -7.426781 |   | 1457897289 | 405C238E25FE0B9E7 ... | 37.177922 | -7.447443 |   | 1457899229 | 405C238E25FE0B9E7 ... | 37.177922 | -7.447443 |   | 1457972626 | 405C238E25FE0B9E7 ... | 37.18059 | -7.46128 |   | 1458062553 | 405C238E25FE0B9E7 ... | 37.177322 | -7.426781 |   | 1458241825 | 405C238E25FE0B9E7 ... | 37.178172 | -7.444512 |   | 1458244457 | 405C238E25FE0B9E7 ... | 37.178172 | -7.444512 |   | 1458412513 | 405C238E25FE0B9E7 ... | 37.177322 | -7.426781 |   | 1458412292 | 405C238E25FE0B9E7 ... | 37.177322 | -7.426781 |   | 1465197963 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |   | 1465202192 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |   | 1465923817 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |   | 1465923766 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |   | 1465923748 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |   | 1465923922 | 6E9E0581E2A032FD8 ... | 37.118362 | -8.205041 |

我曾想过使用自定义聚合器函数,但似乎没有Python支持。此外,操作需要按特定顺序在相邻点上完成,因此我不知道自定义聚合器是否可行。

我也查看了reduceByKey但距离函数似乎没有满足运算符要求。

有没有办法在Spark中以有效的方式执行此操作?

2 个答案:

答案 0 :(得分:6)

它看起来像窗口函数的工作。假设我们将距离定义为:

from pyspark.sql.functions import acos, cos, sin, lit, toRadians

def dist(long_x, lat_x, long_y, lat_y):
    return acos(
        sin(toRadians(lat_x)) * sin(toRadians(lat_y)) + 
        cos(toRadians(lat_x)) * cos(toRadians(lat_y)) * 
            cos(toRadians(long_x) - toRadians(long_y))
    ) * lit(6371.0)

您可以将窗口定义为:

from pyspark.sql.window import Window

w = Window().partitionBy("User").orderBy("Timestamp")

并使用lag计算连续观察之间的距离:

from pyspark.sql.functions import lag

df.withColumn("dist", dist(
    "longitude", "latitude",
    lag("longitude", 1).over(w), lag("latitude", 1).over(w)
).alias("dist"))

之后,您可以执行标准聚合。

答案 1 :(得分:2)

您可以使用SparkSQL中的Window函数计算两点之间的距离,然后将groupby与每个用户的距离相加。

以下是代码示例:https://gist.github.com/mr1azl/71f376e7efb6637a43b26a83e90d304a