ES7学习笔记(十三)GEO位置搜索
ES的基本内容介绍的已经差不多了,最后我们再来看看GEO位置搜索,现在大部分APP都有基于位置搜索的功能,比如:我们点外卖,可以按照离我们的距离进行排序,这样可以节省我们的配送费和送餐的时间;还有找工作时,也可以按照离自己家的距离进行排序,谁都想找个离家近的工作,对吧。这些功能都是基于GEO搜索实现的,目前支持GEO搜索功能的中间件有很多,像MySQL、Redis、ES等。我们看看在ES当中怎么实现GEO位置搜索。
GEO字段的创建
GEO类型的字段是不能使用动态映射自动生成的,我们需要在创建索引时指定字段的类型为geo_point
,geo_point
类型的字段存储的经纬度,我们看看经纬度是怎么定义的,
英文 | 简写 | 正数 | 负数 | |
---|---|---|---|---|
维度 | latitude | lat | 北纬 | 南纬 |
经度 | longitude | lon或lng | 东经 | 西经 |
经度的简写有2个,一般常用的是lon,lng则在第三方地图的开放平台中使用比较多。下面我们先创建一个带有geo_point
类型字段的索引,如下:
PUT /my_geo
{
"settings":{
"analysis":{
"analyzer":{
"default":{
"type":"ik_max_word"
}
}
}
},
"mappings":{
"dynamic_date_formats":[
"MM/dd/yyyy",
"yyyy/MM/dd HH:mm:ss",
"yyyy-MM-dd",
"yyyy-MM-dd HH:mm:ss"
],
"properties":{
"location":{
"type":"geo_point"
}
}
}
}
创建了一个my_geo索引,在索引中有一些基础的配置,默认IK分词器,动态映射的时间格式。重点是最后我们添加了一个字段location,它的类型是geo_point
。
索引创建完了,我们添加两条数据吧,假设,路人甲在北京站,路人乙在朝阳公园。那么我们怎么“北京站”和“朝阳公园”的经纬度呢?我们在做项目时,前端都会接地图控件,经纬度的信息可以调用地图控件的API获取。在咱们的示例中,也不接地图控件了,太麻烦了,直接在网上找到“北京站”和“朝阳公园”的坐标吧。
我们查到“北京站”的坐标如下:
然后添加一条数据:
POST /my_geo/_doc
{
"name":"路人甲",
"location":{
"lat": 39.90279998006104,
"lon": 116.42703999493406
}
}
再查“朝阳公园”的坐标
再添加“路人乙”的信息
POST /my_geo/_doc
{
"name":"路人乙",
"location":{
"lat": 39.93367367974064,
"lon": 116.47845257733152
}
}
我们再用elasticsearch-head
插件看一下索引中的数据:
GEO查询
“路人甲”和“路人乙”的信息都有了,但是没有location
字段的信息,因为location
是特性类型的字段,在这里是展示不出来的。我们搜索一下吧,看看怎么用geo搜索,假设“我”的位置在“工体”,我们先要查到“工体”的坐标,
然后再查询5km范围内都有谁,发送请求如下:
POST /my_geo/_search
{
"query":{
"bool":{
"filter":{
"geo_distance":{
"distance":"5km",
"location":{
"lat":39.93031708627304,
"lon":116.4470385453491
}
}
}
}
}
}
在查询的时候用的是filter
查询,再filter查询里再使用geo_distance
查询,我们定义距离distance
为5km,再指定geo类型的字段location
,当前的坐标为:39.93031708627304N,116.4470385453491E。查询一下,看看结果:
{
……
"hits":[
{
"_index":"my_geo",
"_type":"_doc",
"_id":"AtgtXnIBOZNtuLQtIVdD",
"_score":0,
"_source":{
"name":"路人甲",
"location":{
"lat": 39.90279998006104,
"lon": 116.42703999493406
}
}
},
{
"_index":"my_geo",
"_type":"_doc",
"_id":"ZdguXnIBOZNtuLQtMVfA",
"_score":0,
"_source":{
"name":"路人乙",
"location":{
"lat": 39.93367367974064,
"lon": 116.47845257733152
}
}
}
]
}
看来,我们站在“工体”,“北京站”的路人甲和“朝阳公园”的路人乙都在5km的范围内。把范围缩短一点如何,改为3km看看,搜索的请求不变,只是把distance
改为3km,看看结果吧,
{
……
"hits":[
{
"_index":"my_geo",
"_type":"_doc",
"_id":"ZdguXnIBOZNtuLQtMVfA",
"_score":0,
"_source":{
"name":"路人乙",
"location":{
"lat": 39.93367367974064,
"lon": 116.47845257733152
}
}
}
]
}
只有在“朝阳公园”的路人乙被搜索了出来。完全符合预期,我们再看看程序中怎么使用GEO搜索。
JAVA 代码
在定义实体类时,对应的GEO字段要使用特殊的类型,如下:
@Setter@Getter
public class MyGeo {
private String name;
private GeoPoint location;
}
location的类型是GeoPoint
,添加数据的方法没有变化,转化成Json就可以了。再看看查询怎么用,
public void searchGeo() throws IOException {
SearchRequest searchRequest = new SearchRequest("my_geo");
SearchSourceBuilder ssb = new SearchSourceBuilder();
//工体的坐标
GeoPoint geoPoint = new GeoPoint(39.93367367974064d,116.47845257733152d);
//geo距离查询 name=geo字段
QueryBuilder qb = QueryBuilders.geoDistanceQuery("location")
//距离 3KM
.distance(3d, DistanceUnit.KILOMETERS)
//坐标工体
.point(geoPoint);
ssb.query(qb);
searchRequest.source(ssb);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
for (SearchHit hit : response.getHits().getHits()) {
System.out.println(hit.getSourceAsString());
}
}
- SearchRequest指定索引
my_geo
- 创建工体的坐标点
GeoPoint
- 创建geo距离查询,指定geo字段
location
,距离3km,坐标点工体 - 其他的地方没有变化
运行一下,看看结果,
{"name":"路人乙","location":{"lat":39.93360786576342,"lon":116.47853840802}}
只有在“朝阳公园”的路人乙被查询了出来,符合预期。
距离排序
有的小伙伴可能会有这样的疑问,我不想按照距离去查询,只想把查询结果按照离“我”的距离排序,该怎么做呢?再看一下,
public void searchGeoSort() throws IOException {
SearchRequest searchRequest = new SearchRequest("my_geo");
SearchSourceBuilder ssb = new SearchSourceBuilder();
//工体的坐标
GeoPoint geoPoint = new GeoPoint(39.93367367974064d,116.47845257733152d);
GeoDistanceSortBuilder sortBuilder = SortBuilders
.geoDistanceSort("location", geoPoint)
.order(SortOrder.ASC);
ssb.sort(sortBuilder);
searchRequest.source(ssb);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
for (SearchHit hit : response.getHits().getHits()) {
System.out.println(hit.getSourceAsString());
}
}
这次查询并没有设置查询条件,而是创建了一个geo距离排序,同样,先指定geo字段location
,和当前的坐标工体,再设置排序是升序。运行一下,看看结果,
{"name":"路人乙","location":{"lat":39.93360786576342,"lon":116.47853840802}}
{"name":"路人甲","location":{"lat":39.902799980059335,"lon":116.42721165631102}}
离“工体”比较近的“路人乙”排在了第一个,也是符合预期的。有问题大家评论区留言吧~
ES7学习笔记(十三)GEO位置搜索的更多相关文章
- java之jvm学习笔记十三(jvm基本结构)
java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...
- python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容
python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...
- Go语言学习笔记十三: Map集合
Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...
- iView学习笔记(三):表格搜索,过滤及隐藏列操作
iView学习笔记(三):表格搜索,过滤及隐藏某列操作 1.后端准备工作 环境说明 python版本:3.6.6 Django版本:1.11.8 数据库:MariaDB 5.5.60 新建Django ...
- Vue学习笔记十三:Vue+Bootstrap+vue-resource从接口获取数据库数据
目录 前言 SpringBoot提供后端接口 Entity类 JPA操作接口 配置文件 数据库表自动映射,添加数据 写提供数据的接口 跨域问题 前端修改 效果图 待续 前言 Vue学习笔记九的列表案例 ...
- python 学习笔记十三 JQuery(进阶篇)
jQuery 是一个 JavaScript 库. jQuery 极大地简化了 JavaScript 编程. 安装jQuery 有两个版本的 jQuery 可供下载: Production versio ...
- java jvm学习笔记十三(jvm基本结构)
欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完 ...
- PE结构学习笔记--关于AddressOfEntryPoint位置在文件中怎么确定问题
第一次学习PE结构,也不知道有没有更好的办法. 1.AddressOfEntryPoint 这个成员在OptionalHeader里面,OptionalHeader的类型是一个IMAGE_OPTION ...
- ES7学习笔记——Array.prototype.includes和求幂运算符**
一直以来,在前端开发时使用的基本都是ES5,以及少量的ES6.3月份换工作面试时,发现一些比较大的公司,对ES6比较重视,阿里的面试官直接问ES7和ES8,对于从未接触过人来说,完全是灾难.由此也显现 ...
随机推荐
- 2019.06.18训练日记(赞FLS)
之前打了几场比赛,有很多题没做出来,这些题无论是知识点不会,还是说在当时时间和思路的影响下没有做出来,这都应该做出来,至少现在必须做出来,本来打算专心复习,分数高了,好保研,但是想了想如果局限于只把学 ...
- ln命令:软链接与硬链接的区别与应用
ln命令:软链接与硬链接的区别与应用 摘要 Linux系统中,链接是一个十分常见且实用的文件处理命令,它分为软链接和硬链接两种类型.软链接类似于Windows中的快捷方式,硬链接又有着与原文件保持同步 ...
- 前端之HTML1
直接上代码: <!DOCTYPE html> <html> <body bgcolor="green"> <h1 align=" ...
- 无线脉冲水表LoRaWAN方案芯片ASR6500S
无线脉冲水表LoRaWAN方案 物联网是新一代信息技术的重要组成部分,也是"信息化"时代的重要发展阶段,在物联网飞速发展的今天,只有多技术融合的物联网解决方案才能够在不同的应用场景 ...
- 微软原文翻译:适用于.Net Core的WPF数据绑定概述
原文链接,大部分是机器翻译,仅做了小部分修改.英.中文对照,看不懂的看英文. Data binding overview in WPF 2019/09/19 Data binding in Windo ...
- vs每次生成都全部编译的问题
最近vs每次生成都会编译整个工程,经查找为.qrc中的资源路径不存在导致,删除路径后问题解决. 原文来自微信公众号"程序员成长日志",已经工作的程序员朋友可以关注下,分享日常工作中 ...
- 【系列】Python编程思想(1):Python简介与开发环境搭建
李宁老师的 开始学习. 本系列文章深入介绍了Python的各种技术,堪称是目前最全的Python教程.主要目的是让读者可以了解Python的各种核心技术,包括各种Python函数库.本教程使用Py ...
- springBoot第二种配置文件yaml书写方式及读取数据、整合myBatis和整合junit
一.yaml文件格式:key-value形式:可以表示对象 集合 1.语法:key:value 冒号后面必须跟一个空格再写value值 key1: key2: key3:value 2.属性取值:a. ...
- Postman学习宝典(二)
文章来源于:米阳MeYoung Postman 入门2 - Script.Runner 上次Postman 入门1 我们介绍全局变量和环境变量时已经使用过Tests 和 pre-request scr ...
- MySQL++:Liunx - MySQL 主从复制
目标:搭建两台MySQL服务器,一台作为主服务器,一台作为从服务器,实现主从复制 环境:虚拟机 主数据库:192.168.211.101 从数据库:192.168.211.102 MySQL 安装可参 ...