乐趣区

关于elasticsearch:elasticsearch地理位置查询

一、背景

最近有个需要,须要获取某个地位左近的楼盘,比方:获取以后用户所在位置,方圆 100km 千米之内的楼盘信息。通过调研,发现能够应用 redismongodbelasticsearch等实现。通过思考之后决定应用 es 来实现,此处简略记录下 esgeo方面 api 的应用。

二、geo 数据类型

es 中存在 2 种地理位置数据类型,geo_pointgeo_shapees 无奈自动识别这种数据类型,须要在创立 mapping 的时候,本人手动指定。

1、geo_point

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

2、geo_shape

geo_shape示意的是一个简单的图形,应用的是 GeoJSON 的格局来示意简单的图形。比方 :咱们要示意一个图书馆的坐标地位,如果图书馆占的地位比拟大,用一个点示意可能就不准了,此时就能够应用geo_shape 来示意了。

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

三、此处对 geo_point 类型实战

1、背景

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 圆形查问

这个是间隔查问,是以某个点向四周扩算的间隔范畴。

在上一步的 背景 中,咱们晓得 上海站 的坐标 (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

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 来实现

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、坐标拾取零碎

退出移动版