我需要能够从用户选择的特定位置显示到 n 城市/城镇的距离。它就像点击地图并获得100英里范围内的所有目的地一样,只是它不是地图而是网页上的链接。
我需要选择一个可以从州内扩展到全球范围的解决方案 - 这意味着从数千到数十万个位置。
我虽然存储了CITY1_ID,CITY2_ID&关系数据库表中的DISTANCE,但我怀疑它是否可以很好地扩展到Web应用程序(数百万行)。
使用NoSQL数据库或图形数据库可以更有效地完成这项工作吗?或者RDBMS是否足以通过适当的设计解决这个问题?
补充:如果我不存储在数据库中,那么我将如何得到类似的信息: 让我距离圣何塞100英里以内的所有城市?
答案 0 :(得分:4)
你应该为每个城市存储一个city_id, latitude, longitude
- 然后根据运行时输入计算距离。
答案 1 :(得分:2)
不是计算两个城市之间的距离,而是计算一个100英里的边界框,然后你有4个浮点变量插入你的数据库 - 浮点数比数据库中的距离计算快得多。下行是你在角落里得到更多的距离。
用于计算边界框的PHP函数
function getBoundingBox($lat_degrees,$lon_degrees,$distance_in_miles) { $radius = 3963.1; // of earth in miles // bearings $due_north = 0; $due_south = 180; $due_east = 90; $due_west = 270; // convert latitude and longitude into radians $lat_r = deg2rad($lat_degrees); $lon_r = deg2rad($lon_degrees); // find the northmost, southmost, eastmost and westmost corners $distance_in_miles away // original formula from // http://www.movable-type.co.uk/scripts/latlong.html $northmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_north)); $southmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_south)); $eastmost = $lon_r + atan2(sin($due_east)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r)); $westmost = $lon_r + atan2(sin($due_west)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r)); $northmost = rad2deg($northmost); $southmost = rad2deg($southmost); $eastmost = rad2deg($eastmost); $westmost = rad2deg($westmost); //return 2 points NW corner and SE corner return array($northmost,$westmost,$southmost,$eastmost); }
那么你的SQL是
SELECT * FROM table WHERE latitude <= $northmost AND longitude >= $westmost AND latitude >= $southmost AND longitude <= $eastmost
答案 2 :(得分:0)
不要存储它,用经度和纬度计算运行时间。极其可扩展,与保存城市之间的所有距离相反。
你有一个参考点(圣何塞)并循环遍历你所有的城市记录并计算它的运行时间(如果有很多记录,客户可以用javascript或其他东西完成这个计算,因为如果你有服务器这样做,很快就会造成损失)。 JavaScript可能看起来像这样:
var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1).toRad(); // Javascript functions in radians
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
以上代码来自here
注意:因为我是荷兰人,因此使用公制系统
答案 3 :(得分:0)
我使用Neo4J来表示类似的东西,它可以很好地扩展到可以表示为图形的任何类型的数据。
答案 4 :(得分:0)
正如其他人所说,您可以为每个条目存储Lat / Long坐标,并在运行时使用类似于以下内容的距离来计算距离,这提供了km /英里距离输出:
function distance($lat1, $lng1, $lat2, $lng2, $miles = true)
{
$pi80 = M_PI / 180;
$lat1 *= $pi80;
$lng1 *= $pi80;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
编辑:这不适合在半径搜索中的 n 匹配。考虑到给定半径内的城镇密度,最好将距离计算移动到SQL中,因为它的速度要快得多,你可以匹配 x km / miles内的那些。
答案 5 :(得分:0)
我多次使用的简单解决方案(但不是使用mysql)创建了一个用户定义函数some_distance_function
,其中包含四个参数latitude1
,longitude1
,latitude2
,longitude2
返回距离,然后只针对该距离函数测试所有内容,并查看每个项目,无论距离是否小于或等于给定值。如果你只有几千个地点,这是非常好的和有效的。
如果您需要针对数百万条记录运行此查询,您可能希望查看哪些GIS(地理信息系统)扩展可用于您选择的数据库,因为有更好的(至少在搜索能力方面)用于搜索大量位置的持久数据结构。
编辑: 要举例说明Microsoft如何执行此操作,请参阅http://technet.microsoft.com/en-us/library/bb964712(v=sql.105).aspx
看起来MySQL通常支持空间扩展:
http://dev.mysql.com/doc/refman/5.0/en/gis-introduction.html
http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html
编辑II:
看起来这个问题可能也会有所帮助。
Find the distance between two points in MYSQL. (using the Point Datatype)
答案 6 :(得分:0)
这是使用RDBMS的解决方案。保留两张桌子
当您需要从给定的纬度和经度查找特定半径范围内的城市时,您可以对两个表格进行有效范围查询,以获得一定纬度和经度范围内的城市。然后,您可以仅计算检索到的城市的实际距离。