ElasticSearch
数据类型
数据类型:geo_point
。
插入数据
插入数据有两种方式:
- 指明经纬度
- 纬度在前,经度在后,逗号分隔
指明经纬度
1 2 3 4 5 6 7 8 9
| POST ent_info/_doc/91320925140612674L/_update { "doc": { "location": { "lat": 39.456789, "lon": 67.456788 } } }
|
lat
:纬度,latitude
,对应X轴。
lon
:经度,longitude
,对应Y轴。
纬度在前,经度在后,逗号分隔
1 2 3 4 5 6
| POST ent_info/_doc/91371102MA3F2BJ40Q/_update { "doc": { "location": "39.456789,67.456788" } }
|
这两种方式,都可以插入数据,需要注意的是,这两种方式插入的数据,查询出来的内容不一样。
查询结果
对于指明经纬度的,查出来的也是指明了经纬度的。
示例代码:
1 2 3 4 5 6 7 8 9 10 11
| GET ent_info/_doc/_search { "query":{ "term": { "id": { "value": "91320925140612674L" } } }, "_source": ["ent_name","location"] }
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| { "took": 2, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 10.778748, "hits": [ { "_index": "ent_info", "_type": "_doc", "_id": "91320925140612674L", "_score": 10.778748, "_source": { "location": { "lon": 67.456788, "lat": 39.456789 }, "ent_name": "建湖县园林建设工程有限公司" } } ] } }
|
没有指明经纬度的,查出来也是没有指明经纬度。
示例代码:
1 2 3 4 5 6 7 8 9 10 11
| GET ent_info/_doc/_search { "query":{ "term": { "id": { "value": "91371102MA3F2BJ40Q" } } }, "_source": ["ent_name","location"] }
|
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| { "took": 1, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 1, "max_score": 10.778748, "hits": [ { "_index": "ent_info", "_type": "_doc", "_id": "91371102MA3F2BJ40Q", "_score": 10.778748, "_source": { "location": "39.456789,67.456788", "ent_name": "山东鼎泰价格评估有限公司" } } ] } }
|
个人更推荐第一种方式,指明经纬度,这种方式更清晰。
范围查询
查询语句
以某点为圆心,周围一米:
1 2 3 4 5 6 7 8 9 10 11 12
| GET ent_info/_doc/_search { "query": { "geo_distance": { "location": { "lon":67.456788, "lat":39.456789 }, "distance": 1 } } }
|
以某点为圆心,周围一公里:
1 2 3 4 5 6 7 8 9 10 11 12
| GET ent_info/_doc/_search { "query": { "geo_distance": { "location": [ 67.456788, 39.456789 ], "distance": 1000 } } }
|
Java实现
以某点为圆心,周围一米:
1 2 3
| QueryBuilders.geoDistanceQuery("location") .distance(geoDistance, DistanceUnit.METERS) .point(geoLat,geoLon)
|
以某点为圆心,周围一公里:
1 2 3
| QueryBuilders.geoDistanceQuery("location") .distance(geoDistance, DistanceUnit.KILOMETERS) .point(geoLat, geoLon)
|
解释说明:
location
:地理坐标字段
geoDistance
:距离
geoLat
:纬度
geoLon
:经度
DistanceUnit.METERS
和DistanceUnit.KILOMETERS
,距离的单位。
在Java实现中,我们可以指定单位。但是在查询语句中,不能指定单位。
排序
一般排序场景只有一种,以与圆心的距离,从近到远,进行排序。
查询语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| GET ent_info/_doc/_search { "query": { "geo_distance": { "location": { "lon":121.63024, "lat":31.25322 }, "distance": 5000 } }, "sort": [ { "_geo_distance": { "location": [ { "lat": 31.25322, "lon": 121.63024 } ] } } ] }
|
Java实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| QueryBuilders.geoDistanceQuery("location") .distance(geoDistance, DistanceUnit.KILOMETERS) .point(geoLat, geoLon);
GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("location", geoLat,geoLon);
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("ent_info") .setTypes("_doc") .setQuery(query) .addSort(sort);
SearchResponse searchResponse = searchRequestBuilder.get();
|
解释说明:
location
:地理坐标字段
geoDistance
:距离
geoLat
:纬度
geoLon
:经度
多边形查询
多边形查询:画一个多边形,查询在多边形范围内的。
查询语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| GET ent_info/_doc/_search { "query": { "geo_polygon": { "location": { "points": [ { "lat": 31.27173508703935, "lon": 121.61240677660302 }, { "lat": 31.24841664295535, "lon": 121.64701484913262 }, { "lat": 31.239087636484996, "lon": 121.63344305598375 }, { "lat": 31.242741775632748, "lon": 121.6387213002787 } ] } } } }
|
Java实现
1 2 3 4 5 6 7
| GeoPoint gp1 = new GeoPoint(gpLat_1, gpLon_1); geoPointList.add(gp1); GeoPoint gp2 = new GeoPoint(gpLat_2, gpLon_2); geoPointList.add(gp2); GeoPoint gp3 = new GeoPoint(gpLat_3, gpLon_3); geoPointList.add(gp3); QueryBuilders.geoPolygonQuery("location", geoPointList)
|
gpLat_1
:多边形的第一个点的纬度
gpLon_1
:多边形的第一个点的经度
gpLat_2
、gpLon_2
:多边形的第二个点的纬度、经度
gpLat_3
、gpLon_3
:多边形的第三个点的纬度、经度
PostgreSQL
数据类型
在PostgreSQL中,没有专门的地理坐标的数据类型,可以考虑采用 point
这个数据类型。
插入数据
1 2
| insert into ent_info (location) values ('(116.309339,40.040582)')
|
范围查询
在PostgreSQL下,没有直接可以用的地理坐标方法。
同时,鉴于,不同经度下,一单位的纬度,对应的长度(米)是不一样的,比如,赤道和南北极,差距会很大。
所以,需要进行额外运算。
示例代码:
1 2 3 4 5 6 7 8 9
| SELECT * FROM ent_info acos( sin(radians(location[1])) * sin(radians(${lat})) + cos(radians(location[1])) * cos(radians(${lat})) * cos(radians(location[0]) - radians(${lon})) ) * 6371 <= ${distance}
|
location[1]
:被查询字段的纬度
location[0]
:被查询字段的经度
${lat}
:入参,纬度
${lon}
:入参,经度
${distance}
:入参,距离
那么,怎么排序呢?
上文的一串三角函数,就是在计算与圆心的距离。
PostgreSQL
和MySQL
,同属于关系型数据库,整体语法差别不大。
关于PostgreSQL
的一些语法,可以参考:
版权声明: 本博客所有文章版权为文章作者所有,未经书面许可,任何机构和个人不得以任何形式转载、摘编或复制。