Before doing the content retrieval based on Lucene, we know that Lucene can realize the content retrieval of the text information, the numerical information, and the space distance seems to be realized for the source code; In the last six months, I have contacted SOLR, which has a spatial distance retrieval (latitude and longitude), Recently on the implementation of the study, learned that in the implementation of space distance retrieval has a more commonly used technical--geohash, the following is the introduction of the next Geohash.
Geohash Features
- Geohash uses a string to represent longitude and latitude two coordinates, such as my current position of the Geohash value of wx4sv61q;
- Geohash logo is not a point, but a region, such as wx4sv61q corresponds to a rectangular region;
- A coded prefix can identify a larger area, such as a wx4sv61 encoding representing an area larger than the wx4sv61q, but the area represented by the wx4sv61q must be in the area represented by the wx4sv61.
So we go to do distance retrieval, only need to geohash prefix matching can be, specific reasons in the later content to introduce.
Geohash principle
The simplest explanation for Geohash is to convert a position information into a string encoding that can be sorted and comparable. The following implementation procedures are described in detail below:
First we divide latitude (-90, 90) into two intervals (-90, 0), (0, 90), and if the latitude value of the coordinate position is in the first interval, the encoding is 0, otherwise the encoding is 1. We use 40.222012 examples, since 40.222012 belongs to (0, 90), so the code is 1, then we continue to (0, 90), (0, 45) 45, and 90 in (two, 40.222012), so the code is 0, and so on, We do 20 splits, and the last 40.222012 coding is 10111001001101000110.
For longitude, the same method is used to get 116.248283 of the code is 11010010101010100101.
Next we merge the latitude and longitude encoding, the odd number is the longitude, the even number is a longitudinal, the resulting code is 1110011101001001100011011001100000110110 (here need to pay special attention, here said odd, even is the subscript of the value array, starting from 0);
Finally, with BASE32 encoding, binary string corresponding decimal is 28, 29, 4, 24, 27, 6, 1, 22, converted to Base32 is wx4sv61q, so that (40.222012, 116.248283) encoded as wx4sv61q. (The following diagram describes the corresponding relationship between base32)
The encoded wx4sv61q on the map corresponds to the following figure:
Here we geohash the coding length of 8, when the accuracy is 19 meters, the following table lists the different encoding length corresponding to the accuracy:
From the above precision know, if you want to select and I (40.222012, 116.248283) 2km apart from the items, we only need to find the object coordinates corresponding to the Geohash wx4sv as a prefix.
Geohash extension
So far we have a certain understanding of the spatial index, but the content described above is not possible for one of the following situations:
We can see from the diagram, the red point and the green point at the top of the distance, and the green point below the distance, but the red dots and the green dots below the code string, are wx4g0. For geohash such a boundary problem solution is also very simple, we do search or query, the surrounding eight areas to match, so that the boundary problem is well resolved. Here we will implement the Geohash with Java.
Java implementation
Before implementing, we first define a locationbean, which is used to represent latitude and longitude information:
/**
* @Description: The storage of latitude and longitude information * *
package com.lulei.geo.bean;
public class Locationbean {public
static final double Minlat = -90;
public static final Double Maxlat = n;
public static final Double minlng = -180;
public static final Double maxlng = 180;
Private double lat;//latitude [ -90,90]
private double lng;//longitude [ -180,180] public
locationbean (double lat, double LNG ) {
This.lat = lat;
THIS.LNG = LNG;
}
Public double Getlat () {return
lat;
}
public void Setlat (double lat) {
This.lat = lat;
}
Public double getlng () {return
LNG;
}
public void setlng (double LNG) {
this.lng = LNG;
}
}
Then we write a class to implement the Geohash, in the process of implementing Geohash, we need to define some constants and latitude information, as follows:
public class Geohash {
private locationbean location;
/**
* 1 2500km;2 630km;3 78km;4 30km
* 5 2.4km; 6 610m; 7 76m; 8 19m
/
private int hashlength = 8;//latitude/Longitude turn into Geohash length
private int latlength = 20;//latitude converts to binary length
private int lnglength = 20;//longitude to binary length
private double M inlat;//per unit size of latitude
private double minlng;//each longitude fall
private static final char[] CHARS = {' 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 '}
When Geohash is instantiated, we need to assign values to some of the properties:
Public Geohash (double lat, double LNG) {
location = new Locationbean (lat, LNG);
SETMINLATLNG ();
}
public int gethashlength () {return
hashlength;
}
/**
* @Author: Lulei
* @Description: Set latitude and longitude of the smallest unit *
*
private void setminlatlng () {
Minlat = Locationbean.maxlat-locationbean.minlat;
for (int i = 0; i < latlength i++) {
Minlat/= 2.0;
}
MINLNG = LOCATIONBEAN.MAXLNG-LOCATIONBEAN.MINLNG;
for (int i = 0; i < lnglength i++) {
minlng/= 2.0;
}
}
When we use Geohash, we need to set the length of the final encoding, so write a method to implement the Geohash length setting
public boolean sethashlength (int. length) {
if (length < 1) {return
false;
}
hashlength = length;
Latlength = (length * 5)/2;
if (length% 2 = 0) {
lnglength = latlength;
} else {
lnglength = latlength + 1;
}
SETMINLATLNG ();
return true;
}
With these settings, we need to convert the longitude and latitude into the corresponding binary encoding
Private boolean[] Gethasharray (double, double max, int length) {
if (value < min | | | value > MA x) {return
null;
}
if (length < 1) {return
null;
}
Boolean[] result = new Boolean[length];
for (int i = 0; i < length; i++) {
double mid = (min + max)/2.0;
if (Value > mid) {
Result[i] = true;
Min = mid;
} else {
Result[i] = false;
max = mid;
}
}
return result;
}
We need to combine two binary strings into one after we get the binary code of longitude and latitude respectively
Private boolean[] Merge (boolean[] Latarray, boolean[] lngarray) {
if (Latarray = null | | lngarray = NULL) {
Retu RN null;
}
Boolean[] result = new Boolean[lngarray.length + latarray.length];
Arrays.fill (result, false);
for (int i = 0; i < lngarray.length i++) {
result[2 * i] = lngarray[i];
}
for (int i = 0; i < latarray.length i++) {
result[2 * i + 1] = Latarray[i];
}
return result;
}
In the end, we need to transform the obtained binary into base32
/** * @param lat * @param LNG * @return * @Author: Lulei * @Description: Obtain base32 string of longitude and latitude/private string G
ETGEOHASHBASE32 (double lat, double LNG) {boolean[] Bools = getgeobinary (lat, LNG);
if (bools = = null) {return null;
StringBuffer sb = new StringBuffer ();
for (int i = 0; i < bools.length i = i + 5) {boolean[] base32 = new BOOLEAN[5];
for (int j = 0; J < 5; J +) {Base32[j] = bools[i + j];
} Char cha = Getbase32char (base32);
if (' = = Cha ') {return null;
Sb.append (CHA);
return sb.tostring (); /** * @param base32 * @return * @Author: Lulei * @Description: Convert five-bit binary to base32/private char getbase32ch
AR (boolean[] base32) {if (Base32 = null | | | base32.length!= 5) {return ';
int num = 0;
For (Boolean bool:base32) {num <<= 1;
if (bool) {num = 1;
} return chars[num% chars.length];
}
For the question of how to get the Geohash value of the surrounding eight regions we can do the following transformation, we already know the latitude and longitude of the current point, we also know the latitude of each region, and if the longitude plus or minus this width, we can be located in the region to the left and right side of the longitude, If the latitude plus or minus this width, we can get the latitude of the upper and lower parts of the area, so that we can get the coordinates of one point in the eight regions around the region separately, we calculate the coordinates of the eight points, that is, the corresponding Geohash encoding for the eight regions.
Public list<string> Getgeohashbase32for9 () {Double Leftlat = Location.getlat ()-Minlat;
Double Rightlat = Location.getlat () + Minlat;
Double uplng = LOCATION.GETLNG ()-minlng;
Double downlng = location.getlng () + minlng;
list<string> Base32for9 = new arraylist<string> ();
Left from top to bottom 3 String leftup = GetGeoHashBase32 (Leftlat, UPLNG); if (!) ( Leftup = = NULL | |
". Equals (Leftup))) {Base32for9.add (leftup);
String Leftmid = getGeoHashBase32 (Leftlat, LOCATION.GETLNG ()); if (!) ( Leftmid = = NULL | |
". Equals (Leftmid))) {Base32for9.add (leftmid);
String Leftdown = getGeoHashBase32 (Leftlat, DOWNLNG); if (!) ( Leftdown = = NULL | |
". Equals (Leftdown))) {Base32for9.add (Leftdown);
}//middle from top to bottom 3 String midup = GetGeoHashBase32 (Location.getlat (), UPLNG); if (!) ( Midup = = NULL | |
". Equals (Midup))) {Base32for9.add (midup);
String Midmid = getGeoHashBase32 (Location.getlat (), LOCATION.GETLNG ()); if (!) ( MIdmid = = NULL | |
". Equals (Midmid))) {Base32for9.add (midmid);
String Middown = getGeoHashBase32 (Location.getlat (), DOWNLNG); if (!) ( Middown = = NULL | |
". Equals (Middown))) {Base32for9.add (Middown);
///right from top to bottom 3 String rightup = GetGeoHashBase32 (Rightlat, UPLNG); if (!) ( Rightup = = NULL | |
". Equals (Rightup))) {Base32for9.add (rightup);
String Rightmid = getGeoHashBase32 (Rightlat, LOCATION.GETLNG ()); if (!) ( Rightmid = = NULL | |
". Equals (Rightmid))) {Base32for9.add (rightmid);
String Rightdown = getGeoHashBase32 (Rightlat, DOWNLNG); if (!) ( Rightdown = = NULL | |
". Equals (Rightdown))) {Base32for9.add (Rightdown);
return BASE32FOR9;
}
Run results
Complete code
The above blog already has the complete Loacationbean code, here will no longer write.
/** * @Description: Geohash to achieve the transformation of latitude and longitude * * * Package com.lulei.geo;
Import java.util.ArrayList;
Import Java.util.Arrays;
Import java.util.List;
Import Com.lulei.geo.bean.LocationBean;
Import Com.lulei.util.JsonUtil;
public class Geohash {private Locationbean location; /** * 1 2500km;2 630km;3 78km;4 30km * 5 2.4km; 6 610m; 7 76m; 8 19m */private int hashlength = 8; Transformed by latitude into geohash length private int latlength = 20; The latitude is converted into binary length private int lnglength = 20; Convert longitude to binary length private double minlat;//the unit size of each latitude private double minlng;//The fall of each longitude private static final char[] CH
ARS = {' 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 Geohash (double lat, double LNG) {location = new Locationbean (lat, LNG);
SETMINLATLNG ();
public int gethashlength () {return hashlength; }
/* * @Author: Lulei * @Description: The smallest unit of latitude and longitude/private void setminlatlng () {Minlat = Locationbean.
Maxlat-locationbean.minlat;
for (int i = 0; i < latlength i++) {Minlat/= 2.0;
} minlng = LOCATIONBEAN.MAXLNG-LOCATIONBEAN.MINLNG;
for (int i = 0; i < lnglength i++) {minlng/= 2.0; }/** * @return * @Author: Lulei * @Description: Nine/public LIST<STRING&G with coordinates and surrounding points T
Getgeohashbase32for9 () {Double Leftlat = Location.getlat ()-Minlat;
Double Rightlat = Location.getlat () + Minlat;
Double uplng = LOCATION.GETLNG ()-minlng;
Double downlng = location.getlng () + minlng;
list<string> Base32for9 = new arraylist<string> ();
Left from top to bottom 3 String leftup = GetGeoHashBase32 (Leftlat, UPLNG); if (!) ( Leftup = = NULL | |
". Equals (Leftup))) {Base32for9.add (leftup); String Leftmid = getGeoHashBase32 (Leftlat, LOCATION.GETLNG ()); if (!) ( Leftmid = = NULL | |
". Equals (Leftmid))) {Base32for9.add (leftmid);
String Leftdown = getGeoHashBase32 (Leftlat, DOWNLNG); if (!) ( Leftdown = = NULL | |
". Equals (Leftdown))) {Base32for9.add (Leftdown);
}//middle from top to bottom 3 String midup = GetGeoHashBase32 (Location.getlat (), UPLNG); if (!) ( Midup = = NULL | |
". Equals (Midup))) {Base32for9.add (midup);
String Midmid = getGeoHashBase32 (Location.getlat (), LOCATION.GETLNG ()); if (!) ( Midmid = = NULL | |
". Equals (Midmid))) {Base32for9.add (midmid);
String Middown = getGeoHashBase32 (Location.getlat (), DOWNLNG); if (!) ( Middown = = NULL | |
". Equals (Middown))) {Base32for9.add (Middown);
///right from top to bottom 3 String rightup = GetGeoHashBase32 (Rightlat, UPLNG); if (!) ( Rightup = = NULL | |
". Equals (Rightup))) {Base32for9.add (rightup);
String Rightmid = getGeoHashBase32 (Rightlat, LOCATION.GETLNG ()); if (!) ( Rightmid = = null | |
". Equals (Rightmid))) {Base32for9.add (rightmid);
String Rightdown = getGeoHashBase32 (Rightlat, DOWNLNG); if (!) ( Rightdown = = NULL | |
". Equals (Rightdown))) {Base32for9.add (Rightdown);
return BASE32FOR9; /** * @param length * @return * @Author: Lulei * @Description: Set latitude and longitude into geohash length * * Public b
Oolean sethashlength (int length) {if (length < 1) {return false;
} hashlength = length;
Latlength = (length * 5)/2;
if (length% 2 = 0) {lnglength = Latlength;
else {lnglength = latlength + 1;
} setminlatlng ();
return true; /** * @return * @Author: Lulei * @Description: Obtain longitude and latitude Base32 string/public string getgeohashbase
() {return getGeoHashBase32 (Location.getlat (), LOCATION.GETLNG ()); /** * @param lat * @param LNG * @return * @Author: Lulei * @Description: Obtaining latitude and longitude Base32string/private String getGeoHashBase32 (double lat, double LNG) {boolean[] Bools = getgeobinary (lat, LNG);
if (bools = = null) {return null;
StringBuffer sb = new StringBuffer ();
for (int i = 0; i < bools.length i = i + 5) {boolean[] base32 = new BOOLEAN[5];
for (int j = 0; J < 5; J +) {Base32[j] = bools[i + j];
} Char cha = Getbase32char (base32);
if (' = = Cha ') {return null;
Sb.append (CHA);
return sb.tostring (); /** * @param base32 * @return * @Author: Lulei * @Description: Convert five-bit binaries to base32/private
Char Getbase32char (boolean[] base32) {if (Base32 = = NULL | | base32.length!= 5) {return ';
int num = 0;
For (Boolean bool:base32) {num <<= 1;
if (bool) {num = 1;
} return chars[num% chars.length]; /** * @param lat * @pAram LNG * @return * @Author: Lulei * @Description: Get the coordinates of the GEO binary string */private boolean[] Getgeobinary (do
Uble lat, double LNG) {boolean[] Latarray = Gethasharray (lat, Locationbean.minlat, Locationbean.maxlat, latlength);
boolean[] Lngarray = Gethasharray (LNG, LOCATIONBEAN.MINLNG, LOCATIONBEAN.MAXLNG, lnglength);
Return merge (Latarray, Lngarray);
/** * @param latarray * @param lngarray * @return * @Author: Lulei * @Description: Merging of longitude and latitude binary system * * Private boolean[] Merge (boolean[] Latarray, boolean[] lngarray) {if (Latarray = null | | lngarray = NULL)
{return null;
Boolean[] result = new Boolean[lngarray.length + latarray.length];
Arrays.fill (result, false);
for (int i = 0; i < lngarray.length i++) {result[2 * i] = lngarray[i];
for (int i = 0; i < latarray.length i++) {result[2 * i + 1] = Latarray[i];
return result; }/** * @pAram Value * @param min * @param max * @return * @Author: Lulei * @Description: Converts numbers to geohash binary strings * Private boolean[] Gethasharray (double value, double min, double max, int length) {if (Value < min | | valu
E > Max) {return null;
} if (length < 1) {return null;
} boolean[] result = new Boolean[length];
for (int i = 0; i < length; i++) {Double mid = (min + max)/2.0;
if (Value > mid) {result[i] = true;
Min = mid;
else {Result[i] = false;
max = mid;
} return result; The public static void main (string[] args) {//TODO auto-generated method stub Geohash g = New Geohash (
40.222012, 116.248283);
System.out.println (G.getgeohashbase32 ());
System.out.println (Jsonutil.parsejson (G.getgeohashbase32for9 ()));
}
}
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.