使用mysql在地图上搜索点时处理集群

Posted

技术标签:

【中文标题】使用mysql在地图上搜索点时处理集群【英文标题】:Dealing with clusters when searching for points on map using mysql 【发布时间】:2013-06-10 06:44:23 【问题描述】:

我发现了各种问题的解决方案类似于这个问题,但到目前为止还没有什么钱。非常感谢您的帮助。

我有一个 mysql (v.5.6.10) 数据库,其中包含一个名为 POSTS 的表,该表在地图上存储了数百万行经纬度兴趣点。每个点都被归类为几种不同类型中的一种。每行的结构为id, type, coords

id unsigned bigint + 主键。每次插入的新行都会自动递增。 typeunsigned tinyint 用于编码兴趣点的类型。 coords mysql 地理空间 POINT 数据类型,表示兴趣点的纬度/经度。

“坐标”上有一个空间索引。

我需要找到一种有效的方法来查询表格并返回特定纬度/经度位置(“ 位置”)。数据库非常动态,因此请假设每次查询表时数据都完全不同。

如果 X 是无限的,那么问题是微不足道的。我只需要执行如下查询:

SELECT id, type, AsText(coords) FROM POSTS WHERE MBRContains(GeomFromText(BoundingBox, Position))

其中 'BoundingBox' 是一个 mysql POLYGON 数据类型,它完美地包围了从 Position 开始的半径为 R 的圆。使用边界框当然不是一个完美的解决方案,但这对于我试图解决的特定问题并不重要。我可以使用“ORDER BY ID DESC”对结果进行排序,以首先检索和处理最近插入的点。

如果 X 小于无穷大,那么我只需将上面的内容修改为:

SELECT id, type, AsText(coords) FROM POSTS WHERE MBRContains(GeomFromText(BoundingBox, Position)) ORDER BY id DESC LIMIT X

我要解决的问题是,当该区域中的点高度聚集时(例如,在地图搜索区域上的城市内),我如何从地图上的给定区域获得具有良好代表性的结果集.例如:

在上面的示例中,我站在 X 处,并在黑框边界框中搜索最近插入的 5 个 black 类型的点。如果这些点都插入到右下角的集群中(假设集群是伦敦),那么我的结果集将不包括搜索区域右上角附近的黑点。这对我的应用程序来说是个问题,因为我不希望用户认为在点聚集的任何区域之外没有兴趣点。

我已经考虑了一些潜在的解决方案,但是当行数很大(数百万)时,我找不到一个有效的解决方案。到目前为止我尝试过的方法包括:

    将搜索区域划分为 S 个正方形(即,将其变成一个网格)并在每个正方形内搜索最多 x/S 个点 - 即,对网格中的每个正方形执行单独的 mysql 查询.这适用于少量行,但当行数很大时效率低下,因为您需要将区域划分为大量正方形以使该方法有效工作。只有少数方格,您不能保证每个方格都不会包含人口密集的集群。大量的方块意味着大量的 mysql 搜索导致事情突突。

    向表中的每一行添加一列,用于存储每个点到最近邻居的距离。将点插入表中时,会计算给定点的最近邻距离。使用这种结构,我可以按最近邻距离列对搜索结果进行排序,以便最后返回聚类中的任何点。此解决方案仅在我搜索搜索区域内的所有点时才有效。例如,考虑上图中的情况。如果我想找到最近插入的 5 个 green 类型的点,则为每个点记录的最近邻距离将不正确。为每个查询重新计算这些距离的成本太高了,即使使用 KD 树这样的高效算法也是如此。

事实上,我看不出有任何方法需要对表行中的数据进行预处理(或者,换句话说,“接触”相关搜索区域数据集中的每个点)在行数为变大。我已经考虑过 k-means / DBSCAN 等算法,但鉴于上述用例,我找不到任何能以足够效率工作的方法。

有珍珠吗?我的直觉告诉我这可以解决,但到目前为止我很难过。

【问题讨论】:

如果你应该只显示5个地方,为什么你觉得有必要暗示右上角的存在?如何为前 5 个案例使用更明显的颜色和集群图标并首先对它们进行集群,然后再对其他案例进行集群。我在 Google 地图中采用了这种方法。 【参考方案1】:

这种情况下的后处理似乎更有效。获取给定类型的最后 X 个点。查找是否存在一些聚类,例如:相对于您的视点距离而言,太多点太靠近。删除其中最旧的(或非常接近的 - 可能是您的数据引用了相同的 POI)。多少 - 取决于你。获取下一个 X 点并查看其中是否有一些不在集群中,或者您可以根据距离和最近为每个点计算一个值,并根据该值丢弃点。

【讨论】:

谢谢 - 这给了我一些想法。基本上,我试图阻止簇外的点(所谓的“噪声”点)从搜索结果中消失。我将尝试从搜索区域中获取初始批次的 X 点(如建议的那样),然后在同一区域中执行新的搜索,但划分出由第一批中标识的集群(如果有的话)占据的区域(例如,通过排除每个集群的凸包或类似的东西)。重复直到搜索显示不再有集群。手指交叉。

以上是关于使用mysql在地图上搜索点时处理集群的主要内容,如果未能解决你的问题,请参考以下文章

在地图上显示点时出错

Django - 当用户选择地图上的点时,如何以模式形式包含地图并将坐标保存到数据库?

ArcGIS API for Silverlight地图加载众多点时,使用Clusterer解决重叠问题

移动谷歌地图标记点时用纬度和经度更新数据库

仅在谷歌地图上呈现可见集群项目的最佳方式

用户在地图上标记点时如何获取经纬度值?