ES的基本内容介绍的已经差不多了,最后我们再来看看GEO位置搜索,现在大部分APP都有基于位置搜索的功能,比如:我们点外卖,可以按照离我们的距离进行排序,这样可以节省我们的配送费和送餐的时间;还有找工作时,也可以按照离自己家的距离进行排序,谁都想找个离家近的工作,对吧。这些功能都是基于GEO搜索实现的,目前支持GEO搜索功能的中间件有很多,像MySQL、Redis、ES等。我们看看在ES当中怎么实现GEO位置搜索。

GEO字段的创建

GEO类型的字段是不能使用动态映射自动生成的,我们需要在创建索引时指定字段的类型为geo_pointgeo_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位置搜索的更多相关文章

  1. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...

  2. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

  3. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  4. iView学习笔记(三):表格搜索,过滤及隐藏列操作

    iView学习笔记(三):表格搜索,过滤及隐藏某列操作 1.后端准备工作 环境说明 python版本:3.6.6 Django版本:1.11.8 数据库:MariaDB 5.5.60 新建Django ...

  5. Vue学习笔记十三:Vue+Bootstrap+vue-resource从接口获取数据库数据

    目录 前言 SpringBoot提供后端接口 Entity类 JPA操作接口 配置文件 数据库表自动映射,添加数据 写提供数据的接口 跨域问题 前端修改 效果图 待续 前言 Vue学习笔记九的列表案例 ...

  6. python 学习笔记十三 JQuery(进阶篇)

    jQuery 是一个 JavaScript 库. jQuery 极大地简化了 JavaScript 编程. 安装jQuery 有两个版本的 jQuery 可供下载: Production versio ...

  7. java jvm学习笔记十三(jvm基本结构)

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完 ...

  8. PE结构学习笔记--关于AddressOfEntryPoint位置在文件中怎么确定问题

    第一次学习PE结构,也不知道有没有更好的办法. 1.AddressOfEntryPoint 这个成员在OptionalHeader里面,OptionalHeader的类型是一个IMAGE_OPTION ...

  9. ES7学习笔记——Array.prototype.includes和求幂运算符**

    一直以来,在前端开发时使用的基本都是ES5,以及少量的ES6.3月份换工作面试时,发现一些比较大的公司,对ES6比较重视,阿里的面试官直接问ES7和ES8,对于从未接触过人来说,完全是灾难.由此也显现 ...

随机推荐

  1. 2019.06.18训练日记(赞FLS)

    之前打了几场比赛,有很多题没做出来,这些题无论是知识点不会,还是说在当时时间和思路的影响下没有做出来,这都应该做出来,至少现在必须做出来,本来打算专心复习,分数高了,好保研,但是想了想如果局限于只把学 ...

  2. ln命令:软链接与硬链接的区别与应用

    ln命令:软链接与硬链接的区别与应用 摘要 Linux系统中,链接是一个十分常见且实用的文件处理命令,它分为软链接和硬链接两种类型.软链接类似于Windows中的快捷方式,硬链接又有着与原文件保持同步 ...

  3. 前端之HTML1

    直接上代码: <!DOCTYPE html> <html> <body bgcolor="green"> <h1 align=" ...

  4. 无线脉冲水表LoRaWAN方案芯片ASR6500S

    无线脉冲水表LoRaWAN方案 物联网是新一代信息技术的重要组成部分,也是"信息化"时代的重要发展阶段,在物联网飞速发展的今天,只有多技术融合的物联网解决方案才能够在不同的应用场景 ...

  5. 微软原文翻译:适用于.Net Core的WPF数据绑定概述

    原文链接,大部分是机器翻译,仅做了小部分修改.英.中文对照,看不懂的看英文. Data binding overview in WPF 2019/09/19 Data binding in Windo ...

  6. vs每次生成都全部编译的问题

    最近vs每次生成都会编译整个工程,经查找为.qrc中的资源路径不存在导致,删除路径后问题解决. 原文来自微信公众号"程序员成长日志",已经工作的程序员朋友可以关注下,分享日常工作中 ...

  7. 【系列】Python编程思想(1):Python简介与开发环境搭建

    李宁老师的 开始学习.   本系列文章深入介绍了Python的各种技术,堪称是目前最全的Python教程.主要目的是让读者可以了解Python的各种核心技术,包括各种Python函数库.本教程使用Py ...

  8. springBoot第二种配置文件yaml书写方式及读取数据、整合myBatis和整合junit

    一.yaml文件格式:key-value形式:可以表示对象 集合 1.语法:key:value 冒号后面必须跟一个空格再写value值 key1: key2: key3:value 2.属性取值:a. ...

  9. Postman学习宝典(二)

    文章来源于:米阳MeYoung Postman 入门2 - Script.Runner 上次Postman 入门1 我们介绍全局变量和环境变量时已经使用过Tests 和 pre-request scr ...

  10. MySQL++:Liunx - MySQL 主从复制

    目标:搭建两台MySQL服务器,一台作为主服务器,一台作为从服务器,实现主从复制 环境:虚拟机 主数据库:192.168.211.101 从数据库:192.168.211.102 MySQL 安装可参 ...