美文网首页Ngix开源springboot
elasticsearch地理位置查询

elasticsearch地理位置查询

作者: huan1993 | 来源:发表于2021-04-21 17:57 被阅读0次

    一、背景

    最近有个需求,需要获取某个位置附近的楼盘,比如:获取当前用户所在位置,方圆100km千米之内的楼盘信息。经过调研,发现可以使用 redismongodbelasticsearch等实现。经过考虑之后决定使用es来实现,此处简单记录下esgeo方面api的使用。

    二、geo数据类型

    es中存在2种地理位置数据类型,geo_pointgeo_shapees无法自动识别这种数据类型,需要在创建mapping的时候,自己手动指定。

    1、geo_point

    geo_point使用的是经纬度的坐标点,可以计算落在某个矩形内的点、以某个点为半径(圆)的点、某个多边形内的点(弃用了)、排序、聚合等操作。

    geo_point

    2、geo_shape

    geo_shape表示的是一个复杂的图形,使用的是GeoJSON的格式来表示复杂的图形。比如:我们要表示一个图书馆的坐标位置,如果图书馆占的位置比较大,用一个点表示可能就不准了,此时就可以使用geo_shape来表示了。

    不过这种数据类型也有缺点:比如不能排序等等(因为是多边形的点)。

    三、此处对geo_point类型实战

    1、背景

    image-20210421161252713

    1、图中的 ① ② ③ ④ 表示是需要加入到 es 中的建筑物

    建筑物 坐标 距离地点 相隔距离 解释
    上海站 121.462311,31.256224 上海站
    上海静安洲际酒店 121.460186,31.251281 上海站 586.24米 上海站和该酒店大概像个586.24米
    交通公园 121.473939,31.253531 上海站 1146.45米
    万业远景大厦 121.448215,31.26229 上海站 1501.74米

    2、图中的圆形、正方形、多边形表示后期需要使用 es 查询出来里面里面的地点。

    3、图中的短小的箭头➡️表示边界。

    2、插入地点数据

    1、创建索引

    PUT /geo_index
    {
      "settings": {
        "number_of_shards": 2,
        "number_of_replicas": 2,
        "analysis": {
          "analyzer": {
            "default": {
              "type": "ik_max_word"
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "building_name": {
            "type": "keyword"
          },
          "location": {
            // 此处手动指定数据类型
            "type": "geo_point"
          }
        }
      }
    }
    

    注意⚠️:

    1、在索引中,我们自己指定来location字段的类型为geo_point类型。

    2、building_name的字段类型为keyword表示不分词,这个字段只是为了测试,没有什么用。

    3、不用指定索引的type,在es7中只有一个type。

    2、插入地理位置数据

    POST _bulk
    {"create":{"_index":"geo_index","_id":1}}
    {"building_name":"上海站","location":{"lat":31.256224,"lon":121.462311}}
    {"create":{"_index":"geo_index","_id":2}}
    {"building_name":"上海静安洲际酒店","location":"POINT (121.460186 31.251281)"}
    {"create":{"_index":"geo_index","_id":3}}
    {"building_name":"交通公园","location":"31.253531,121.473939"}
    {"create":{"_index":"geo_index","_id":4}}
    {"building_name":"万业远景大厦","location":[121.448215,31.26229]}
    

    注意⚠️:

    1、从上面可知:地理位置的插入的格式可以存在4种方式。

    1、 {"lat":"","lon":""}
    2、 "lat,lon"
    3、 [Well-Known Text](https://docs.opengeospatial.org/is/12-063r5/12-063r5.html) "POINT (lon lat)"
    4、 [lon,lat]
    5、 还有一种 geohash 的格式
    
    需要注意的是:使用 数组/Well-Known-Text 的格式的时候,经纬度是反过来的。
    

    3、执行检索

    1、geo_bounding_box 矩形过滤

    矩形位置大概坐标

    从上图可知左上角和右下方的坐标分别为 (121.444075,31.265395)和(121.468417,31.253845)

    执行查询,应该可以查询出 上海站万业远景大厦

    1、es查询语句

    GET /geo_index/_search
    {
      "query": {
        "bool": {
          "must": {
            "match_all": {}
          },
          "filter": {
            "geo_bounding_box": {
              "location": {
                "top_left": {
                  "lat": 31.265395,
                  "lon": 121.444075
                },
                "bottom_right": {
                  "lat": 31.253845,
                  "lon": 121.468417
                }
              }
            }
          }
        }
      }
    }
    

    2、查询结果

    矩形查询结果

    从图中可以看到,查询出来了 上海站万业远景大厦,结果是正确的。

    2、geo_distance 圆形查询

    这个是距离查询,是以某个点向周围扩算的距离范围。

    image-20210421161252713

    在上一步的背景中,我们知道上海站的坐标(121.462311,31.256224),同时也知道了上海站距离各个周边的距离有多远,此处我们以上海站为中心,查询方圆600米的建筑物,可知只有上海静安洲际酒店上海站符合。

    1、es查询语句

    GET /geo_index/_search
    {
      "query": {
        "bool": {
          "must": {
            "match_all": {}
          },
          "filter": {
            "geo_distance": {
              "distance": "600m",
              "distance_type": "arc", 
              "_name":"optional_name",
              "location": {
                "lat": 31.256224,
                "lon": 121.462311
              }
            }
          }
        }
      }
    }
    

    注意⚠️:

    1、distance_type的值存在2个 arcplane

    • arc:默认的方式,这种方式计算比较精确,但是比较慢,是把地球当作一个球体计算。

    • plane:这种方式计算比较快,但是可能不怎么准,越靠近赤道越准,是把地球当成平坦的进行计算。

    2、distance后面可用的单位有kmmcmmmnmimiydftin

    image-20210421164716919

    2、查询结果

    距离查询

    3、geo_distance 查询并排序,返回距离相隔多少米

    1、es 查询语句

    GET /geo_index/_search
    {
      "query": {
        "bool": {
          "must": {
            "match_all": {}
          },
          "filter": {
            "geo_distance": {
              "distance": "600m",
              "distance_type": "arc",
              "_name": "optional_name",
              "location": {
                "lat": 31.256224,
                "lon": 121.462311
              }
            }
          }
        }
      },
      "sort": [
        {
          "_geo_distance": {
            "location": {
              "lat": 31.256224,
              "lon": 121.462311
            },
            "order": "desc",
            "unit": "m",
            "distance_type": "arc"
          }
        }
      ]
    }
    

    注意⚠️:

    1、sort执行排序。

    2、查询结果

    距离排序

    4、geo_distance聚合

    需求:

    1. 统计`上海站`500米之内的建筑物有多少。
    2. 统计`上海站`500-1000米之内的建筑物有多少。
    3. 统计`上海站`大于1000米的建筑物有多少。
    

    1、es查询语句

    GET /geo_index/_search
    {
      "query": {
        "bool": {
          "must": {
            "match_all": {}
          }
        }
      },
      "aggs": {
        "rings_around_amsterdam": {
          "geo_distance": {
            "field": "location",
            "origin": {
              "lat": 31.256224,
              "lon": 121.462311
            },
            "unit": "m",
            "distance_type": "arc",
            "ranges": [
              {"to": 500,"key": "first"},
              {"from": 500,"to": 1000,"key": "second" },
              {"from": 1000,"key": "third"}
            ],
            "keyed": true
          }
        }
      }
    }
    

    2、查询结果

    聚合

    从上图中可以看到:

    1、距离上海站在 0-500米之间的建筑物只有1个。

    2、距离上海站在 500-1000之间的建筑物有1个。

    3、距离上海站在 1000以上的有2个。

    5、geo-polygon-多边形查询(过时)

    在 es7.12 中已经过时了,推荐使用 geo_shape来实现

    多边形查询过时了,推荐使用geo_shape查询

    6、一个综合案例

    1、需求:

    1、查询语句query,查询出所有的数据,并过滤出以上海站为中心的3km内的所有的建筑物。

    2、aggs,用于统计出上海在 500米以内、500-1000米、1000米之外的建筑物数量。

    3、sort用于排序。

    4、post_filter用于将结果缩小到上海站1000米以内。

    2、查询结果

    GET /geo_index/_search
    {
      "query": {
        "bool": {
          "must": {
            "match_all": {}
          },
     // 过滤出上海站周围3km范围内的建筑物
          "filter": {
            "geo_distance": {
              "distance": "3km",
              "distance_type": "arc", 
              "_name":"optional_name",
              "location": {
                "lat": 31.256224,
                "lon": 121.462311
              }
            }
          }
        }
      },
     // 聚合上海站周围的建筑物的数量
      "aggs": {
        "rings_around_amsterdam": {
          "geo_distance": {
            "field": "location",
            "origin": {
              "lat": 31.256224,
              "lon": 121.462311
            },
            "unit": "m",
            "distance_type": "arc",
            "ranges": [
              {"to": 500,"key": "first"},
              {"from": 500,"to": 1000,"key": "second" },
              {"from": 1000,"key": "third"}
            ],
            "keyed": true
          }
        }
      },
    // 对查询到的结果排序,并将距离放到响应数据的 sort 字段中。
      "sort": [
        {
          "_geo_distance": {
            "location": {
              "lat": 31.256224,
              "lon": 121.462311
            },
            "order": "desc",
            "unit": "m",
            "distance_type": "arc"
          }
        }
      ],
    // 将结果缩小到上海站附近1km的范围内。
      "post_filter": {
        "geo_distance": {
          "distance": "1km",
          "location": {
            "lat": 31.256224,
            "lon": 121.462311
          }
        }
      }
    }
    

    四、参考文档

    1、geo_point数据类型

    2、距离单位

    3、排序

    4、矩形查询

    5、圆形查询,距离查询

    6、坐标拾取系统

    相关文章

      网友评论

        本文标题:elasticsearch地理位置查询

        本文链接:https://www.haomeiwen.com/subject/kgmzlltx.html