如何查找附近的药店

查找附近的药店应该是一个最基本的基于地理位置的应用,但要怎么做呢?
1、通过计算药店与我之间的距离,来确定是否它是否在附近。
2、通过对比药店跟我两个位置的GeoHash值来确定我们是否处于同个区域。

本文说明的是第二种方式,因为它更靠谱一点。

GeoHash介绍

这里推一篇维基百科供参考GeoHash
还有知乎的一篇文章GeoHash
GeoHash应该是一种位置压缩算法,用来把二维的位置信息变成一维的信息。我们表达一个位置需要两个值——经度、维度。这两个值可以通过GeoHash算法压缩成一个字符串。大家可以在这个网站体验一下geohash.co

GeoHash的特点

两个GeoHash相同说明他们是同个区域。随着GeoHash变长,它所表示的区域也就越小。
网上可以找到GeoHash长度跟误差(区域大小)的对照表,比如5位的GeoHash大概表达的是5平方公里这样的面积。

geohash length lat bits lng bits lat error lng error km error
1 2 3 ±23 ±23 ±2500
2 5 5 ±2.8 ±5.6 ±630
3 7 8 ±0.70 ±0.70 ±78
4 10 10 ±0.087 ±0.18 ±20
5 12 13 ±0.022 ±0.022 ±2.4
6 15 15 ±0.0027 ±0.0055 ±0.61
7 17 18 ±0.00068 ±0.00068 ±0.076
8 20 20 ±0.000085 ±0.00017 ±0.019

使用GeoHash实现查找附近的药店

计算出所有药店的GeoHash

给所有位置都计算出GeoHash,当然长度尽可能的长,这样后期使用的时候,可以灵活调整精度。示例:

latitude longitude geohash
30.789748 121.339645 wtqr1jhg
30.257383 120.177994 wtmknsny
30.236452 120.044845 wtmk58mu
30.236452 120.044845 wtmk58mu
34.71191 113.65735 ww0v6r4g

Geohash的代码实现可以google到,也可以参考我的另外一篇文章使用kettle生成GeoHash

计算当前位置的以及周边的8个GeoHash

因为GeoHash表达的是一个正方形的区域,你当前位置不一定就是该区域的中心,所以四周的8个区域也是你搜索的目标。
这里推荐一个php的实现https://github.com/chency147/geohash

     
NorthWest North NorthEast
West Me East
SouthWest South SouthEast
     
ws4uztw22x ws4uztw22z ws4uztw23p
ws4uztw22w ws4uztw22y ws4uztw23n
ws4uztw22t ws4uztw22v ws4uztw23j

与数据库中的GeoHash对比

以下代码示例使用thinkphp5.1 mysql写的。通过查找前N位一样的值来实现查找附近的药店。

function filterGeohash($geohash, $geohashNeighbors, $topN)
{
  $list = DrugStoreModel::where(
    'LEFT(geohash, :topN) = LEFT(:geohash, :topN) or
      LEFT(geohash, :topN) = LEFT(:North, :topN) or
      LEFT(geohash, :topN) = LEFT(:NE, :topN) or
      LEFT(geohash, :topN) = LEFT(:East, :topN) or
      LEFT(geohash, :topN) = LEFT(:SE, :topN) or
      LEFT(geohash, :topN) = LEFT(:South, :topN) or
      LEFT(geohash, :topN) = LEFT(:SW, :topN) or
      LEFT(geohash, :topN) = LEFT(:West, :topN) or
      LEFT(geohash, :topN) = LEFT(:NW, :topN)',
    [
      'topN'    => $topN,
      'geohash' => $geohash,
      'North'   => $geohashNeighbors['North'],
      'NE'      => $geohashNeighbors['NorthEast'],
      'East'    => $geohashNeighbors['East'],
      'SE'      => $geohashNeighbors['SouthEast'],
      'South'   => $geohashNeighbors['South'],
      'SW'      => $geohashNeighbors['SouthWest'],
      'West'    => $geohashNeighbors['West'],
      'NW'      => $geohashNeighbors['NorthWest']
    ])
    ->hidden(['id', 'search_content'])->select();

  return $list;
}

版权声明:如无特别声明,本文版权归 一年四季 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 使用GeoHash查找附近的药店 》

本文链接:https://www.yucanlin.cn/develop/%E4%BD%BF%E7%94%A8GeoHash%E6%9F%A5%E6%89%BE%E9%99%84%E8%BF%91%E7%9A%84%E8%8D%AF%E5%BA%97.html