geohash简介:
geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。
geohash有以下几个特点:
首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。
其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。
第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。
这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM
place WHERE geohash LIKE ‘wx4g0e%’),即可查询附近的所有地点。Geohash比直接用经纬度的高效很多。
用途:
移动互联网,lbs可以说是一个基础应用,geohash对于解决附近地点搜索提供了一个有效的解决方案。
扩展:
这个php扩展,提供了三个函数:
/** * $latitude //纬度 * $longitude //经度 * $precision //精密度, 默认是12 * 返回 $precision 长度的 string */ geohash_encode($latitude, $longitude, $precision=12); /** * $hash //geohash_encode后的值 * 返回 array // Array * ( * [latitude] => 39.416916975752 * [longitude] => 100.92223992571 * [north] => 39.416917059571 * [east] => 100.92224009335 * [south] => 100.92223992571 * [west] => 100.92223975807 * ) */ geohash_decode($hash); /** * $hash //geohash_encode后的值 * 返回 在$hash 8个 (东南西北各二个)附近的hash值 */ geohash_neighbors($hash);
github地址:http://github.com/shenzhe/geohash
另外一种算法:
geo
= encode_geohash(30.63578, 104.031601, 12);
//神马时候做成个php扩展把!
echo
$geo
;
print_r(decode_geohash(
$geo
));
function
encode_geohash(
$latitude
,
$longitude
,
$deep
)
{
$BASE32
=
'0123456789bcdefghjkmnpqrstuvwxyz'
;
$bits
=
array
(16,8,4,2,1);
$lat
=
array
(-90.0, 90.0);
$lon
=
array
(-180.0, 180.0);
$bit
=
$ch
=
$i
= 0;
$is_even
= 1;
$i
= 0;
$mid
;
$geohash
=
''
;
while
(
$i
<
$deep
)
{
if
(
$is_even
)
{
$mid
= (
$lon
[0] +
$lon
[1]) / 2;
if
(
$longitude
>
$mid
)
{
$ch
|=
$bits
[
$bit
];
$lon
[0] =
$mid
;
}
else
{
$lon
[1] =
$mid
;
}
}
else
{
$mid
= (
$lat
[0] +
$lat
[1]) / 2;
if
(
$latitude
>
$mid
)
{
$ch
|=
$bits
[
$bit
];
$lat
[0] =
$mid
;
}
else
{
$lat
[1] =
$mid
;
}
}
$is_even
= !
$is_even
;
if
(
$bit
< 4)
$bit
++;
else
{
$i
++;
$geohash
.=
$BASE32
[
$ch
];
$bit
= 0;
$ch
= 0;
}
}
return
$geohash
;
}
function
decode_geohash(
$geohash
)
{
$geohash
=
strtolower
(
$geohash
);
$BASE32
=
'0123456789bcdefghjkmnpqrstuvwxyz'
;
$bits
=
array
(16,8,4,2,1);
$lat
=
array
(-90.0, 90.0);
$lon
=
array
(-180.0, 180.0);
$hashlen
=
strlen
(
$geohash
);
$is_even
= 1;
for
(
$i
= 0;
$i
<
$hashlen
;
$i
++ )
{
$of
=
strpos
(
$BASE32
,
$geohash
[
$i
]);
for
(
$j
=0;
$j
<5;
$j
++) {
$mask
=
$bits
[
$j
];
if
(
$is_even
) {
$lon
[!(
$of
&
$mask
)] = (
$lon
[0] +
$lon
[1])/2;
}
else
{
$lat
[!(
$of
&
$mask
)] = (
$lat
[0] +
$lat
[1])/2;
}
$is_even
= !
$is_even
;
}
}
$point
=
array
( 0 => (
$lat
[0] +
$lat
[1]) / 2, 1 => (
$lon
[0] +
$lon
[1]) / 2);
return
$point
;
}