前言
附近的人,这四个字的需求就大有文章可做了。很二逼的做法是,存每个人的经度纬度,然后遍历数据库所有数据,foreach循环,两点距离坐标公式。量少的时候,这个没啥问题。量大了,扫描全表 + 经纬度距离运算分分钟拖垮数据库。那么是否有方案可以解决这个痛点呢,今年就来说下Geohash
实现思路
想要不拖垮数据,要做到能走索引。就是跟你无关的点,不要扫描。减少扫描行数来实现减轻数据库的压力。那么减少扫描行数肯定要想到索引。可是经纬度有两个字段,且查询条件无论怎么写都没办法走索引。那么唯一能想到的就是二维变一维。 geohash基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码,这种方式简单粗暴,可以满足对小规模的数据进行经纬度的检索。两个点的距离越近,他们的编码前缀部分就相同,前缀部分相同越多,代表距离越近。然后我们做数据库扫描的时候 可以 WHERE geohash Like 'code%'这样就起到了走索引从而优化了执行效率。
代码思路(PHP)
class Geohash
{
const LATITUDE = 1;
const LONGITUDE = 2;
const BASE32 = array(
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm',
'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z');
public static function encode($latitude = 0, $longitude = 0, $level = 11)
{
$latitude_str = self::separate($latitude, '', 1, self::get_precision_level_num($level, self::LATITUDE), self::get_interval_value(self::LATITUDE));
$longitude_str = self::separate($longitude, '', 1, self::get_precision_level_num($level, self::LONGITUDE), self::get_interval_value(self::LONGITUDE));
return self::geohash_encode(self::combination($latitude_str, $longitude_str));
}
public static