使用Scala在内存中运行地理空间查询

4
有没有一种方法可以在Scala中运行地理空间查询,给定一组纬度/经度坐标,以找到最近的距离?查询可能需要在内存中运行。
该值集大约包含100万个经纬度坐标。我正在尝试在Spark中完成这项工作,但我找到的唯一解决方案是Magellan,但我甚至无法使其适用于Spark 1.6和Scala 2.11,因此我正在尝试自定义解决方案。
查询示例:给定WGS84坐标系中的一个点和100万个WGS84坐标系的点集,我想要在一英里半径内找到最近的15个坐标。

请问您能否提供一些细节信息?您是否使用数据库或其他数据存储方式?坐标是如何存储的?您的数据集有多大? - marcospereira
我已经更新了问题。 - Randomize
你在使用Magellan时遇到了什么问题?你尝试过怎样使用它?有出现错误信息吗? - marcospereira
我只是想将它作为普通依赖项放入我的sbt文件中,但在任何存储库中都找不到它,而且似乎只有Scala版本2.10可用。 - Randomize
看看这篇博客文章是否对你有帮助:http://hortonworks.com/blog/magellan-geospatial-analytics-in-spark/ - marcospereira
Magellan对我也不起作用。 - VB_
2个回答

1
这是一个带有RTree实现的库,可用于Scala中的地理数据索引:https://github.com/davidmoten/rtree 只需选择一个边界框矩形来确定您的点,该点将成为给定半径(在您的情况下为距离)的圆的中心,然后通过距离过滤掉边界框角落的错误结果,再按已经计算出的距离排序以取得最近的15个结果。
您可以使用“haversine”公式来检查点之间的距离条件(请参见此处的说明http://www.movable-type.co.uk/scripts/latlong.html)。
import java.lang.Math._
import com.github.davidmoten.rtree.geometry.{Point, Rectangle}
import com.github.davidmoten.rtree.geometry.Geometries._

def distance(p1: Point, p2: Point): Double = {
  val radLon1 = toRadians(p1.x)
  val radLat1 = toRadians(p1.y)
  val radLon2 = toRadians(p2.x)
  val radLat2 = toRadians(p2.y)
  val x = sin((radLon2 - radLon1) * 0.5)
  val y = sin((radLat2 - radLat1) * 0.5)
  val a = y * y + cos(radLat1) * cos(radLat2) * x * x
  atan2(sqrt(a), sqrt(1 - a)) * 12756274 // The Earth diameter in meters
}

计算边界框,请使用以下函数:

def boundingRectangles(c: Point, r: Double): List[Rectangle] = {
  val radLon = toRadians(c.x)
  val radLat = toRadians(c.y)
  val radDist = r / 6378137 // The Earth radius in meters
  val lat1 = toDegrees(radLat - radDist)
  val lat2 = toDegrees(radLat + radDist)
  if (lat1 > -90 && lat2 < 90) {
    val deltaLon = asin(sin(radDist) / cos(radLat))
    val lon1 = toDegrees(radLon - deltaLon)
    val lon2 = toDegrees(radLon + deltaLon)
    if (lon1 < -180) rectangle(-180, lat1, lon2, lat2) :: rectangle(lon1 + 360, lat1, 180, lat2) :: Nil
    else if (lon2 > 180) rectangle(-180, lat1, lon2 - 360, lat2) :: rectangle(lon1, lat1, 180, lat2) :: Nil
    else rectangle(lon1, lat1, lon2, lat2) :: Nil
  } else rectangle(-180, max(lat1, -90), 180, min(lat2, 90)) :: Nil
}

当圆被日期变更子午线穿过时所需的矩形列表,因为RTree不支持地球上的地理坐标包装,所以我们通过日期变更子午线将这些矩形分成两部分。
公式和描述在此处 http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#Longitude 编辑:最终,我们拥有了自己的不可变RTree版本,采用STR打包,并针对平面和球形几何图形的高效窗口和knn查询进行了调整。

https://github.com/plokhotnyuk/rtree2d


非常感谢您的有趣回答!是否存在一种在内存中构建geohash/2d-sphere索引的方法? - Randomize

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接