Geo
Tips
Geographical location query, which is exactly the same as the function provided by Es official, supports a total of 4 types of geographic location query:
- GeoBoundingBox
- GeoDistance
- GeoPolygon
- GeoShape
Through these four types of queries, various powerful and practical functions can be realized
application scenarios
- Stores near takeaway apps
- People near social apps
- Drivers near taxi apps
- Crowd feature extraction within the specified range of regional crowd portrait APP
- Health code, etc.
- ...
EE supports 100% of ES geographic location related functions, and it is easier to use.
Notes
- Before using the geolocation query API, you need to create or update the index in advance
- Focus: The first three types of API (GeoBoundingBox, GeoDistance, GeoPolygon) field index type must be geo_point
- The index type of the GeoShape field must be geo_shape, otherwise the function will not work properly. For details, please refer to the following figure
- It is recommended to use String for the field type, because the wkt text format is String, which is very convenient. As for the field name, you can just see the name.
public class Document {
// Omit other fields...
private String location;
private String geoLocation;
}
2
3
4
5
# GeoBoundingBox
GeoBoundingBox: Literally translated as a geographic bounding box, a rectangular range formed by the upper left point and the lower right point, all points within this range can be queried, but not many are actually used, please refer to the following figure:
# API
// inside the rectangle
geoBoundingBox(R column, GeoPoint topLeft, GeoPoint bottomRight);
// not inside the rectangle (supported in 0.9.7+)
notInGeoBoundingBox(R column, GeoPoint topLeft, GeoPoint bottomRight);
2
3
4
5
# Usage example
@Test
public void testGeoBoundingBox() {
// Query all points within the rectangle formed by the coordinates of the upper left and lower right points
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
// Assume the coordinates of the upper left point
GeoPoint leftTop = new GeoPoint(41.187328D, 115.498353D);
// Assume the coordinates of the lower right point
GeoPoint bottomRight = new GeoPoint(39.084509D, 117.610461D);
wrapper.geoBoundingBox(Document::getLocation, leftTop, bottomRight);
// find all points not within this rectangle
// wrapper.notInGeoBoundingBox(Document::getLocation, leftTop, bottomRight);
List<Document> documents = documentMapper.selectList(wrapper);
documents.forEach(System.out::println);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Tips
- The above example only demonstrates one of them. In fact, there are many syntaxes for coordinate points in this framework. Several data formats officially provided by ElasticSearch are supported. Users can choose the corresponding api for query parameters according to their own habits. structure:
- GeoPoint: The latitude and longitude representation used in the demo above
- latitude and longitude array: [116.498353, 40.187328],[116.610461, 40.084509]
- Latitude and longitude strings: "40.187328, 116.498353", "116.610461, 40.084509"
- Latitude and longitude bounding box WKT: "BBOX (116.498353,116.610461,40.187328,40.084509)"
- latitude and longitude GeoHash (hash): "xxx"
Among them, the conversion of latitude and longitude hash can refer to this website: GeoHash Coordinate Online Conversion (opens new window)
# GeoDistance
GeoDistance: Literally translated as geographic distance, in fact, it takes a given point as the center, draws a circle with a given radius, and the points within this circle can be detected and used more frequently, such as the takeaway we use Software, you can use this function to query all the stores within 3 kilometers around, yes, you can also use it to write YP software to query the PLMM within 3 kilometers nearby...
# API
// find all points within the circle
geoDistance(R column, Double distance, DistanceUnit distanceUnit, GeoPoint centralGeoPoint);
// find all points that are not inside the circle (supported in 0.9.7+)
notInGeoDistance(R column, Double distance, DistanceUnit distanceUnit, GeoPoint centralGeoPoint);
2
3
4
5
# Usage example
@Test
public void testGeoDistance() {
// Query all points within a radius of 168.8 kilometers with a longitude of 41.0 and a latitude of 115.0 as the center of the circle
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
// where the unit can be omitted, the default is km
wrapper.geoDistance(Document::getLocation, 168.8, DistanceUnit.KILOMETERS, new GeoPoint(41.0, 116.0));
//Query all points that are not within the circle
// wrapper.notInGeoDistance(Document::getLocation, 168.8, DistanceUnit.KILOMETERS, new GeoPoint(41.0, 116.0));
// The above syntax can also be written in the following forms, the effect is the same, and it is compatible with different user habits:
// wrapper.geoDistance(Document::getLocation,"1.5km",new GeoPoint(41.0,115.0));
// wrapper.geoDistance(Document::getLocation, "1.5km", "41.0,115.0");
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Tips
- The same form of expression for coordinate points is also supported, which is the same as the Tips in GeoBondingBox, and will not be repeated here.
- For EE, which is a favorite of fans, it is a matter of course that it is compatible with the different habits of various users, so you will find a lot of method overloading when you use it. Choose an API that best suits your usage habits or meets the specified usage scenario to call. That's it.
# GeoPolygon
GeoPolygon: Literally translated as geographic polygon, in fact, it takes the polygon formed by all the given points as the range, and queries all the points within this range. This function is often used for electronic fences, and it is used more frequently, such as sharing bicycles. The parking area can be realized by this technology, please refer to the following figure:
# API
geoPolygon(R column, List<GeoPoint> geoPoints)
# Usage example
@Test
public void testGeoPolygon() {
// Query all points in the irregular graph composed of the given point list, the number of points is at least 3
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
List<GeoPoint> geoPoints = new ArrayList<>();
GeoPoint geoPoint = new GeoPoint(40.178012, 116.577188);
GeoPoint geoPoint1 = new GeoPoint(40.169329, 116.586315);
GeoPoint geoPoint2 = new GeoPoint(40.178288, 116.591813);
geoPoints.add(geoPoint);
geoPoints.add(geoPoint1);
geoPoints.add(geoPoint2);
wrapper.geoPolygon(Document::getLocation, geoPoints);
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Tips
- Similarly, regarding the input parameter form of the coordinate point, it also supports a variety of forms. It is consistent with the official. You can refer to the Tips in GeoBoundingBox, which will not be repeated here. It is worth noting that the number of polygon points cannot be less than 3, otherwise Es cannot outline If the polygon is output, this query will report an error.
- The index type and field type are the same as the Tips in GeoBondingBox
# GeoShape
GeoShape: Literally translated as geographic graphics, how do you understand it? At first glance, it seems to be very similar to GeoPolygon, but in fact, the first three types of queries are all coordinate points, and this method queries graphics, such as a park, from the world map. It can be regarded as a point, but if the map is made large enough, for example, if the map is specific to Binjiang District, Hangzhou, the park may become an area composed of several points. In some special scenarios, you need to query this complete Area, and the intersection of two areas, etc., you need to use GeoShape. If you don’t understand it, you might as well read it down first. Take Hangzhou as an example. I will give an example of a health code, assuming the area inside the black circle. For the medium-risk area, I now want to find out all the people in the ES who are in the civic center and in the medium-risk area, and turn all their health codes into orange. In fact, what I am looking for is the orange area in the picture below. At this time, the area formed by the red arrow is the entire civic center.I can use the entire civic center as a geographic graph, and then use the large black circle as the query graph to find their intersection.
The ShapeRelation corresponding to the above figure is INTERSECTS, take a look at the following API.
# API
// Query graphs that match the indexed graph
geoShape(R column, String indexedShapeId);
// Query for graphs that do not conform to indexed graphs (supported in 0.9.7+)
notInGeoShape(R column, String indexedShapeId);
// Query a list of graphs that match the specified graph and graph relationship
geoShape(R column, Geometry geometry, ShapeRelation shapeRelation);
// Query the list of graphs that do not match the specified graph and graph relationship
notInGeoShape(R column, Geometry geometry, ShapeRelation shapeRelation);
2
3
4
5
6
7
8
9
10
11
# Usage example
This API is not commonly used, you can also skip directly to see the query by graph below.
/**
* Known graphics index ID (not commonly used)
* In some high-frequency scenarios, such as an already built park, the graphics coordinates are fixed, so you can store this fixed graphics into es first
* Follow-up can be directly queried based on the id of this graph, which is more convenient, so there is this method, but it is not flexible enough and not commonly used
*/
@Test
public void testGeoShapeWithShapeId() {
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
// The indexedShapeId here is the id of the shape that the user has created in Es in advance
wrapper.geoShape(Document::getGeoLocation, "edu");
// non-compliance
// wrapper.notInGeoShape(Document::getGeoLocation, "edu");
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
This API is more commonly used than the above method, that is, the user can specify whether the graph to be queried is a rectangle, a circle, or a polygon... (see the comments in the code for details):
/**
* Graphics are customized by users (commonly used), this framework supports all supported graphics of Es:
* (Point,MultiPoint,Line,MultiLine,Circle,LineaRing,Polygon,MultiPolygon,Rectangle)
*/
@Test
public void testGeoShape() {
// Note that the graph is queried here, so the field index type of the graph must be geoShape, not geoPoint, so the geoLocation field is used instead of the location field
LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
// Here is a demonstration of a circle, where x, y are the coordinates of the center of the circle, and r is the radius. For other graphics, please demonstrate by yourself, and the reasons for the space are different.
Circle circle = new Circle(13,14,100);
// shapeRelation supports multiple types, if not passed, it defaults to within
wrapper.geoShape(Document::getGeoLocation, circle, ShapeRelation.INTERSECTS);
// non-compliance
// wrapper.notInGeoShape(Document::getGeoLocation, circle, ShapeRelation.INTERSECTS);
List<Document> documents = documentMapper.selectList(wrapper);
System.out.println(documents);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
in the above map WKT (Well-Known Text) coordinates of the civic center (polygon) (simulated data, real data can be obtained from AutoNavi Map/Baidu Map, etc. by calling the open API provided by them):
"POLYGON((108.36549282073975 22.797566864832092,108.35974216461182 22.786093175673713,108.37265968322754 22.775963875498206,108.4035587310791 22.77600344454008,108.41003894805907 22.787557113881462,108.39557647705077 22.805360509802284,108.36549282073975 22.797566864832092))";
It has already been stored in Es. In fact, we will store all the data or business data that may be used in the project in Es in advance, otherwise the query will be meaningless. Check the air? Therefore, when the above API is queried according to GeoShape, The only parameter that needs to be passed in is the graphic of the range you delineate (the parameter above is a circle).
Tips
GeoShape is easy to be confused with GeoPolygon. It needs special attention. They are actually two different things, and their index types also need to be different. The former is geo_point and the latter is geo_shape.