ElasticSearch GEO:地理坐标点(geo point)

来自Wikioe
跳到导航 跳到搜索


关于

在 ES 中地理坐标指的就是经度和纬度,ES 中存储经纬度坐标的数据类型为:geo_point

定义geo_point类型映射

可以通过定义索引映射的时候,指定字段类型为 geo_point,表示存储的是一个经纬度坐标值。


示例:

PUT /shop
{
  "mappings": {
    "properties": {
      "location": { 
        "type": "geo_point" // location字段的类型为geo_point
      }
    }
  }
}

geo_point的存储格式

保存 geo_point 类型的数据主要有下面几种格式:

  1. PUT /shop/_doc/1
    {
      "location": { 
        "lat": 41.12,
        "lon": -71.34
      }
    }
    
    • lat:纬度
    • lon:经度
  2. PUT /shop/_doc/2
    {
      "location": [ -71.34, 41.12 ] 
    }
    
    • [ 经度, 纬度]:以数组的形式存储经纬度
  3. PUT /shop/_doc/3
    {
      "location": "41.12,-71.34" 
    }
    
    • "纬度,经度":以字符串的形式存储经纬度

按距离搜索(geo_distance

如果 ES 索引的字段类型为:geo_point,我们就可以按距离搜索文档。


示例:

  1. 创建店铺索引:
    PUT /shops
    {
      "mappings": {
        "properties": {
          "id": { // 店铺Id
            "type": "integer"
          },
          "title": { // 店铺名
            "type": "text"
          },
          "location": { // 店铺经纬度
            "type": "geo_point"
          }
        }
      }
    }
    
  2. 按距离搜索:通过 geo_distance 搜索指定距离内的文档
    GET /shops/_search
    {
      "query": { // query查询
        "bool": { // 布尔组合查询
          "must": { 
            "match_all": {} // 这里不设置其他查询条件,所以匹配全部文档
          },
          "filter": { // 【因为地理信息搜索不打算参与相关度计算,所以使用 filter 包裹 geo_distance】
            "geo_distance": { // 【geo_distance 按距离搜索】
              "distance": "1km", // 设置搜索距离为1千米
              "location": { // 搜索location字段存储的经纬度和当前经纬度之间的距离。
                "lat": 39.889916, // 当前纬度
                "lon": 116.379547 // 当前经度
              }
            }
          }
        }
      }
    }
    

如上,搜索当前经纬度和 location 字段存储的经纬度之间的距离在 1 千米范围之内的所有文档。


geo_distance参数说明:

  • distance:设置搜索距离,常用距离单位:km(千米)、m(米)
  • 当前经纬度坐标点:既然要计算距离,肯定需要知道两个坐标点才能计算,所以 geo_distance 参数需要提供当前坐标点。

按距离排序(_geo_distance

根据地理信息搜索文档之后,返回多个文档数据的时候,很多业务场景都希望根据距离由近到远排序。


示例:

GET /shops/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_distance": { // 按距离搜索
          "distance": "1km", // 搜索1千米范围
          "location": { // 搜索字段为location
            "lat": 39.889916, // 当前纬度
            "lon": 116.379547 // 当前经度
          }
        }
      }
    }
  },
  "sort": [ // 设置排序条件
    {
      "_geo_distance": { //【 _geo_distance 代表根据距离排序】
        "location": { // 根据location存储的经纬度计算距离。
          "lat": 39.889916, // 当前纬度
          "lon": 116.379547 // 当前经度
        },
        "order": "asc" // asc 表示升序,desc 表示降序
      }
    }
  ]
}
  • 按距离排序条件,需要再次设置当前经纬度坐标,这样 ES 才知道计算距离的参考坐标。

按矩形范围搜索(geo_bounding_box

ES 中通过 geo_bounding_box 搜索,在地图画一个矩形,搜索矩形范围内的坐标点。


示例:在地图画一个矩形,把矩形范围内的店铺找出来。

GET /shops/_search
{
  "query": {
    "bool": { // 布尔组合查询
      "must": {
        "match_all": {} // 这里设置其他搜索条件,直接搜索所有文档
      },
      "filter": { // 地理信息搜索不打算参与相关度评分,所以使用filter包裹起来。
        "geo_bounding_box": { // geo_bounding_box实现按矩形范围搜索
          "location": { // 店铺的坐标点保存在location字段中
              "top_left": { // 【设置矩形的左上角坐标】
              "lat": 40.73, // 纬度
              "lon": -74.1 // 经度
              },
              "bottom_right": { // 【设置矩形的右下角坐标】
              "lat": 40.717,
              "lon": -73.99
              }
          }
        }
      }
    }
  },
  "sort": [ // 设置排序条件
    {
      "_geo_distance": { // _geo_distance代表按距离排序
        "location": { // 计算 location保存的坐标和当前坐标的距离
          "lat": 40, // 当前纬度
          "lon": -70 // 当前经度
        },
        "order": "asc" // 根据距离升序排序
      }
    }
  ]
}
  • 按矩形范围搜索店铺,如果需要对搜索的结果按距离排序,需要指定一个当前参考坐标,否则 ES 无法计算距离,也就是无法按距离排序。

按多边形范围搜索(geo_polygon

ES 通过 geo_polygon,在地图上画一个多边形,搜索包含在多边形内部的坐标点。


示例:在地图上画一个多边形,搜索店铺

GET /shops/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {} // 这里不设置其他搜索条件,直接匹配所有文档
      },
      "filter": { // 地理信息搜索不参与相关度算分,所以使用filter包裹起来
        "geo_polygon": { // geo_polygon 搜索语句
          "location": { // 店铺的坐标存储在location字段.
            "points": [ // 【设置组成多边形的经纬度坐标点数组】
              {
                "lat": 40.73, // 纬度
                "lon": -74.1 // 经度
              },
              {
                "lat": 40.83,
                "lon": -75.1
              },
              {
                "lat": 20,
                "lon": -90
              }
            ]
          }
        }
      }
    }
  }
}
  • 通常 ES 搜索中为了提升性能,可以使用 filter 禁掉相关度计算,还可以缓存查询结果