如何使用 laravel/php 根据 longitude/latitude 接近度对对象进行分组

How to group objects based on longitude/latitude proximity using laravel/php

我有一群用户。用户数可以是 50 也可以是 2000。每个人都应该有一个 long/lat 我从 Google Geo api.

中检索到的

我需要全部查询,并按邻近度和一定数量对它们进行分组。假设计数是 12,我在该组中有 120 个用户。我想根据人们与其他人的距离 (long/lat) 对他们进行分组。这样我就得到了 10 组靠近的人。

我目前有 google 地理编码 api 设置并且更愿意使用它。

TIA。

-- 更新 我已经用谷歌搜索了一段时间,看来我正在寻找 returns 按邻近度分组的空间查询。

...看来我正在寻找 returns 按邻近度分组的空间查询。 ...

您可以使用 hdbscan。您的组实际上是 hdbscan 措辞中的集群。您需要与 min_cluster_size 和 min_samples 合作才能使您的组正确。

https://hdbscan.readthedocs.io/en/latest/parameter_selection.html

https://hdbscan.readthedocs.io/en/latest/

hdbscan 似乎在 Python 下运行。

这里有两个关于如何从 PHP 调用 Python 的链接: Calling Python in PHP, Running a Python script from PHP

以下是有关选择哪种聚类算法的更多信息: http://nbviewer.jupyter.org/github/scikit-learn-contrib/hdbscan/blob/master/notebooks/Comparing%20Clustering%20Algorithms.ipynb

http://scikit-learn.org/stable/modules/clustering.html#clustering

请记住,这个问题会随着您添加的每个用户呈指数增长,因为距离计算量与用户数量的平方相关(实际上是 N*(N-1) 距离...所以 2000用户群将意味着每次通过将近 400 万次距离计算。在确定所需资源的大小时请记住这一点

您是希望根据直线(实际上是大圆)距离还是根据 walking/driving 距离对它们进行分组?

如果是前者,如果您能够容忍较小的误差范围并希望假设地球是一个球体,则可以通过简单的数学计算得出大圆距离的近似值。来自 GCMAP.com:

Earth's hypothetical shape is called the geoid and is approximated by an ellipsoid or an oblate sphereoid. A simpler model is to use a sphere, which is pretty close and makes the math MUCH easier. Assuming a sphere of radius 6371.2 km, convert longitude and latitude to radians (multiply by pi/180) and then use the following formula:

theta = lon2 - lon1
dist = acos(sin(lat1) × sin(lat2) + cos(lat1) × cos(lat2) × cos(theta))
if (dist < 0) dist = dist + pi
dist = dist × 6371.2

The resulting distance is in kilometers.

现在,如果您需要精确的计算并且愿意花费 CPU 周期来完成更复杂的数学运算,您可以使用 Vincenty 的公式,它使用 WGS-84 地球参考椭球模型用于导航、制图等。更多信息 HERE

至于算法本身,你需要用每次计算的结果建立一个to-from矩阵。每行和每列代表每个节点。您可以考虑两个简化:

  1. 距离与行进方向无关,所以$dist[n][m] == $dist[m][n](不需要计算整个矩阵,只计算一半)
  2. 从节点到自身的距离始终为 0,因此无需计算它,但由于您打算按邻​​近度分组,为了避免用户与自身分组,您可能希望始终强制 $dist[m][m] 到一个任意定义的异常大的常量(例如 $dist[m][m] = 22000 (miles)。只要你的所有用户都在地球上就可以工作)

所有计算完成后,使用数组排序的方法找到距离每个节点最近的X个节点,就可以了 (您可能想要也可能不想阻止一个用户被分到多个组,但这只是业务逻辑)

在没有先看到您的一些进展的情况下,此时提供的实际代码有点太多,但这基本上是您需要在算法上做的事情。

使用 GeoHash 算法[1]。有一个 PHP 实现 [2]。您可以预先计算不同精度的 geohashes,将它们与经纬度值一起存储在 SQL 数据库中,并使用本机 GROUP BY 进行查询。

  1. https://en.wikipedia.org/wiki/Geohash
  2. https://github.com/lvht/geohash