美文网首页
ElasticSearch GeoLocation 官方文档翻译

ElasticSearch GeoLocation 官方文档翻译

作者: 斯威特 | 来源:发表于2017-03-09 17:54 被阅读0次

    Geo Points

    Geo-points 就是我们地球的经纬度,它能够用于计算地球两点之间的距离。

    Geo-points 不能使用动态mapping,必须提前制定好geo_point类型

    PUT /attractions
    {
      "mappings": {
        "restaurant": {
          "properties": {
            "name": {
              "type": "string"
            },
            "location": {
              "type": "geo_point"
            }
          }
        }
      }
    }
    

    Lat/Lon Formats

    假设我们把 location 字段定义为geo_point 类型,我们创建文档的时候应该包含一对 latitude/longitude ,可以是 string ,arrays 或者 objects

    PUT /attractions/restaurant/1
    {
      "name":     "Chipotle Mexican Grill",
      "location": "40.715, -74.011" 
    }
    
    PUT /attractions/restaurant/2
    {
      "name":     "Pala Pizza",
      "location": { 
        "lat":     40.722,
        "lon":    -73.989
      }
    }
    
    PUT /attractions/restaurant/3
    {
      "name":     "Mini Munchies Pizza",
      "location": [ -73.983, 40.719 ] 
    }
    

    注意:

    latitude/longitude 在每种类型的顺序是不一样的,在字符串中是"latitude,longitude",但是在数组中应为[longitude,latitude],

    以前,字符串和数组中的经纬度顺序是一致的,但是为了和GeoJSON保持一致,所以讲数组的经纬度顺序颠倒了。

    Filtering by Geo Point

    四种geo-point filters 可以帮助我们去过滤数据,当我们使用geolocation时。

    geo_bounding_box:
    找出落在一个指定的长方形中的geo-points
    geo_distance:
    找出以一个点为中心,一个指定半径范围内的geo-points
    geo_distance_range:
    找出以一个点为中心,设置一个最小半径和一个最大半径,在这个之间的geo-points
    geo_polygon:
    找出落在一个多边形范围内的geo-points,这个代价是相当昂贵的,如果你有这样的需求,建议使用 geo-shapes

    每种filter的计算一个点是否落到一个区域的方式有些不同,但过程都是相似的。
    所请求的区域被转换为quad/geohash前缀标记的范围,然后去倒排索引中搜索具有相同标记的文档。

    建议:

    Geo-filters 是相当耗费性能的,它适合用于在文档数量较少的时候。首先,你应该利用其它filter先过滤掉一部分数据。

    Geo Bounding Box Filter

    它是到目前为止最有效率的filter,因为他的计算非常简单。你只需提供上、下、左、右四个坐标,剩下的就是他会比较longitude 是否在左右坐标内,latitude 是否在上下坐标内

    GET /attractions/restaurant/_search
    {
      "query": {
        "filtered": {
          "filter": {
            "geo_bounding_box": {
              "location": { 
                "top_left": {
                  "lat":  40.8,
                  "lon": -74.0
                },
                "bottom_right": {
                  "lat":  40.7,
                  "lon": -73.0
                }
              }
            }
          }
        }
      }
    }
    

    Optimizing Bounding Boxes

    geo_bounding_box 是不需要将所有的geo-points都加载到内存的。因为它需要做的就是检查the lat and lon 是否落到了一个指定的区域。它可以用倒排索引去做个一次过滤。

    为了使用这种优化,我们必须指定geo_point 的映射,设置 "lat_lon": true

    PUT /attractions
    {
      "mappings": {
        "restaurant": {
          "properties": {
            "name": {
              "type": "string"
            },
            "location": {
              "type":    "geo_point",
              "lat_lon": true 
            }
          }
        }
      }
    }
    

    现在,当你执行下面的查询时,我们会告诉elasticsearch使用lat 和lon的索引

    GET /attractions/restaurant/_search
    {
      "query": {
        "filtered": {
          "filter": {
            "geo_bounding_box": {
              "type":    "indexed", 
              "location": {
                "top_left": {
                  "lat":  40.8,
                  "lon": -74.0
                },
                "bottom_right": {
                  "lat":  40.7,
                  "lon":  -73.0
                }
              }
            }
          }
        }
      }
    }
    

    Geo Distance Filter

    geo_distance 这个过滤器会画个圆,来找到在这个落在这个圆内所有的文档

    GET /attractions/restaurant/_search
    {
      "query": {
        "filtered": {
          "filter": {
            "geo_distance": {
              "distance": "1km", 
              "location": { 
                "lat":  40.715,
                "lon": -73.988
              }
            }
          }
        }
      }
    }
    

    geo-distance 的搜索是相当耗费性能的,为了优化,elasticsearch会首先会画一个内切于圆的正方形。然后用bounding-box filter 过滤掉一部分数据。然后在执行geo-distance filter去找到那些落在圆内的数据。

    Faster Geo-Distance Calculations

    两点之间的距离可以利用一个牺牲性能来提高精度的算法去计算

    arc:
    最慢但是精度最高的就是arc 了,一个把地球看成一个球体,但是精度还是有限的,因为实际上地球并不是一个真正的球体
    plane:
    plane 算法把地球看成扁平的。它很快但是精度低。在赤道精度最高。
    sloppy_arc:
    这么称呼他是因为这个算法是粗滤的计算。

    在查询的时候,你可以和下面一样,指定一个算法

    GET /attractions/restaurant/_search
    {
      "query": {
        "filtered": {
          "filter": {
            "geo_distance": {
              "distance":      "1km",
              "distance_type": "plane", 
              "location": {
                "lat":  40.715,
                "lon": -73.988
              }
            }
          }
        }
      }
    }
    

    geo_distance_range Filter

    geo_distance 和 geo_distance_range 的唯一区别是,geo_distance_range是一个圆环。

    GET /attractions/restaurant/_search
    {
      "query": {
        "filtered": {
          "filter": {
            "geo_distance_range": {
              "gte":    "1km", 
              "lt":     "2km", 
              "location": {
                "lat":  40.715,
                "lon": -73.988
              }
            }
          }
        }
      }
    }
    

    Sorting by Distance

    查询结果是可以跟到一个点的距离排序的

    GET /attractions/restaurant/_search
    {
      "query": {
        "filtered": {
          "filter": {
            "geo_bounding_box": {
              "type":       "indexed",
              "location": {
                "top_left": {
                  "lat":  40.8,
                  "lon": -74.0
                },
                "bottom_right": {
                  "lat":  40.4,
                  "lon": -73.0
                }
              }
            }
          }
        }
      },
      "sort": [
        {
          "_geo_distance": {
            "location": { 
              "lat":  40.715,
              "lon": -73.998
            },
            "order":         "asc",
            "unit":          "km", 
            "distance_type": "plane" 
          }
        }
      ]
    }
    

    你可以问问你自己,为什么要指定距离单位,排序?这不取决于我们用米、千米而产生不同的结果。真是的原因是排序的时候会返回结果

    ...
      "hits": [
         {
            "_index": "attractions",
            "_type": "restaurant",
            "_id": "2",
            "_score": null,
            "_source": {
               "name": "New Malaysia",
               "location": {
                  "lat": 40.715,
                  "lon": -73.997
               }
            },
            "sort": [
               0.08425653647614346 
            ]
         },
    ...
    

    相关文章

      网友评论

          本文标题:ElasticSearch GeoLocation 官方文档翻译

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