按接近度排序结果(带坐标和半径)

Dou*_*oug 5 mysql sql postgresql geolocation neo4j

给定一个包含4个圆圈的数据库,其中每个圆圈都有一个半径和一个地理位置中心:

id | radius | latitude | longitude
---+--------+----------+----------
 1 |      3 |    40.71 |    100.23
 2 |     10 |    50.13 |    100.23
 3 |     12 |    39.92 |    100.23
 4 |      4 |    80.99 |    100.23
Run Code Online (Sandbox Code Playgroud)

注意:每个圆的经度是相同的,以保持简单.

假设我们是在圆2,我想找到附近的每一个圆圈,根据latitude/ longitude坐标和radius每圈.

例如,根据纬度/经度坐标,我们有这样的顺序:

  1. 圈1(因为接近度:9.42 <- 50.13 - 40.71)
  2. 圈3(因为接近度:10.21 <- 50.13 - 39.92)
  3. 圆4(因为接近度:30.86 <- 80.99 - 50.13)

但根据纬度/经度坐标和每个圆的半径,我们应该:

  1. 圈3(因为接近度:1.79 <- 12 - 10.21)
  2. 圈1(因为接近度:6.42 <- 9.42 - 3)
  3. 圆4(因为接近度:26.86 <- 30.86 - 4)

在SQL中有一种简单的方法吗?

ara*_*nid 1

cubeearthdistance可以处理这个问题,至少产生近似的答案。具体来说,他们假设地球是一个简单的球体,这使得数学变得容易得多。

通过这些扩展,您可以生成圆 2 和其他圆之间的距离,如下所示:

select circle.id,
       earth_distance(ll_to_earth(circle.latitude, circle.longitude),
                      ll_to_earth(x.latitude, x.longitude))
 from circle,
      circle x
 where x.id = 2 and circle.id <> x.id
 order by 2;
Run Code Online (Sandbox Code Playgroud)

校正圆半径应该只涉及从上面的距离中减去x.radiuscircle.radius,尽管您需要考虑半径的单位。默认情况下,earth_distance将计算以米为单位的值。

现在,让查询做一些事情,而不是扫描整个圆列表并计算每个圆的距离,然后对它们进行排序和限制,这更具挑战性。有几种方法:

  • 使用多维数据集的要点索引功能,因此您可以创建索引以在任何圆中心周围的某些框中进行搜索,从而减少要考虑的圆列表。
  • 每当编辑圆时,预先计算每个圆与所有其他圆之间的距离,并使用触发器在单独的表中维护此计算。

第二个选项基本上是这样开始的:

create table circle_distance as
select a.id as a_id, b.id as b_id,
 earth_distance(ll_to_earth(a.latitude, a.longitude),
                ll_to_earth(b.latitude, b.longitude))
 from circle a, circle b
 where a.id <> b.id;
alter table circle_distance add unique(a_id, b_id);
create index on circle_distance(a_id, earth_distance);
Run Code Online (Sandbox Code Playgroud)

然后是一些相当繁琐的函数,用于删除/插入相关行circle_distance,由 上的触发器调用circle。这意味着您可以执行以下操作:

select b_id from earth_distance where a_id = $circle_id order by earth_distance limit $n
Run Code Online (Sandbox Code Playgroud)

该查询将能够使用该索引来(a_id,earth_distance)进行快速扫描。