最有效的计算最近城市的方法(来自白名单)

时间:2011-09-19 21:37:05

标签: php javascript iframe geolocation

我有一个城市白名单。比方说,西雅图,波特兰,塞勒姆。使用GeoIP,我会检测用户城市。我们称之为 $ user_city 。根据$ user_city,我想在140英里的白名单(西雅图|| Portland || Salem)中显示距离最近城市的分类列表。如果城市未列入140英里,我只会显示一个下拉菜单,并要求用户手动选择一个城市。

有几种方法可以做到这一点:

  1. 动态计算(我在一个SO答案中找到了算法)
  2. 在DB的帮助下(让我解释一下):
  3.   

    创建一个名为regions

    的表

    地区将有

      

    城市1 |城市2 |距离(最远140英里)
      city 1 =来自白名单的城市   city 2 =距离城市140英里内的任何城市

    这将创建一个合理大小的表。如果我的白名单有200个城市,并且每个城市140英里内有40个城市(或城镇)。这将创建8000行。

    Now, when a user comes to my site:
    1) I check if user is from whitelist city already (city 1 column). If so, display that city
    2). If not, check if $user_city is in "city 2" column
     2a) if it is, get whitelist city with lowest distance
     2b) if it is not, display drop-down for manual input
    

    最终约束:无论我们选择哪种方法,都必须在iFrame中使用。我的意思是,我可以在我的mysite1.com上创建此页面并将此页面嵌入到iframe内的someothersite2.com中吗?它仍然可以获得user_city并找到最近的白名单城市吗?我知道有一些跨域脚本规则,所以我不确定iFrame是否能够获取用户IP地址,将其传递给GeoIP,并将其解析为$ user_city

    所以,我的问题:

    如何做到最好?如果很多人将我的页面嵌入他们的页面(使用iframe),那么我的服务器每秒会被强烈<10000> 次(一厢情愿的想法,但让我们假设是这种情况)。我不知道DB是否能够处理如此多的冲击。我不想为更多的数据库服务器或网络服务器付费。我想尽量减少我的资源需求。所以,我不介意通过JavaScript将一些工作卸载到用户的浏览器。

    编辑:

    1. 有些答案建议存储lat,long然后再进行数学运算。我建议创建“区域”表的原因是这样所有数学都是预计算的。如果我有一个城市的“白名单”,并且如果我为每个列入白名单的城市预先计算所有可能的附近城市。然后我不必每次都计算距离(例如使用Haversine算法)。

    2. 是否可以通过一些狡猾的Java Script使用来将所有这些内容卸载到用户的浏览器中?我不想让我的服务器超载免费服务。它可能会赚钱,但我非常接近破产,我担心在我赚足够的钱来支付升级费用之前我的服务器会崩溃。

    3. 所以,这个问题的三个约束是1)应该从iframe内部工作(我希望这将成为病毒,每个博客都希望将我的网站嵌入到他们的页面的iframe中。)2)应该非常快3)应该最小化我的服务器上的负载

4 个答案:

答案 0 :(得分:1)

  • 使用一个表City并为每个查询执行mysql数学计算,并添加缓存层,例如memcache。公平的表现和非常灵活!
  • 使用两个表City (id,lat,lng,name)Distance (city_id1,city_id2,dist),按传统JOIN获取结果。 (也可以使用缓存层。)不是很灵活。
  • 自定义数据结构:CityObj (id,lat,lng,data[blob])只是序列化并压缩城市的php数组并存储它。这可能会引起你的注意,但正如我们所知,瓶颈永远不是CPU或内存,而是盘IO。这是从INT的索引读取的,与使用tmp表的JOIN相关联。这不是很灵活,但速度快且可扩展。易于分片和集群。

答案 1 :(得分:1)

  

是否可以通过一些狡猾的Java Script使用来将所有这些内容卸载到用户的浏览器中?我不想让我的服务器超载免费服务。它可能会赚钱,但我非常接近破产,我担心在我赚足够的钱来支付升级费用之前我的服务器会崩溃。

是的,有可能......使用Google Maps API和geometry library。您正在寻找的功能是google.maps.geometry.spherical.computeDistanceBetween。我之前做过的Here is an example可能会帮助你开始。我在这里使用jQuery。查看源代码,了解正在发生的事情并根据需要进行修改。简言之:

  1. supplierZips是一个与您的城市白名单相当的邮政编码数组。
  2. 我在页面加载时做的第一件事是对白名单位置进行地理编码。如果您的城市白名单不变,您实际上可以提前执行此操作并缓存结果。这会加快你的应用程序。
  3. 当用户输入邮政编码时,我首先检查它是否是来自美国所有有效邮政编码的json数据集中的有效zip(http://ampersand.no.de/maps/validUSpostalCodes.json,352 kb,根据{{{ 3}})。
  4. 如果该zip有效,我会使用Google Maps API中提到的computeDistanceBetween计算该zip与白名单中每个位置之间的位置。
  5. 希望这有助于您入门。

答案 2 :(得分:0)

您只需获取每个城市的latlong,然后将其添加到数据库中。

所以每个城市只有1条记录。地球上的位置没有存储距离。

完成后,您可以使用半正式公式(http://en.wikipedia.org/wiki/Haversine_formula)轻松进行查询,以获取范围内最近的城市。

  

知道有一些跨域脚本规则,所以我不确定iFrame是否能够获取用户IP地址

如果您只是从嵌入页面获取信息,则可以获取用户ip或其他任何内容。

  

我不知道数据库是否能够处理如此多的重击

如果您有那么多请求,那么您应该找到一种方法来获取它:-)您可以用于升级:D

答案 3 :(得分:0)

您的算法似乎通常是正确的。我要做的是使用PostGIS(一个postgresql插件,比看起来更容易设置:-D)。我相信额外的学习曲线是完全值得的,它是地理数据的标准。

如果您将白名单城市作为POINTs,具有纬度和经度,您实际上可以要求PostGIS按距离到给定的纬度/经度进行排序。它应该比自己做得更有效(PostGIS非常优化)。

您可以使用Yahoo Placefinder或Google Maps等地理编码API来获取您的用户城市(以及白名单城市)。我会做的是拥有一个存储城市名称,lat和lon的表(或者与白名单城市相同),并对其进行查找。如果找不到城市名称,请点击您正在使用的API,并将结果缓存到表格中。通过这种方式,除了模糊的地方之外,您很快就不需要访问API。 API也很快。

如果你真的要看到那种服务器负载,你可能想要考虑使用PHP以外的东西(例如node.js)。顺便说一下,从服务器的角度来看,从iframe进行地理编码不会有任何问题,就像浏览器“正常”访问该页面一样。