參考文章:
Elasticsearch地理形狀
Elasticsearch geo_shape地理形狀
ES地理范圍查詢第二講:地理位置信息之geo_shape
ES GEO地理空間查詢java版
Elasticsearch geo_point/geo_shape
一、概述
通常情況,我們使用一個經(jīng)緯度坐標(biāo)表示一個店鋪的位置、一個用戶的位置,經(jīng)緯度在地圖上僅僅表示一個點,有時候需要表示一個區(qū)域,例如:停車場、商場、學(xué)校等等,這些區(qū)域擁有各種各樣的形狀,包括:圓形、多邊形等等。
ES中存儲地理形狀的數(shù)據(jù)類型為: geo_shape
geo_shape
支持存儲的常用形狀數(shù)據(jù)如下:
- 點(point)
- 圓形(circle)
- 矩形(envelope)
- 多邊形 (polygon)
提示: 在geo_shape中,點作為一種特殊的形狀,geo_shape可以存儲一個點。
二、geo_shape數(shù)據(jù)格式
geo_shape支持GeoJson
和WKT(Well-Known Text)
格式存儲空間形狀數(shù)據(jù)。建議使用wkt。詳細支持的格式描述如下面圖片上描述。
格式說明
-
GeoJson格式數(shù)據(jù)
GeoJson格式參考官方網(wǎng)站:https://geojson.org/
在es中則只需要存儲其geometry的屬性值即為geo_shape的值。
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"name": "Dinagat Islands"
}
}
- wkt Well-Known Text (WKT)
POINT (-77.03653 38.897676)
LINESTRING (-77.03653 38.897676,-77.009051 38.889939)
POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))
MULTIPOINT (102.0 2.0, 103.0 2.0)
MULTILINESTRING ((102.0 2.0, 103.0 2.0, 103.0 3.0, 102.0 3.0),(100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8))
MULTIPOLYGON (((102.0 2.0, 103.0 2.0, 103.0 3.0, 102.0 3.0, 102.0 2.0)), ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))
GEOMETRYCOLLECTION (POINT (100.0 0.0), LINESTRING (101.0 0.0, 102.0 1.0))
BBOX (100.0, 102.0, 2.0, 0.0)
存儲示例
- 定義geo_shape類型映射
PUT /example
{
"mappings": {
"properties": {
"location": {
"type": "geo_shape" // 定義location字段類型為geo_shape
}
}
}
}
- 存儲一個點
POST /example/_doc
{
"location" : {
"type" : "point", // 存儲的圖形類型為:point,表示存儲一個坐標(biāo)點
"coordinates" : [-77.03653, 38.897676] // 坐標(biāo)點格式: [經(jīng)度, 緯度]
}
}
POST /example/_doc
{
"location" : "POINT (-77.03653 38.897676)"
}
- 存儲一個多邊形
POST /example/_doc
{
"location": {
"type": "polygon", // 存儲的圖形類型為: polygon,表示一個多邊形
"coordinates": [ // 支持多個多邊形
[ // 第一個多邊形,多邊形由下面的坐標(biāo)數(shù)組組成。
[100, 0], // 第一個坐標(biāo)點,坐標(biāo)格式: [經(jīng)度, 緯度]
[101, 0],
[101, 1],
[100, 1],
[100, 0] // 最后一個坐標(biāo)點,要跟第一個坐標(biāo)點相同,這樣多邊形才能形成閉合
]
]
}
}
POST /example/_doc
{
"location" : "POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))"
}
三、geo_shape地理形狀搜索
當(dāng)索引的字段類型定義為geo_shape之后,我們就可以通過geo_shape實現(xiàn)圖形搜索。
1. 圖形搜索類型
下面是geo_shape支持的圖形搜索類型:文章來源:http://www.zghlxwxcb.cn/news/detail-405441.html
intersects - 查詢的形狀與索引的形狀有重疊(默認(rèn)), 即圖形有交集則匹配。
disjoint - 查詢的形狀與索引的形狀完全不重疊。
within - 查詢的形狀包含索引的形狀。
2.圖形搜索例子
GET /example/_search
{
"query":{
"bool": { // 布爾組合查詢語句
"must": {
"match_all": {} // 這里設(shè)置其他查詢條件,直接匹配全部文檔
},
"filter": { // 地理信息搜索,通常不參與相關(guān)性計算,所以使用filter包裹起來
"geo_shape": { // geo_shape搜索語句
"location": { // 圖形數(shù)據(jù)存儲在location字段
"relation": "within" // 設(shè)置圖形搜索類型,這里設(shè)置為包含關(guān)系
"shape": { //這個可以理解為其實就是geojson的geometry的值
"type": "polygon", // 設(shè)置圖形類型,各種圖形格式參考geo_shape的數(shù)據(jù)格式支持的圖形類型
"coordinates": [
[
[
104.0396387972344,
30.59613123035072
],
[
104.0393476378968,
30.59549712177650
],
[
104.0396387858758,
30.59638313574942
],
[
104.0396387972344,
30.59613123035072
]
]
]
}
}
}
}
}
}
}
四、Java查詢代碼示例
GeoShape Polygon 查詢
- 依賴jar包
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.8</version>
</dependency>
- 核心代碼示例
MultiPolygonBuilder multiPolygonBuilder = new MultiPolygonBuilder();
String shapeField = "";
for (MultiCondition.GeoPolygon geoPolygon : geoPolygons){
List<Coordinate> coordinateList = geoPolygon.geoPoints.stream().map(point -> new Coordinate(point.getLon(),point.getLat())).collect(Collectors.toList());
CoordinatesBuilder coordinates = new CoordinatesBuilder().coordinates(coordinateList);
PolygonBuilder polygonBuilder = new PolygonBuilder(coordinates);
multiPolygonBuilder.polygon(polygonBuilder);
shapeField = geoPolygon.getShapeField();
}
try {
GeoShapeQueryBuilder geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(shapeField, multiPolygonBuilder.buildGeometry());
queryBuilder.filter(geoShapeQueryBuilder);
} catch (IOException e) {
e.printStackTrace();
}
- 代碼示例
package cn.com.example.cdgisdatahandle.config;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
import org.elasticsearch.common.geo.builders.PolygonBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.WKTReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ElasticsearchDaoImpl {
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private DefConfig defConfig;
public SearchResponse geoShapeQuery(String wkt) {
String indexName = defConfig.getEs_realtimepeople_index_name();
String geoShapeField = defConfig.getEs_realtimepeople_geoshape_field();
String peopleNumField = defConfig.getEs_realtimepeople_peoplenum_field();
SearchResponse response = null;
SearchRequest request = new SearchRequest();
request.indices(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.trackTotalHits(true);
//查詢條件
BoolQueryBuilder boolQueryBuilder = buildWktBoolQueryBuilder(geoShapeField, wkt);
boolQueryBuilder.must(QueryBuilders.matchAllQuery());
boolQueryBuilder.must(QueryBuilders.matchQuery("name", "小明"));
//聚合求和
AggregationBuilder agg = AggregationBuilders.sum("aggSum").field(peopleNumField);
try {
searchSourceBuilder.query(boolQueryBuilder).aggregation(agg);
request.source(searchSourceBuilder);
response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return response;
}
/**
* 構(gòu)建Wkt條件
* 參考文章:https://blog.csdn.net/z69183787/article/details/105563778
*
* @date 2019/9/26
*/
private BoolQueryBuilder buildWktBoolQueryBuilder(String queryField, String wkt) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
WKTReader wktReader = new WKTReader();
try {
Geometry geom = wktReader.read(wkt);
GeoShapeQueryBuilder geoShapeQueryBuilder = null;
if (wkt.startsWith("POLYGON")) {
Polygon polygon = (Polygon) geom;
List<Coordinate> coordinateList = Arrays.stream(polygon.getCoordinates()).collect(Collectors.toList());
CoordinatesBuilder coordinates = new CoordinatesBuilder().coordinates(coordinateList);
PolygonBuilder polygonBuilder = new PolygonBuilder(coordinates);
geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(queryField, polygonBuilder.buildGeometry())
.relation(ShapeRelation.WITHIN);
boolQueryBuilder.filter(geoShapeQueryBuilder);
} else if (wkt.startsWith("MULTIPOLYGON")) {
MultiPolygon multiPolygon = (MultiPolygon) geom;
int num = multiPolygon.getNumGeometries();
MultiPolygonBuilder multiPolygonBuilder = new MultiPolygonBuilder();
for (int i = 0; i < num; i++) {
Polygon polygon = (Polygon) multiPolygon.getGeometryN(i);
List<Coordinate> coordinateList = Arrays.stream(polygon.getCoordinates()).collect(Collectors.toList());
CoordinatesBuilder coordinates = new CoordinatesBuilder().coordinates(coordinateList);
PolygonBuilder polygonBuilder = new PolygonBuilder(coordinates);
multiPolygonBuilder.polygon(polygonBuilder);
}
geoShapeQueryBuilder = QueryBuilders.geoShapeQuery(queryField, multiPolygonBuilder.buildGeometry())
.relation(ShapeRelation.WITHIN);
boolQueryBuilder.filter(geoShapeQueryBuilder);
}
} catch (Exception e) {
System.out.println("構(gòu)建Wkt條件錯誤" + e.getMessage());
}
return boolQueryBuilder;
}
public static void main(String[] args) {
ElasticsearchDaoImpl elasticsearchDao = new ElasticsearchDaoImpl();
String wkt = "POLYGON((110.20111083984375 25.431803168948832,110.05897521972658 25.32075284544021,110.07476806640624 25.187233664941914,110.643310546875 25.1070518051296,110.62477111816405 25.230721136478365,110.55198669433594 25.446064798199416,110.35491943359375 25.353644304321108,110.21072387695312 25.299647958643703,110.17501831054689 25.312683764022793,110.20111083984375 25.431803168948832))";
string wkt2 = "MULTIPOLYGON (((102.0 2.0, 103.0 2.0, 103.0 3.0, 102.0 3.0, 102.0 2.0)), ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0), (100.2 0.2, 100.8 0.2, 100.8 0.8, 100.2 0.8, 100.2 0.2)))";
long startCurrentTimeMillis = System.currentTimeMillis();
elasticsearchDao.geoShapeQuery(wkt);
elasticsearchDao.geoShapeQuery(wkt2);
long endCurrentTimeMillis = System.currentTimeMillis();
System.out.println((endCurrentTimeMillis - startCurrentTimeMillis)/1000 + " s");
}
}
MultiPolygonBuilder 構(gòu)建兩個多邊形,外多邊形,內(nèi)多邊形,求環(huán)形部分相交數(shù)據(jù)文章來源地址http://www.zghlxwxcb.cn/news/detail-405441.html
Coordinate 結(jié)構(gòu)
用一個數(shù)組表示 經(jīng)緯度 坐標(biāo)點:
[lon,lat]
一組坐標(biāo)點放到一個數(shù)組來表示一個多邊形:
[[lon,lat],[lon,lat], ... ]
一個多邊形( polygon )形狀可以包含多個多邊形;第一個表示多邊形的外輪廓,后續(xù)的多邊形表示第一個多邊形內(nèi)部的空洞:
[
[[lon,lat],[lon,lat], ... ], # main polygon
[[lon,lat],[lon,lat], ... ], # hole in main polygon
...
]
到了這里,關(guān)于Elasticsearch地理空間之geo_shape的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!