【问题标题】:Run a geospatial query in memory using Scala使用 Scala 在内存中运行地理空间查询
【发布时间】:2016-05-06 18:07:11
【问题描述】:

有没有办法在 Scala 中运行地理空间查询,给定一组纬度/经度坐标,以找到最近的距离?查询可能需要在内存中运行。

这组值大约是 100 万个经度/纬度坐标。我正在尝试在 Spark 中执行此操作,但我发现的唯一解决方案是 Magellan,但我什至无法使其适用于 Spark 1.6 和 Scala 2.11,因此我正在尝试自定义解决方案。

查询示例:给定 wgs84 坐标中的一个点和 100 万组 wsg84 坐标,我想要一英里半径内最近的 15 个坐标。

【问题讨论】:

  • 您能告诉我们一些细节吗?您使用的是数据库还是任何其他数据存储?坐标是如何存储的?你的数据集有多大?
  • 我已经更新了问题
  • 麦哲伦有什么问题?你是如何尝试使用它的?有任何错误信息吗?
  • 我只是想把它作为正常的依赖项放在我的 sbt 文件中,它在任何存储库中都找不到,它看起来只有 scala 版本 2.10 可用
  • 看看这篇博文对你有没有帮助:hortonworks.com/blog/magellan-geospatial-analytics-in-spark

标签: scala apache-spark geometry geospatial


【解决方案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 索引?
【解决方案2】:

如果你想要任意数据,那么你可能需要一个库,但如果它只是 wgs84 中的距离,那么它是一个直接的公式,例如对 Calculate distance in meters when you know longitude and latitude in java 的响应

【讨论】:

    猜你喜欢
    • 2011-06-01
    • 2019-10-24
    • 2022-08-02
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    相关资源
    最近更新 更多