首页 > ELK > elasticsearch基于地理位置的搜索
2019
07-14

elasticsearch基于地理位置的搜索

场景


现在基于地理位置的app层出不穷,支持地理位置的组件也有不少,Elasticsearch也不例外,并且ES可以把地理位置、全文搜索、结构化搜索和分析结合到一起,我们来看一下。


注意

本文章基于es7,用es6的话可能语法稍有不同,仅供参考

geo point数据类型

Elasticsearch基于地理位置的搜索,有一个专门的对象geo_point存储地理位置信息(经度,纬度),并且提供了一些基本的查询方法,如geo_bounding_box。

建立geo_point类型的mapping

PUT /my_geo
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      },
      "name": {
        "type": "text"
      }
    }
  }
}

创建了一个my_geo索引,添加了一个字段location,它的类型是geo_point


插入数据

#latitude:维度,longitude:经度
POST /my_geo/_doc
{
    "name":"路人甲",
    "location":{
        "lat": 39.90279998006104,
        "lon": 116.42703999493406
    }
}

POST /my_geo/_doc
{
    "name":"路人乙",
    "location":{
        "lat": 39.93367367974064,
        "lon": 116.47845257733152
    }
}


范围查询(3种方式)

1.geo_distance查询,根据当前位置的距离进行搜索,非常实用

查询5km范围内都有谁,filter使用geo_distance查询,我们定义距离distance为5km,再指定geo类型的字段location

POST /my_geo/_search
{
    "query":{
        "bool":{
            "filter":{
                "geo_distance":{
                    "distance":"5km",
                    "location":{
                        "lat":39.93031708627304,
                        "lon":116.4470385453491
                    }
                }
            }
        }
    }
}

结果发现:路人甲,路人乙都出来啦,你再试着改变举例3km看看效果呢?


2.geo_bounding_box查询,查询某个矩形的地理位置范围内的坐标点

POST /my_geo/_search
{
  "query": {
     "geo_bounding_box": {
      "location": {
        "top_left":{
          "lon": 116,
          "lat": 39.99
        },
        "bottom_right":{
          "lon": 117,
          "lat": 39.9
        }
      }
    } 
  }
}

3.geo_polygon查询,查询三个点(三角形)范围内的坐标点

支持多边形,只是这个过滤器使用代价很大,尽量少用

POST /my_geo/_search
{
  "query": {
    "geo_polygon": {
      "location": {
        "points": [
          {
            "lon": 115,
            "lat": 23
          },
          {
            "lon": 113,
            "lat": 25
          },
          {
            "lon": 112,
            "lat": 21
          }
        ]
      }
    }
  }
}

按距离排序

按从近到远排序

POST /my_geo/_search
{
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "5km",
          "location": {
            "lat": 39.93031708627304,
            "lon": 116.4470385453491
          }
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 39.93031708627304,
          "lon": 116.4470385453491
        },
        "order": "asc",
        "unit": "m",
        "distance_type": "plane"
      }
    }
  ]
}

_geo_distance: 固定写法,下面为指定位置的经纬度

unit: 距离的单位,m/km都行

distance_type: 计算距离的方式,sloppy_arc (默认值), arc (精准的) and plane (最快速的)

返回值:

{
  "took" : 1,
  "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" : "kH1qEHQBfUQLnDXv35Mt",
        "_score" : null,
        "_source" : {
          "name" : "路人乙",
          "location" : {
            "lat" : 39.93367367974064,
            "lon" : 116.47845257733152
          }
        },
        "sort" : [
          2704.400492813901
        ]
      },
      {
        "_index" : "my_geo",
        "_type" : "_doc",
        "_id" : "j31qEHQBfUQLnDXvfJOK",
        "_score" : null,
        "_source" : {
          "name" : "路人甲",
          "location" : {
            "lat" : 39.90279998006104,
            "lon" : 116.42703999493406
          }
        },
        "sort" : [
          3503.0165324004943
        ]
      }
    ]
  }
}

sort里面的内容,就是与当前位置的地面距离,单位是m。


统计我当前位置几个范围内人的数量

unit表示距离单位,常用的是mi和km。

distance_type表示计算距离的方式,sloppy_arc (默认值), arc (精准的) and plane (最快速的)。

POST /my_geo/_search
{
  "size": 0,
  "aggs": {
    "group_by_distance": {
      "geo_distance": {
        "field": "location",
        "origin": {
          "lon": 39.933673679,
          "lat": 116.47845257
        },
        "unit": "mi", 
        "distance_type": "arc", 
        "ranges": [
          {"from": 0,"to": 1000},
          {"from": 1000,"to": 2000},
          {"from": 2000,"to": 5000}
        ]
      }
    }
  }
}


本文》有 0 条评论

留下一个回复