This is more of a challenge question than something I urgently need, so don't spend all day on it guys.

我早在2000年左右就建立了一个约会网站(早已不复存在),其中一个挑战是计算用户之间的距离,这样我们就可以在X英里的半径内展示你的"匹配".为了说明问题,给出以下数据库模式(大致):

用户表

邮政编码表格 邮政编码 纬度 经度

在USER.ZipCode=ZIPCODE.ZipCode上连接用户和邮政编码.

你会采取什么方法来回答以下问题:哪些用户居住在距离给定用户的邮政编码X英里范围内的邮政编码中.

我们使用了2000 census data,其中有邮政编码表及其大致的纬度和经度.

我们还使用Haversine Formula来计算球体上任意两点之间的距离...非常简单的数学.

问题是,至少对我们来说,作为19岁的大学生,我们真的变成了如何有效地计算和/存储所有成员到所有其他成员的距离.一种方法(我们使用的方法)是导入所有数据并计算从每个邮政编码到每个其他邮政编码的距离.然后,您将存储结果并对其进行索引.类似于:

SELECT  User.UserId
FROM    ZipCode AS MyZipCode
        INNER JOIN ZipDistance ON MyZipCode.ZipCode = ZipDistance.MyZipCode
        INNER JOIN ZipCode AS TheirZipCode ON ZipDistance.OtherZipCode = TheirZipCode.ZipCode
        INNER JOIN User AS User ON TheirZipCode.ZipCode = User.ZipCode
WHERE   ( MyZipCode.ZipCode = 75044 )
        AND ( ZipDistance.Distance < 50 )

当然,问题是ZipDistance表中将有很多行.这并不是完全行不通的,但它真的很大.此外,它还需要对整个数据集进行完整的前期工作,这也不是无法管理的,但不一定是可取的.

不管怎样,我想知道你们中的一些大师会对这样的事情采取什么态度.另外,我认为这是程序员使用撞击时经常遇到的问题,特别是当你考虑算法上相似的问题时.我感兴趣的是一个彻底的解决方案,它至少包括所有部分的提示,以便真正快速、高效地完成这项工作.谢谢!

推荐答案

好的,首先,你不需要在这里使用哈弗正弦公式.对于精度较低的公式产生较大误差的大距离,您的用户不关心匹配是正负几英里,而对于较近的距离,误差非常小.在维基百科的Geographical Distance篇文章中列出了更容易(计算)的公式.

由于邮政编码不同于均匀分布的邮政编码,所以在邮政编码密集分布的地区(华盛顿附近的东海岸就是一个很好的例子),任何均匀划分邮政编码的进程都会受到很大影响.如果您想要直观的比较,请查看http://benfry.com/zipdecode并比较邮政编码前缀89和07.

处理对此空间进行索引的一种更好的方法是使用像QuadtreeR-tree这样的数据 struct .此 struct 允许您对不均匀分布的数据进行空间和距离搜索.

下面是四叉树的外观:

四叉树

要对其进行搜索,请使用其中较小单元格的索引向下钻取每个较大单元格.维基百科更详细地解释了这一点.

当然,由于这是一件相当常见的事情,其他人已经为您完成了困难的部分.由于您尚未指定正在使用的数据库,因此将以PostgreSQL扩展PostGIS为例.PostGIS包括执行R树空间索引的能力,这允许您执行高效的空间查询.

导入数据并构建空间索引后,查询距离的查询如下所示:

SELECT zip
FROM zipcode
WHERE
geom && expand(transform(PointFromText('POINT(-116.768347 33.911404)', 4269),32661), 16093)
AND
distance(
   transform(PointFromText('POINT(-116.768347 33.911404)', 4269),32661),
   geom) < 16093

我会让您自己操作教程的睡觉.

这里有一些其他的参考资料可以帮助您入门.

Database相关问答推荐

在哪里存储 PHP 应用程序的数据库登录凭据

哪个能够存储 1 亿条记录的嵌入式数据库具有高效的 C 或 C++ API

如何以编程方式在 C# 中创建 Microsoft Access 数据库?

MySQL 语法 LIMIT x, y 的 T-SQL 类似的功能是什么?

在表上插入或更新违反外键约束

Uniqueidentifier vs. IDENTITY vs. Material Code - 主键的最佳 Select 是哪个?

是否可以在ORDER BY子句之后放置任何可能造成安全风险的内容?

避免从网站数据库中data scraping数据抓取?

应用程序用户应该是数据库用户吗?

如何产生幻读?

多语言数据库,默认回退

使用 typeORM 搜索早于日期的数据

无法加载时区?

conflict serializable和conflict equivalent有什么区别?

你如何记录你的数据库 struct ?

Django Atomic Transaction 是否锁定数据库?

为什么用 varbinary 而不是 varchar

复制没有 LOCK 权限的 postgres 数据库

SQLite 数据库方案作为实体关系模型

自引用表上的 SQL 递归查询 (Oracle)