Elasticsearch ES实现GEO位置搜索

这篇具有很好参考价值的文章主要介绍了Elasticsearch ES实现GEO位置搜索。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

ES实现GEO位置搜索

Elasticsearch-7.15.2
附近查询,也叫做距离查询(geo_distance):查询到指定中心点小于某个距离值的所有文档。

创建索引 (my_geo),直接设置mapping

GEO字段的创建:添加一个字段location,类型为 geo_point。

GEO类型的字段是不能使用动态映射自动生成的,我们需要在创建索引时指定字段的类型为geo_point,geo_point 类型的字段存储的经纬度。

curl -X PUT http://192.168.11.21:9200/my_geo -H 'Content-Type:application/json' -d'
{
  "mappings": {
    "properties": {
      "name": {"type": "text"},
      "location": {"type":"geo_point"}
    }
  }
}'

插入2条数据

curl -X POST 192.168.11.21:9200/my_geo/_doc/1 -H 'Content-Type: application/json' -d '{
  "name": "路人甲北京站",
  "location": {
    "lat": 39.90279998006104,
    "lon": 116.42703999493406
  }
}'

curl -X POST 192.168.11.21:9200/my_geo/_doc/2 -H 'Content-Type: application/json' -d '{
  "name": "路人乙朝阳公园",
  "location": {
    "lat": 39.93367367974064,
    "lon": 116.47845257733152
  }
}'
查询语句 curl

我的位置在“工体”,“北京站”的路人甲和“朝阳公园”的路人乙都在5km的范围内,查询5km和3km范围内都有谁。

把范围缩短distance改为3km,请求如下:

curl -XGET '192.168.11.21:9200/my_geo/_search?pretty=true' -H 'Content-Type:application/json' -d '
{
  "query":{
      "bool":{
          "must":{"match_all":{ }},
          "filter":{
              "geo_distance":{
                  "distance":"3km",
                  "location":{"lat": 39.93031708627304,"lon": 116.4470385453491}
              }
          }
      }
  }}'

结果:在“朝阳公园”的路人乙被搜索了出来。

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {"total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0},
  "hits" : {"total" : { "value": 1, "relation" : "eq"},
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_geo",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "路人乙朝阳公园",
          "location" : {"lat" : 39.93367367974064,"lon": 116.47845257733152}
        }
      }
    ]
  }}

距离排序

5公里范围内排序查询。

curl -XGET  'http://192.168.11.21:9200/my_geo/_search?pretty=true' -H 'Content-Type:application/json' -d '
{
  "query":{
      "bool":{
          "must":{
              "match_all":{ }
          },
          "filter":{
              "geo_distance":{ // 按距离搜索
                  "distance":"5km", // 搜索范围
                  "location":{"lat": 39.93031708627304,"lon": 116.4470385453491} // 当前纬度 经度
              }
          }
      }
  },
    "sort": [
    {
      "_geo_distance": { // _geo_distance代表根据距离排序
        "location": { // 根据location存储的经纬度计算距离
            "lat": 39.93031708627304, // 当前纬度 经度
            "lon": 116.4470385453491
        },
        "order": "asc"
      }
    }
  ]
}' 

curl查询结果:离我“工体”比较近的“路人乙”排在了第一个,也是符合预期的。

{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "my_geo",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "name" : "路人乙",
          "location" : {
            "lat" : 39.93367367974064,
            "lon" : 116.47845257733152
          }
        },
        "sort" : [
          2704.400492813901
        ]
      },
      {
        "_index" : "my_geo",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "name" : "路人甲",
          "location" : {
            "lat" : 39.90279998006104,
            "lon" : 116.42703999493406
          }
        },
        "sort" : [
          3503.0165324004943
        ]
      }
    ]
  }}

JAVA程序中使用GEO搜索

在定义实体类时,对应的GEO字段要使用特殊的类型。location的类型是GeoPoint,添加数据时转成Json存储。

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;

@Data
@Document(indexName = "my_geo")
public class MyGeo {

    @Field(type = FieldType.Keyword)
    private String goodsName;

    @Field(store = true)
    @GeoPointField
    private GeoPoint location;
}

geo距离查询

    public void geoDistanceQuery(){
        //创建查询请求对象
        SearchRequest request = new SearchRequest("my_geo");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        GeoPoint geoPoint = new GeoPoint(39.93031708627304, 116.4470385453491);//工体的坐标
        //geo距离查询
        QueryBuilder queryBuilder = QueryBuilders.geoDistanceQuery("location")
                .distance(5, DistanceUnit.KILOMETERS)
                .point(geoPoint);

        sourceBuilder.query(queryBuilder);
        request.source(sourceBuilder);
        try {
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            for(SearchHit hit : response.getHits().getHits()){
                
                System.out.println(hit.getSourceAsString());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
结果:
{"name":"路人甲","location":{"lat":39.90279998006104,"lon":116.42703999493406}}
{"name":"路人乙","location":{"lat":39.93367367974064,"lon":116.47845257733152}}

距离排序

    public void geoDistanceSortQuery(){
        SearchRequest request = new SearchRequest("my_geo"); //创建查询请求对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        GeoPoint geoPoint = new GeoPoint(39.93031708627304, 116.4470385453491);//工体的坐标
        
        GeoDistanceSortBuilder sortBuilder = SortBuilders.geoDistanceSort("location", geoPoint).order(SortOrder.ASC);
        sourceBuilder.sort(sortBuilder);
        request.source(sourceBuilder);
        
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            for(SearchHit hit : response.getHits().getHits()){
                System.out.println(hit.getSourceAsString());
    }
结果:
{"name":"路人乙","location":{"lat":39.93367367974064,"lon":116.47845257733152}}
{"name":"路人甲","location":{"lat":39.90279998006104,"lon":116.42703999493406}}

其他

距离排序(带分页)
GeoDistanceQueryBuilder

    /**
     *  ElasticSearchRepository和 RestHighLevelClient ElasticsearchRestTemplate的区别
     *  https://blog.csdn.net/zhiyikeji/article/details/128908596
     *
     *  从名字就能看出来,QueryBuilder主要用来构建查询条件、过滤条件,SortBuilder主要是构建排序。
     *  譬如,我们要查询距离某个位置100米范围内的所有人、并且按照距离远近进行排序:
     */
    public void findGeoDistanceSort(){
        double lat = 39.93031708627304, lng = 116.4470385453491; //工体

        //设定搜索半径
        GeoDistanceQueryBuilder queryBuilder = QueryBuilders.geoDistanceQuery("location")
                //.geoDistance(GeoDistance.PLANE)
                .point(lat, lng).distance(300, DistanceUnit.KILOMETERS);

        //计算距离多少公里 获取点与点之间的距离
        GeoDistanceSortBuilder sortBuilder = SortBuilders.geoDistanceSort("location", lat, lng)
                .point(lat, lng).unit(DistanceUnit.METERS).order(SortOrder.ASC);

        Pageable pageable = PageRequest.of(0, 10);

        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder().withPageable(pageable)
                .withFilter(queryBuilder).withSort(sortBuilder);

        NativeSearchQuery nativeSearchQuery = builder.build();

        org.springframework.data.elasticsearch.core.SearchHits<MyGeo> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, MyGeo.class);
        List<org.springframework.data.elasticsearch.core.SearchHit<MyGeo>> searchHitList = searchHits.getSearchHits();
        if(searchHitList.isEmpty()){
            System.out.println("没有查询到数据!");
            return;
        }

        searchHitList.forEach(hit ->{
            // 此处的索引和查询返回结果中sort集合的索引一致,目的在于取返回结果中的距离计算结果,以免二次计算,造成资源浪费
            //Object geoDistance = hit.getSortValues().get(2);
            System.out.println("hit -- " + JSONObject.toJSONString(hit));
        });
    }

结果:
{"name":"路人乙","location":{"lat":39.93367367974064,"lon":116.47845257733152}}
{"name":"路人甲","location":{"lat":39.90279998006104,"lon":116.42703999493406}}

参考资料

ES7学习笔记(十三)GEO位置搜索
https://www.modb.pro/db/73991

ES GEO地理空间查询 基于geo-point的多边形查询
https://huaweicloud.csdn.net/637eedd2df016f70ae4c9b19.html

通过ElasticsearchRestTemplate 完成地理搜索 矩形搜索,附近人搜索, 距离搜索
https://blog.csdn.net/qq_41712271/article/details/134881584

###复杂查询包含ES按距离排序
https://blog.csdn.net/m0_56726104/article/details/120785048


geo 距离排序检索
https://blog.csdn.net/wenxingchen/article/details/95448215/

GEO位置搜索 https://www.modb.pro/db/73991
ElasticsearchTemplate 经纬度按距离排序 http://www.javashuo.com/article/p-uqiafsey-hx.html

ES 位置查询之geo_point
https://blog.csdn.net/weixin_43918355/article/details/118366065文章来源地址https://www.toymoban.com/news/detail-793945.html

到了这里,关于Elasticsearch ES实现GEO位置搜索的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ElasticSearch系列 - SpringBoot整合ES:实现搜索结果排序 sort

    00. 数据准备 01. Elasticsearch 默认的排序方式是什么? ElasticSearch 默认的排序方式是相关性排序。相关性排序是根据查询条件与文档的匹配程度来计算每个文档的相关性得分,然后按照得分从高到低进行排序。相关性排序是 ElasticSearch 中最常用的排序方式,因为它可以根据查询

    2024年02月02日
    浏览(51)
  • Es elasticsearch 二十 站内搜索示例 高亮内容 java springboot 实现

    目录 实现思路 代码 全依赖 参数对象 搜索实现代码全代码 日志 重点 权重 分页 入参高亮数据处理 返回出参数据处理 构建请求 请求体设置搜索字段 返回数据解析获取高亮 高亮通过设置标签和class  前端设置class字体颜色 也可直接写在后端   全依赖 参数对象 搜索实现代码

    2024年02月02日
    浏览(44)
  • ES es Elasticsearch 十三 Java api 实现搜索 分页查询 复杂查询 过滤查询 ids查询 等

    目录 Java api 实现搜索 Pom.xml 建立链接 搜索全部记录 增加规则值查某些字段 搜索分页 全代码 Ids 搜索 搜索Match搜索 multi_match 搜索 多字段搜索 复杂查询 bool查询 filter  bool 复杂查询增加过滤器查询 复杂擦好像加排序 日志 思路 参考 api 写法 写Java代码 请求条件构建层次

    2024年02月04日
    浏览(58)
  • elasticsearch[五]:深入探索ES搜索引擎的自动补全与拼写纠错:如何实现高效智能的搜索体验

    前一章讲了搜索中的拼写纠错功能,里面一个很重要的概念就是莱文斯坦距离。这章会讲解搜索中提升用户体验的另一项功能 - [自动补全]。本章直接介绍 ES 中的实现方式以及真正的搜索引擎对自动补全功能的优化。 大家对上面的这个应该都不陌生,搜索引擎会根据你输入的

    2024年01月24日
    浏览(59)
  • Elasticsearch的地理位置搜索与功能

    地理位置搜索是一种非常重要的搜索功能,它可以根据用户的位置信息来提供相关的搜索结果。在现代的互联网和移动应用中,地理位置搜索已经成为一种基本的功能需求。Elasticsearch是一个强大的搜索引擎,它提供了一套完善的地理位置搜索功能。在本文中,我们将深入探讨

    2024年02月21日
    浏览(39)
  • Elasticsearch 基于地理位置的搜索查询

             ES为用户提供了基于地理位置的搜索功能。它主要支持两种类型的地理查询:一种是地理点(geo_point),即经纬度查询,另一种是地理形状查询(geo_shape),即支持点,线,圆形和多边形等查询。         从实用性来说,地理点(即geo_point)数据类型的使用更多一些,

    2024年02月12日
    浏览(39)
  • ElasticSearch系列 - SpringBoot整合ES:实现分页搜索 from+size、search after、scroll

    01. 数据准备 ElasticSearch 向 my_index 索引中索引了 12 条文档: 02. ElasticSearch 如何查询所有文档? ElasticSearch 查询所有文档 根据查询结果可以看出,集群中总共有12个文档,hits.total.value=12, 但是在 hits 数组中只有 10 个文档。如何才能看到其他的文档? 03. ElasticSearch 如何指定搜

    2023年04月08日
    浏览(44)
  • Java SpringBoot API 实现ES(Elasticsearch)搜索引擎的一系列操作(超详细)(模拟数据库操作)

    小编使用的是elasticsearch-7.3.2 基础说明: 启动:进入elasticsearch-7.3.2/bin目录,双击elasticsearch.bat进行启动,当出现一下界面说明,启动成功。也可以访问http://localhost:9200/ 启动ES管理:进入elasticsearch-head-master文件夹,然后进入cmd命令界面,输入npm run start 即可启动。访问http

    2024年02月04日
    浏览(54)
  • 【ES专题】ElasticSearch搜索进阶

    丑话说在前头 ,说实在这篇笔记写的不是很好,确实很多没有实操。 系列上一篇文章:《【ES专题】ElasticSearch 高级查询语法Query DSL实战》 系列下一篇文章:《【ES专题】ElasticSearch集群架构剖析》 理解ES的核心概念,最最重要的是【索引】和【文档】 理解基本的Query DSL语法

    2024年01月16日
    浏览(60)
  • ElasticSearch(ES) 搜索入门笔记

    ElasticSearch简称ES,经过多年的发展,已是很流行的搜索工具了,无需多介绍,下面就粘一点官方介绍 You know, for search (and analysis) Elasticsearch is the distributed search and analytics engine at the heart of the Elastic Stack. Logstash and Beats facilitate collecting, aggregating, and enriching your data and storing it i

    2024年01月22日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包