所以,简而言之,
细节:
我有 100k biz 记录,每个记录都带有纬度和经度。我看到 MySQL 实际上支持一种名为 point 的数据类型。我应该使用它吗?
MySQL 是否支持 KDTree 存储系统http://en.wikipedia.org/wiki/File:KDTree-animation.gif
最好使用点数据类型而不是常规的浮点数据类型来存储纬度和经度吗?
最终,我想找到诸如最接近点 105,6 的前 100 家餐厅之类的东西,例如,我的数据库包含很多 biz 和点。显然,为每个记录和每个点一个一个地计算距离将是 O(n),因此很糟糕。
请注意,我知道如何像 Yelp 这样的应用程序有效地从数据库中检索距离信息中描述了一个更简单的解决方案,并且我也将在开始时实施该解决方案。这是一个很好的答案。
但是,我认为有一种最佳答案应该胜过它,对吗?事实上,根据纬度和经度存储位置并找到离它最近的东西是一个非常常见的问题,我希望 mysql 有一个特殊的设计模式。它有吗?
我在哪里可以了解更多信息?谢谢。
我的 mongodb 服务器有一个名为 villageContents 的数据库
它有一个名为 tablebusiness 的集合
如果我运行 mongo 我看到了
MongoDB shell version: 2.0.7
connecting to: test
>
Run Code Online (Sandbox Code Playgroud)
我想知道什么是“测试”。那里没有名为 test 的数据库。
我试图执行
> villageContents.tablebusiness.ensureIndex({"LatitudeLongitude" : "2d"})
Wed Aug 15 09:28:28 ReferenceError:is not defined (shell):1
>
Run Code Online (Sandbox Code Playgroud)
我试图执行
> test.villageContents.tablebusiness.ensureIndex({"LatitudeLongitude" : "2d"})
Wed Aug 15 09:29:13 ReferenceError: test is not defined (shell):1
>
Run Code Online (Sandbox Code Playgroud)
我做错了什么?
然后我做了
db.villageContents.tablebusiness.ensureIndex({"LatitudeLongitude" : "2d"})
Run Code Online (Sandbox Code Playgroud)
什么都不显示。甚至没有添加索引。
那么怎么了?
例如,假设我有一张桌子:
Business(BusinessID, Lattitude, Longitude)
Run Code Online (Sandbox Code Playgroud)
当然,所有的都被索引了。还有100万条记录
例如,假设我想找到最接近 106,5 的商家,我该怎么做?
如果我做
SELECT *
FROM Business
WHERE (Some formula to compute distance here) < 2000
Run Code Online (Sandbox Code Playgroud)
例如,或者如果我这样做
SELECT *
FROM Business
TOP 20
Run Code Online (Sandbox Code Playgroud)
理论上,计算机必须计算所有业务的距离,而实际上只有经度和纬度在一定范围内的业务才需要计算。
那么我怎样才能在 PhP 或 SQL 中做我想做的事呢?
我很感激到目前为止的答案。我正在使用 mysql 并且他们没有比明显的解决方案更有效的方法。MySQL 空间也没有计算距离函数。
这里的手册非常不清楚,甚至没有提供一些示例 SQL 语句:http : //dev.mysql.com/doc/refman/5.6/en/column-indexes.html
改写问题的另一种方法如下:
我们知道我们可以有一个多列的索引。如果这些列的索引是不同类型的呢?说第一列是spatial,另一列是fulltextsearch,等等。我们可以在mysql中这样做吗?(奖励:如果您碰巧知道,我们可以在 mongodb 中这样做吗)
假设你有一个 myisam 表
它有一个包含点的 LATLONG 列
它有一个 FULLTEXT 列,其中包含“业务”中的单词
您想先按 LATLONG 查询,然后在匹配的 LATLONG 中根据 FULLTEXT 列进行过滤。
我想您将需要多列索引。
但是什么是 SQL 命令?
我们知道,如果可能,mysql 将始终首先使用全文搜索索引。
这个查询:
SELECT BusinessID as ID ,
111151.29341326*SQRT(pow(-6.186751-X(LatLong),2)+pow(106.772835-Y(LatLong),2)*0.98838574205337) AS Distance from tableauxiliary
use index (LatLong_2)
WHERE
MBRContains(
GeomFromText (
'MULTIPOINT(-6.1934985598076 106.76604791159,-6.1800034401924 106.77962208841)'
),
Latlong)=1
AND Prominent >15
AND MATCH FullTextSearch AGAINST ('sea*' IN BOOLEAN MODE)
ORDER BY
Distance
LIMIT
0, 45
Run Code Online (Sandbox Code Playgroud)
需要很长时间,而这个查询:
SELECT BusinessID as ID ,
111151.29341326*SQRT(pow(-6.186751-X(LatLong),2)+pow(106.772835-Y(LatLong),2)*0.98838574205337) AS …Run Code Online (Sandbox Code Playgroud) 这与我在 stackoverflow 中的问题有关,其中 vb.net 只是挂在更新 mongodb 查询上。
经过长时间的灵魂搜索,我们检查了日志。日志大小为 3GB。
这么大的原木绝对没用。我无法使用任何文本编辑器打开它。
如何保持 mongodb 的日志很小,比如最大 50 mb。
我们只对最后几个命令感兴趣,而不是整个日志。
MongoDB 中是否有相关设置?如果是这样,什么设置:
注意:问题类似于:https ://stackoverflow.com/questions/8777449/mongodb-log-file-size
然而,这个问题并没有问
我如何通过更改一些文本文件或一些持久的东西来做到这一点,以便每次启动 mongodb 时都保持设置。
与此查询等效的 MongoDB 是什么:
SELECT 111151.29341326 * SQRT( pow(-6.186753-`Latitude`, 2)
+ pow(106.772835-`Longitude`, 2)
* cos(-6.186753*0.017453292519943)
* cos(`Latitude`*0.017453292519943)
)
as distance
from tablename ;
Run Code Online (Sandbox Code Playgroud)
这使用半正弦公式来计算到固定点的大圆距离。我们想从一个位置获得最近的 20 个点,然后显示距离。
看看这个查询
SELECT DISTINCT
TB.ID,
TB.Latitude,
TB.Longitude,
111151.29341326*SQRT(pow(-6.185-TB.Latitude,2)+pow(106.773-TB.Longitude,2)*0.98839228980165) AS Distance
FROM
`tablebusiness` AS TB
join tableauxiliary as TA on TA.BusinessID=TB.ID
WHERE
MBRContains(
GeomFromText ('MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)'),
TA.Latlong
)
AND
MATCH (FullTextSearch) AGAINST ('kucing*' IN BOOLEAN MODE)
ORDER BY
Distance
LIMIT
0, 20
Run Code Online (Sandbox Code Playgroud)
这基本上是搜索 TA.LatLong 在 'MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)' 框中的所有 biz,并且在该框之后必须包含 ku
这将返回 22 行。
现在将其与此查询进行比较
SELECT DISTINCT
TB.ID,
TB.Latitude,
TB.Longitude,
111151.29341326*SQRT(pow(-6.185-TB.Latitude,2)+pow(106.773-TB.Longitude,2)*0.98839228980165) AS Distance
FROM
`tablebusiness` AS TB
join tableauxiliary as TA on TA.BusinessID=TB.ID
WHERE
MBRContains(
GeomFromText ('MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)'),
TA.Latlong
) …Run Code Online (Sandbox Code Playgroud) 这是我当前的查询:
SELECT BusinessID as ID,
111151.29341326*SQRT(pow(-6.186751-X(LatLong),2)+pow(106.772835-Y(LatLong),2)*0.98838574205337) AS Distance from
(
SELECT *
FROM
tableauxiliary
WHERE
MBRContains(
GeomFromText (
'MULTIPOINT(-6.1934985598076 106.76604791159,-6.1800034401924 106.77962208841)'
),
Latlong)=1
AND Prominent >15
) AS TA
Having Distance <= 18238
ORDER BY
Distance
LIMIT
0, 45
Run Code Online (Sandbox Code Playgroud)
请注意,他们我使用了子查询。它使用子查询的原因是因为我想要
MBRContains(
GeomFromText (
'MULTIPOINT(-6.1934985598076 106.76604791159,-6.1800034401924 106.77962208841)'
),
Latlong)=1
Run Code Online (Sandbox Code Playgroud)
首先要完成。这将查询时间从 19 秒减少到 0.9 秒。
有没有办法提示mysql查询优化器,这样我就不需要使用子查询
更新:
我试过:
SELECT BusinessID as ID,
111151.29341326*SQRT(pow(-6.186751-X(LatLong),2)+pow(106.772835-Y(LatLong),2)*0.98838574205337) AS Distance from tableauxiliary
USE Index (LatLong_2,FullTextSearch)
WHERE
MBRContains(
GeomFromText (
'MULTIPOINT(-6.1934985598076 106.76604791159,-6.1800034401924 106.77962208841)'
),
Latlong)
AND Prominent >15 …Run Code Online (Sandbox Code Playgroud) 我已经更改了我要使用的目录的所有者
root@ip-10-138-30-205:/media/newdrive# ls -l
total 20
drwxr-xr-x 3 mongodb root 4096 Aug 30 11:32 data
drwx------ 2 root root 16384 Aug 30 09:56 lost+found
root@ip-10-138-30-205:/media/newdrive#
Run Code Online (Sandbox Code Playgroud)
我已经重启了mongodb
root@ip-10-138-30-205:/media/newdrive# service mongodb restart
mongodb stop/waiting
mongodb start/running, process 17140
root@ip-10-138-30-205:/media/newdrive#
Run Code Online (Sandbox Code Playgroud)
我的 mongodb.conf 已经改变了
# Note: if you run mongodb as a non-root user (recommended) you may
# need to create and set permissions for this directory manually,
# e.g., if the parent directory isn't mutable by the mongodb user.
dbpath=/media/newdrive/data
#where to log …Run Code Online (Sandbox Code Playgroud) 对于查找最近邻居之类的事情,我可以理解 R=Tree 可以胜过 B-Tree。R-Tree 可以踢出更明显的假点。
然而,对于矩形中的一个点的简单检查,它是有效的
分钟
如果 x 和 y 由 b 树索引,它们也可以剔除很多假点。
所以我做了一个空间索引的实验
SELECT DISTINCT
TB.ID,
TB.Latitude,
TB.Longitude,
111151.29341326*SQRT(pow(-6.185-TB.Latitude,2)+pow(106.773-TB.Longitude,2)*0.98839228980165) AS Distance
FROM
`tablebusiness` AS TB
join tableauxiliary as TA on TA.BusinessID=TB.ID
WHERE
MBRContains(
GeomFromText ('MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)'),
TA.Latlong
)
AND
MATCH (FullTextSearch) AGAINST ('kucing*' IN BOOLEAN MODE)
ORDER BY
Distance
LIMIT
0, 20
Run Code Online (Sandbox Code Playgroud)
这是相当快的。.24 秒
然后我做
SELECT DISTINCT
TB.ID,
TB.Latitude,
TB.Longitude,
111151.29341326*SQRT(pow(-6.185-TB.Latitude,2)+pow(106.773-TB.Longitude,2)*0.98839228980165) AS Distance
FROM
`tablebusiness` AS TB
join tableauxiliary as TA
WHERE
-6.2317830813328 < TB.Latitude
AND
TB.Latitude …Run Code Online (Sandbox Code Playgroud)