基于Spark中的函数加入两个没有公共密钥的RDD

时间:2016-03-27 10:17:34

标签: apache-spark

我试图以有效的方式将用户登录与最近的城市相匹配。

从两个具有以下内容的RDD开始:

  • RDD1:checkin_id,user_id,session_id,utc_time,timezone_offset, 纬度,经度,类别,子类别
  • RDD2:City_name,lat,lon,country_code,country,city_type

我想基于haver-sin函数计算出的最近城市,将这两种格式加入到以下格式中。

  • checkin_id,user_id,session_id,utc_time,timezone_offset, 纬度,经度,类别,子类别,City_name,国家/地区

在Scala中我使用double for循环执行此操作,但Spark中不允许这样做。我试图使用笛卡儿(rdd1.Cartesian(rdd2))然后减少,但这给了我一个巨大的N * M矩阵。

基于最短的haver-sin距离,是否有更快节省空间的方式加入这些RDD?

1 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是完全避免使用join。假设#cities<< #user(换句话说,RDD1.count<< RDD2.count)简化map对用户的最有效方法:

  • RDD2转换为本地数据结构
  • 将其转换为可用于高效地理空间查询的格式(例如K-d tree
  • broadcast它并用于映射

如果RDD2要大到存储在内存中但要小到可以使用单个文件传递,您可以通过用SpatiaLite之类的解决方案替换本地数据结构来轻松调整此方法:

  • 将数据写入数据库
  • 使用标准Spark工具(SparkFiles
  • 将其分发给工作人员
  • 使用本地数据库上的查询映射用户

最后,如果上述方法都不适合您,请明白join的方式:

  • 您可以轻松地使用纬度和经度从用户位置映射到某个本地实体,如大陆,国家/地区,本地管理实体。使用此信息执行初始加入(显然,如果用户在欧洲的某个地方检查墨尔本,澳大利亚是毫无意义的)
  • 使用像GeoHash这样的工具将用户和城市分配到可用于连接的存储桶(在边界情况下需要进行一些调整 - 如果位于赤道附近,则可能需要将单个对象放入多个存储桶中180度子午线)。