确定用户所在的国家/地区

时间:2014-09-16 13:43:04

标签: mysql location

好的,我知道之前已经问过这个问题,但是我的方法是不使用外部API。我想从我的服务器中找到最好的方法。

目前,我只有我的数据库确定英国的用户城市(尚未在全球范围内),这是我使用Haversine等式实现的:

PROCEDURE 'closestCity'(_lat1 decimal(10,7), _lng1 decimal(10,7):

SELECT id,city,6371*(2*ATAN2(SQRT(SIN(RADIANS(lat-_lat1)/2)*SIN(RADIANS(lat-_lat1)/2)+
SIN(RADIANS(lng-_lng1)/2)*SIN(RADIANS(lng-_lng1)/2)
*COS(RADIANS(_lat1))*COS(RADIANS(lat))),
SQRT(1-SIN(RADIANS(lat-_lat1)/2)*SIN(RADIANS(lat-_lat1)/2)+SIN(RADIANS(lng-_lng1)/2)*
SIN(RADIANS(lng-_lng1)/2)*COS(RADIANS(_lat1))*COS(RADIANS(lat))))) as distance 
FROM LOCCITY ORDER BY distance ASC LIMIT 1;

我成功地掌握了全球城市数据库,这个数据库长达143000多个。所以我的想法是首先确定用户所在的国家/地区,并为每个国家/地区设置单独的城市表。我认为可能出现的唯一问题(目前正在寻找用户城市时略有发生)是,当我使用Haversine方程时,它会找到该国中心点最近的长和纬度。

在某些情况下这不是太糟糕,但以俄罗斯为例。如果你在俄罗斯西部,并且我以这种方式使用了Haversine方程式,那很可能会说你在哈萨克斯坦...

所以,我想到的解决方案是创建长边和纬线的'边界点',并使用针对这些的Haversine方程来找到用户所在的国家。

是否有人知道任何具有这些“边界点”的数据库,或者是否需要使用不同的等式来查找它们所在的城市?或者如果我以完全错误的方式解决它......

更新

所以我在我的测试台上更新了我的数据库,以包括所有全球城市......使用上述程序完成一个查询需要1.2秒。它不是最快的测试装备,我必须等到我把它放在我的实际服务器上以获得真实的结果,但它确实表明使用我当前的程序找到一个位置是不可行的...仍然,143000个半人方程式一秒钟也不错Lol ......我印象深刻

另一个更新

所以我想到了一个可以减少计算量的好方法。第一步是通过使用提供的纬度来确定他们可能进入的一组可能的国家,例如,如果经度超过-10但小于0,则包括英国,爱尔兰然后为了找出用户所在的国家/地区,我可以在粗糙的边界点上使用“绕线数算法”(我在http://en.wikipedia.org/wiki/Point_in_polygon找到了这个...)它实际上很漂亮它是如何工作的,基本上,你从用户点到边界点采取角度,如果它们加起来360,那么它们在多边形(国家):D ...然后我可以使用半正方程找到这个城市...我将在我的服务器上测试我以前的方法和新方法(如果我可以找到国家多边形,或者自己做Lol),并发布结果...希望有一个很大的区别运行时间。

最终更新

好的,我的第一个问题是'确定用户所在的国家/地区'......但我之所以这样说是因为我希望减少服务器必须执行的Haversine方程式。但是,我想到了另一种方法:D ......基本上,我把地球分成了5个x5尺寸的“正方形”。然后我为每个sqaure中的城市创建了一个表(总共612个表)。然后,我使用PHP来确定用户所在的方格,并包含公差的周围方格,然后对这些城市进行半正方程。在这里,它使用随机lat和long:

    $foundglng=false;
    $foundglat=false;
    $gridlng=-180;
    $gridlat=-85;
    $grid=1;
    $error=0;
    $lng=rand(-180,179)+(rand(0,9999999)/10000000);
    $lat=rand(-85,85)+(rand(0,9999999)/10000000);
    while($foundglng==false) {
        if($lng>=$gridlng&&$lng<=$gridlng+9.9999999) {
            $foundglng=true;
            while($foundglat==false) {
                if($lat>=$gridlat&&$lat<=$gridlat+9.9999999) {
                    $foundglat=true;
                } else {
                    $grid+=36;
                    $gridlat+=10;
                    if($gridlat>86) {
                        $error=1;
                        $foundglat=true;
                        $foundglng=true;
                    }
                }
            }
        } else {
            $grid+=1;
            $gridlng+=10;
            if($gridlng>181) {
                $error=1;
                $foundglat=true;
                $foundglng=true;
            }
        }
    }
    $sgarray=NULL;
    $sgarray=array();
    $sgarray[]=$grid;
    $sgarray[]=$grid-37;
    $sgarray[]=$grid-36;
    $sgarray[]=$grid-35;
    $sgarray[]=$grid-1;
    $sgarray[]=$grid+1;
    $sgarray[]=$grid+35;
    $sgarray[]=$grid+36;
    $sgarray[]=$grid+37;
    foreach($sgarray as $key=>$sg) {
        if($sg<1||$sg>612) {
            $sgarray[$key]='GRID' . $grid;
        } else {
            $sgarray[$key]='GRID' . $sg;
        }
    }
    mysql_connect("localhost", "user", "password") or die(mysql_error()); 
    mysql_select_db("db_location") or die(mysql_error()); 
    $result=mysql_query("SELECT id,city,6371*
        (2*ATAN2(SQRT(SIN(RADIANS(lat-$lat)/2)
        *SIN(RADIANS(lat-$lat)/2)+SIN(RADIANS(lng-$lng)/2)
        *SIN(RADIANS(lng-$lng)/2)*COS(RADIANS($lat))
        *COS(RADIANS(lat))),SQRT(1-SIN(RADIANS(lat-$lat)/2)
        *SIN(RADIANS(lat-$lat)/2)+SIN(RADIANS(lng-$lng)/2)*
        SIN(RADIANS(lng-$lng)/2)*COS(RADIANS($lat))*COS(RADIANS(lat))))) 
        as distance FROM 
        (SELECT * FROM $sgarray[0]
        UNION SELECT * FROM $sgarray[1] 
        UNION SELECT * FROM $sgarray[2] 
        UNION SELECT * FROM $sgarray[3]
        UNION SELECT * FROM $sgarray[4]
        UNION SELECT * FROM $sgarray[5]
        UNION SELECT * FROM $sgarray[6]
        UNION SELECT * FROM $sgarray[7]
        UNION SELECT * FROM $sgarray[8]) as temp1
        ORDER BY distance ASC LIMIT 1;");
    while($row = mysql_fetch_assoc($result)) {
        echo $row['city'] . '</br>';
    }

这需要0.1到0.2秒才能运行。所以,与我原来的程序(用1.2分钟)相比,我将时间除以10:D ...稍微微调,可能通过减小网格方块的大小,我可以进一步降低这个...... < / p>

0 个答案:

没有答案