Apache spark 如何在使用pyspark从自己的数据帧中选择的spark数据帧中执行计算
我有一个pyspark模式,如下所示:Apache spark 如何在使用pyspark从自己的数据帧中选择的spark数据帧中执行计算,apache-spark,pyspark,apache-spark-sql,Apache Spark,Pyspark,Apache Spark Sql,我有一个pyspark模式,如下所示: root |-- id: string (nullable = true) |-- long: float (nullable = true) |-- lat: float (nullable = true) |-- geohash: string (nullable = true) |-- neighbors: array (nullable = true) | |-- element: string (containsNull = t
root
|-- id: string (nullable = true)
|-- long: float (nullable = true)
|-- lat: float (nullable = true)
|-- geohash: string (nullable = true)
|-- neighbors: array (nullable = true)
| |-- element: string (containsNull = true)
+---+---------+----------+---------+--------------------+
| id| lat| long|geohash_8| neighbors|
+---+---------+----------+---------+--------------------+
| 0|-6.361755| 106.79653| qqggy1yu|[qqggy1ys, qqggy1...|
| 1|-6.358584|106.793945| qqggy4ky|[qqggy4kw, qqggy4...|
| 2|-6.362967|106.798775| qqggy38m|[qqggy38j, qqggy3...|
| 3|-6.358316| 106.79832| qqggy680|[qqggy4xb, qqggy6...|
| 4| -6.36016| 106.7981| qqggy60j|[qqggy4pv, qqggy6...|
| 5|-6.357476| 106.79842| qqggy68j|[qqggy4xv, qqggy6...|
| 6|-6.360814| 106.79435| qqggy4j3|[qqggy4j1, qqggy4...|
| 7|-6.358231|106.794365| qqggy4t2|[qqggy4t0, qqggy4...|
| 8|-6.357654| 106.79736| qqggy4x7|[qqggy4x5, qqggy4...|
| 9|-6.358781|106.794624| qqggy4mm|[qqggy4mj, qqggy4...|
| 10|-6.357654| 106.79443| qqggy4t7|[qqggy4t5, qqggy4...|
| 11|-6.357079| 106.79443| qqggy4tr|[qqggy4tp, qqggy4...|
| 12|-6.359929| 106.79698| qqggy4pn|[qqggy4ny, qqggy4...|
| 13|-6.358111| 106.79633| qqggy4w9|[qqggy4w3, qqggy4...|
| 14|-6.359685| 106.79607| qqggy4q8|[qqggy4q2, qqggy4...|
| 15|-6.357945|106.794945| qqggy4td|[qqggy4t6, qqggy4...|
| 16|-6.360725|106.795456| qqggy4n4|[qqggy4jf, qqggy4...|
| 17|-6.363701| 106.79653| qqggy1wb|[qqggy1w8, qqggy1...|
| 18| -6.36329|106.794586| qqggy1t7|[qqggy1t5, qqggy1...|
| 19|-6.363304| 106.79429| qqggy1t5|[qqggy1sg, qqggy1...|
+---+---------+----------+---------+--------------------+
数据如下所示:
root
|-- id: string (nullable = true)
|-- long: float (nullable = true)
|-- lat: float (nullable = true)
|-- geohash: string (nullable = true)
|-- neighbors: array (nullable = true)
| |-- element: string (containsNull = true)
+---+---------+----------+---------+--------------------+
| id| lat| long|geohash_8| neighbors|
+---+---------+----------+---------+--------------------+
| 0|-6.361755| 106.79653| qqggy1yu|[qqggy1ys, qqggy1...|
| 1|-6.358584|106.793945| qqggy4ky|[qqggy4kw, qqggy4...|
| 2|-6.362967|106.798775| qqggy38m|[qqggy38j, qqggy3...|
| 3|-6.358316| 106.79832| qqggy680|[qqggy4xb, qqggy6...|
| 4| -6.36016| 106.7981| qqggy60j|[qqggy4pv, qqggy6...|
| 5|-6.357476| 106.79842| qqggy68j|[qqggy4xv, qqggy6...|
| 6|-6.360814| 106.79435| qqggy4j3|[qqggy4j1, qqggy4...|
| 7|-6.358231|106.794365| qqggy4t2|[qqggy4t0, qqggy4...|
| 8|-6.357654| 106.79736| qqggy4x7|[qqggy4x5, qqggy4...|
| 9|-6.358781|106.794624| qqggy4mm|[qqggy4mj, qqggy4...|
| 10|-6.357654| 106.79443| qqggy4t7|[qqggy4t5, qqggy4...|
| 11|-6.357079| 106.79443| qqggy4tr|[qqggy4tp, qqggy4...|
| 12|-6.359929| 106.79698| qqggy4pn|[qqggy4ny, qqggy4...|
| 13|-6.358111| 106.79633| qqggy4w9|[qqggy4w3, qqggy4...|
| 14|-6.359685| 106.79607| qqggy4q8|[qqggy4q2, qqggy4...|
| 15|-6.357945|106.794945| qqggy4td|[qqggy4t6, qqggy4...|
| 16|-6.360725|106.795456| qqggy4n4|[qqggy4jf, qqggy4...|
| 17|-6.363701| 106.79653| qqggy1wb|[qqggy1w8, qqggy1...|
| 18| -6.36329|106.794586| qqggy1t7|[qqggy1t5, qqggy1...|
| 19|-6.363304| 106.79429| qqggy1t5|[qqggy1sg, qqggy1...|
+---+---------+----------+---------+--------------------+
我想计算每个id与其lat long的距离,然后选择所有邻居的lat long,然后计算距离。然后每个id都会有一个与所有邻居的距离列表(以米为单位)
我尝试使用迭代的方法,循环每一行,然后选择一个数据帧,然后计算哈弗森距离,但是性能很差。我一直在研究如何在spark中使用函数式方法进行应用。任何人都可以提供一些建议或参考。更新以满足对组合的需求
如果要进行所有组合,步骤基本上是,将每个邻居ID与其lat/long相关联,将它们分组到每个组合集的一行中,然后计算所有组合的距离。下面是示例代码:
从pyspark.sql.types导入*
从pyspark.sql.functions导入*
从pyspark.sql导入行
进口itertools
schema=StructType[
StructFieldid,StringType,
StructFieldlat,FloatType,
StructFieldlong,FloatType,
StructFieldgeohash_8,StringType,
StructFieldNeights,ArrayTypeStringType
]
数据=[
0,10.0,11.0,A[B,C,D],
1,12.0,13.0,B[D],,
2,14.0,15.0,C,[],
3,16.0,17.0,D,[]
]
input_df=spark.createDataFramesc.parallelizedata,模式
分解以获得每个比较对的一行
df=输入_df.使用列'neighbor',分解'neighbors'。删除'neighbors'
加入以获取邻居的lat/lon
neighbor\u map=input\u df.选择expr'geohash\u 8作为nid'、'lat作为nlat'、'long as NLNG'
df=df.joinneighbor\u映射,col'neighbor'==col'nid','inner'。删除'nid'
分组前为根geohash_8记录添加行
root\u rows=input\u df.selectExprid、lat、long、geohash\u 8、geohash\u 8作为邻居、lat作为nlat、long作为nlong
df=df.unionAllroot\u行
分组方式将行回滚,但现在将lat/lon与相邻行关联
df=df.selectExprid、lat、long、geohash_8、structneighbor、nlat、nlong作为邻居
df=df.groupByid,lat,long,geohash_8.aggcollect_setneights.aliasneights
现在,您在一个字段中拥有了所需的所有数据,因此可以编写python udf来进行组合
定义计算距离左纬度、左纬度、右纬度、右纬度:
返回10.0
def组合进气歧管:
结果=[]
对于itertools.CombinationsInghbors中的左侧和右侧,2:
距离=计算距离左['nlat'],左['nlong'],右['nlat'],右['nlong']
result.appendRowleft=left['neighbor'],right=right['neighbor'],dist=dist
返回结果
udf_schema=ArrayTypeStructType[
StructFieldleft,StringType,
StructFieldright,StringType,
StructFielddist,FloatType
]
组合\u udf=udfcombinations,udf\u模式
最后,应用UDF
df=df.带列“邻居”,组合为“邻居”
打印模式
df.show
这就产生了:
root
|-- id: string (nullable = true)
|-- lat: float (nullable = true)
|-- long: float (nullable = true)
|-- geohash_8: string (nullable = true)
|-- neighbors: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- neighbor: string (nullable = true)
| | |-- nlat: float (nullable = true)
| | |-- nlong: float (nullable = true)
+---+----+----+---------+------------------------------------------------------------------------------------+
|id |lat |long|geohash_8|neighbors |
+---+----+----+---------+------------------------------------------------------------------------------------+
|0 |10.0|11.0|A |[[D, C, 10.0], [D, A, 10.0], [D, B, 10.0], [C, A, 10.0], [C, B, 10.0], [A, B, 10.0]]|
|2 |14.0|15.0|C |[] |
|1 |12.0|13.0|B |[[D, B, 10.0]] |
|3 |16.0|17.0|D |[] |
+---+----+----+---------+------------------------------------------------------------------------------------+
将数据帧与其自身交叉连接,然后根据左df的邻居列进行过滤,包含从右df获得的geohash_8,应给出所有邻居组合。那么你在循环中使用的函数就可以在没有循环的情况下应用了。非常感谢你的帮助。交叉连接会起作用,但它会在筛选前在结果中生成大量数据。因为我的源表有超过160M行,所以需要很长时间。我使用了Ryan爆炸和连接的方式,但是我需要距离对的组合。例如,id 0有邻居2,3,4,那么我需要计算[0,2,0,3,0,4,2,3,2,4]的距离。你知道吗?谢谢,不会吧?id=0应包含3个邻居,即2,3,4。分解后,这将转换为3行,id=0,不同行中的邻居为2、3和4。类似地,id=2应有3行,相邻列中有0、3和4。您所需要做的就是通过创建一个排序集,然后执行删除重复项来删除重复的组合。之后你可以计算距离。非常感谢你的帮助。这太棒了,但我需要这对组合,例如id 0有邻居2,3,4,那么需要计算的距离对应该是[0,2,0,3,0,4,2,3,2,4,3,4],你知道吗?我想按源id和lat long分组,然后应用itertools.composition函数和距离计算。更新了一个完整的示例,我认为它符合您的要求。哇,我不知道您可以在spark中返回如此复杂的模式。我还在学习。你是救命的人。我从你的代码中学到了很多。非常感谢。祝您有个美好的一天。