本文主要是介绍Geohash——地理坐标索引,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
今天看july的博客:第三十六~三十七章、搜索智能提示suggestion,附近地点搜索
(http://blog.csdn.net/v_july_v/article/details/11288807)
里面提到了geohash算法对地理坐标的索引,但是引用的文章和例子让我产生了疑问,对于坐标的经纬度不应该是直接让纬度跟随在经度之后形成一个索引值的,这样只能保证经度相同的且靠近的点排列的比较近,而纬度相同经度只差1的点确不能排列的比较近。
于是查阅了geohash的维基百科说明:http://en.wikipedia.org/wiki/Geohash#Decode_from_base_32
文中举了个例子:
This operation results in the bits 01101 11111 11000 00100 00010. Assuming that counting starts at 0 in the left side, the even bits are taken for the longitude code (0111110000000), while the odd bits are taken for the latitude code (101111001001).
原来是经度和纬度相互交错形成的geohash值。这样就能比较好的让靠近的点按照geohash值也能排列的靠近一些。
写了一段程序来看看经纬度(x坐标和y坐标)互相交错形成的有序值对应的坐标是多少。
//vs2008#include "stdafx.h"
#include <atlstr.h>
#include <conio.h>void GetEvenAndOdd(int nNum, int &nEven, int &nOdd)
{int k = 1;nEven = nOdd = 0;for (int i = 0; i < 8; i++){if (0 != i%2){nEven += k*(nNum & 1);} else{nOdd += k*(nNum & 1);}if (0 != i%2) k *= 2;nNum = nNum >> 1;}
}CString GetBinaryString(int nNum, int nLen)
{CString csRet;for (int i = nLen; i > 0; i--){if ((nNum >> (i-1)) & 1)csRet += "1";elsecsRet += "0";}return csRet;
}int _tmain(int argc, _TCHAR* argv[])
{printf("十进制 geohash值 偶 奇 坐标值\n");for (int i = 0; i < 64; i++){int nEven, nOdd;GetEvenAndOdd(i, nEven, nOdd);CString strGeohash = GetBinaryString(i, 8);CString strEven = GetBinaryString(nEven, 4);CString strOdd = GetBinaryString(nOdd, 4);printf("%02d\t%S\t%S\t%S\t(%d,%d)\n", i, strGeohash.GetBuffer(), strEven.GetBuffer(), strOdd.GetBuffer(), nEven, nOdd);}_getch();return 0;
}
跑出来的坐标值如下:
十进制 | geohash值 | 偶 | 奇 | 坐标值 | 十进制 | geohash 值 | 偶 | 奇 | 坐标值 |
00 | 00000000 | 0000 | 0000 | (0,0) | 32 | 00100000 | 0100 | 0000 | (4,0) |
01 | 00000001 | 0000 | 0001 | (0,1) | 33 | 00100001 | 0100 | 0001 | (4,1) |
02 | 00000010 | 0001 | 0000 | (1,0) | 34 | 00100010 | 0101 | 0000 | (5,0) |
03 | 00000011 | 0001 | 0001 | (1,1) | 35 | 00100011 | 0101 | 0001 | (5,1) |
04 | 00000100 | 0000 | 0010 | (0,2) | 36 | 00100100 | 0100 | 0010 | (4,2) |
05 | 00000101 | 0000 | 0011 | (0,3) | 37 | 00100101 | 0100 | 0011 | (4,3) |
06 | 00000110 | 0001 | 0010 | (1,2) | 38 | 00100110 | 0101 | 0010 | (5,2) |
07 | 00000111 | 0001 | 0011 | (1,3) | 39 | 00100111 | 0101 | 0011 | (5,3) |
08 | 00001000 | 0010 | 0000 | (2,0) | 40 | 00101000 | 0110 | 0000 | (6,0) |
09 | 00001001 | 0010 | 0001 | (2,1) | 41 | 00101001 | 0110 | 0001 | (6,1) |
10 | 00001010 | 0011 | 0000 | (3,0) | 42 | 00101010 | 0111 | 0000 | (7,0) |
11 | 00001011 | 0011 | 0001 | (3,1) | 43 | 00101011 | 0111 | 0001 | (7,1) |
12 | 00001100 | 0010 | 0010 | (2,2) | 44 | 00101100 | 0110 | 0010 | (6,2) |
13 | 00001101 | 0010 | 0011 | (2,3) | 45 | 00101101 | 0110 | 0011 | (6,3) |
14 | 00001110 | 0011 | 0010 | (3,2) | 46 | 00101110 | 0111 | 0010 | (7,2) |
15 | 00001111 | 0011 | 0011 | (3,3) | 47 | 00101111 | 0111 | 0011 | (7,3) |
16 | 00010000 | 0000 | 0100 | (0,4) | 48 | 00110000 | 0100 | 0100 | (4,4) |
17 | 00010001 | 0000 | 0101 | (0,5) | 49 | 00110001 | 0100 | 0101 | (4,5) |
18 | 00010010 | 0001 | 0100 | (1,4) | 50 | 00110010 | 0101 | 0100 | (5,4) |
19 | 00010011 | 0001 | 0101 | (1,5) | 51 | 00110011 | 0101 | 0101 | (5,5) |
20 | 00010100 | 0000 | 0110 | (0,6) | 52 | 00110100 | 0100 | 0110 | (4,6) |
21 | 00010101 | 0000 | 0111 | (0,7) | 53 | 00110101 | 0100 | 0111 | (4,7) |
22 | 00010110 | 0001 | 0110 | (1,6) | 54 | 00110110 | 0101 | 0110 | (5,6) |
23 | 00010111 | 0001 | 0111 | (1,7) | 55 | 00110111 | 0101 | 0111 | (5,7) |
24 | 00011000 | 0010 | 0100 | (2,4) | 56 | 00111000 | 0110 | 0100 | (6,4) |
25 | 00011001 | 0010 | 0101 | (2,5) | 57 | 00111001 | 0110 | 0101 | (6,5) |
26 | 00011010 | 0011 | 0100 | (3,4) | 58 | 00111010 | 0111 | 0100 | (7,4) |
27 | 00011011 | 0011 | 0101 | (3,5) | 59 | 00111011 | 0111 | 0101 | (7,5) |
28 | 00011100 | 0010 | 0110 | (2,6) | 60 | 00111100 | 0110 | 0110 | (6,6) |
29 | 00011101 | 0010 | 0111 | (2,7) | 61 | 00111101 | 0110 | 0111 | (6,7) |
30 | 00011110 | 0011 | 0110 | (3,6) | 62 | 00111110 | 0111 | 0110 | (7,6) |
31 | 00011111 | 0011 | 0111 | (3,7) | 63 | 00111111 | 0111 | 0111 | (7,7) |
将坐标点依次在坐标系上连起来如下图:
可以看出来,geohash和 july文中讲述的R数方法有图形上的分区域相似之处,这种编码方式在区块内尽可能的让邻近点的索引值靠近,但在区块与区块之间还是存在跳跃的地方。所以只简单使用这一种编码技术并不能完全解决邻近点搜索的问题。
要想完美解决问题,还需要考虑的更多一些。
这些问题留待以后继续研究。先写这么多吧。
update:
早上起来搜索了下别人的文章,看到了下面的话:
geohash的最大用途就是附近地址搜索了。不过,从geohash的编码算法中可以看出它的一个缺点:位于格子边界两侧的两点, 虽然十分接近,但编码会完全不同。实际应用中,可以同时搜索当前格子周围的8个格子,即可解决这个问题。
(from: http://tech.idv2.com/2011/07/05/geohash-intro/)
这篇关于Geohash——地理坐标索引的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!