Elasticsearch(022):es常见的字段映射类型之地理形状类型(geo_shape、多边的复杂的地址形状)

概念

在上个小节,我们学习了geo_point的数据类型。

这一小节我们来学习geo_shape数据类型,它有助于索引和搜索 任意地理形状,例如矩形和多边形。当正在索引的数据或正在执行的查询包含除点以外的其他形状时,应使用它

通过上面的概念描述,我们可以得出geo_pointgeo_shape的最大区别是: geo_point表示一个点;geo_shape则表示有多个点连成线组成的形状。 学过数学的肯定很容易理解。

实际开发中,如果我们的地理坐标是一个地理形状,则可以使用地理形状数据类型进行插入、查询文档。比如说学校、大商场这种面积比较大的地理坐标,都需要geo_shape来表示。

  • mapping params

geo_shape映射将geo_json几何对象映射到geo_shape类型。要启用它,用户必须将字段显式映射到geo_shape类型。

地理形状数据类型的参数选项

选项 说明 默认值
tree 将使用的PrefixTree实现的名称:GeohashPrefixTree为geohash,QuadPrefixTree为quadtree。 geohash
precision 可以使用此参数代替tree_levels来为tree_levels参数设置适当的值。该值指定所需的精度,Elasticsearch将计算最佳的tree_levels值以兑现该精度。该值应为数字,后跟可选的距离单位。有效距离单位包括:英寸,英寸,码,码,英里,英里,公里,公里,米,米,厘米,厘米,毫米,毫米。 meters
tree_levels PrefixTree使用的最大层数。这可用于控制形状表示的精度,从而控制索引多少项。默认为所选PrefixTree实现的默认值。由于此参数要求对底层实现有一定程度的了解,因此用户可以改用precision参数。但是,Elasticsearch仅在内部使用tree_levels参数,即使您使用precision参数,这也是通过映射API返回的结果 50m
strategy 策略参数定义了如何在索引和搜索时表示形状的方法。它还会影响可用的功能,因此建议让Elasticsearch自动设置此参数。有两种可用的策略:递归和术语。术语策略仅支持点类型(points_only参数将自动设置为true),而递归策略则支持所有形状类型。(重要:请参见前缀树以获取更多详细信息) recursive
distance_error_pct 用作PrefixTree关于其精度的提示。默认值为0.025(2.5%),最大支持值为0.5。性能注意:如果明确定义了precision或tree_level定义,则此值将默认为0。这样可以保证映射中定义的级别的空间精度。对于低误差的高分辨率形状(例如,误差小于0.001的1m大形状),这可能会导致大量内存使用。为了提高索引性能(以查询准确性为代价),显式定义tree_level或precision以及合理的distance_error_pct,请注意,较大的形状将具有更大的误报率。 0.025
orientation (可选)定义如何解释多边形/多多边形的顶点顺序。此参数定义两个坐标系规则(右手或左手)之一,可以用三种不同的方式来指定每个规则。1.右手规则:右,逆时针,逆时针2. 2.左手规则:左,顺时针,顺时针。默认方向(逆时针)符合OGC标准,该标准以逆时针顺序定义外环顶点,而内环顶点(孔)以顺时针顺序定义。在geo_shape映射中设置此参数可显式设置geo_shape字段的坐标列表的顶点顺序,但可以在每个单独的GeoJSON文档中覆盖。 ccw
points_only 将此选项设置为true(默认为false)可仅为点形状配置geo_shape字段类型(注意:尚不支持多点)。当已知仅索引点时,这将优化geohash和四叉树的索引和搜索性能。目前,无法对geo_point字段类型执行geo_shape查询。此选项通过改善geo_shape字段上的点性能来弥合差距,从而使geo_shape查询在仅点字段上是最佳的。 false
ignore_malformed 如果为true,则会忽略格式错误的geojson形状。如果为假(默认),则格式错误的geojson形状会引发异常并拒绝整个文档。 false
  • 前缀树

为了有效地表示索引中的形状,使用PrefixTree的实现将Shapes转换为代表网格正方形的一系列哈希(通常称为“栅格”)。树的概念来自这样一个事实,即PrefixTree使用多个网格层,每个网格层的精度更高,以表示地球。
可以认为这是在更高的缩放级别下增加地图或图像的细节级别。

es中提供了多个PrefixTree实现。

  • GeohashPrefixTree 对网格正方形使用geohash。Geohash是交错的纬度和经度的位的base32编码的字符串。
    因此,哈希越长,它越精确。添加到geohash的每个字符代表另一个树级别,并为geohash增加5位精度。Geohash表示一个矩形区域,并具有32个子矩形。Elasticsearch中的最大级别数为24。

  • QuadPrefixTree 对网格正方形使用四叉树。与geohash相似,四叉树将纬度和经度的比特交织在一起,结果哈希被置位。
    四叉树中的树级别代表此位集中的2位,每个坐标一个。Elasticsearch中四叉树的最大级别数为50。

  • 空间策略

PrefixTree实现依赖于SpatialStrategy来将提供的Shape分解为近似的网格正方形。每种策略都回答以下问题:

  • 可以索引哪种类型的形状?
  • 可以使用哪些类型的查询操作和形状?
  • 每个字段是否支持多个Shape?

提供以下策略实施(具有相应的功能):

策略 支持的形状 支持的查询 多个形状
recursive All INTERSECTS, DISJOINT, WITHIN, CONTAINS(相交,不相交,内含) Yes
term Points INTERSECTS (相交) Yes
  • 准确性

Geo_shape不提供100%的准确性,并且取决于它的配置方式,它可能对INTERSECTSWITHINCONTAINS查询返回一些误报,而对DISJOINT查询返回一些误报。

为了减轻这种情况,为tree_levels参数选择适当的值并相应地调整期望很重要。例如,一个点可能在特定网格像元的边界附近,因此可能与仅与它紧邻的像元匹配的查询不匹配-即使形状非常接近该点。

示例使用

比如说我们有一些大商场的地理信息。我们想要实现在某个地理位置附近多少米范围有哪些大商场?

1. mapping定义

PUT my_index
{
    "mappings": {
        "docs": {
            "properties": {
                "name": {"type": "text"},
                "location": {
                    "type": "geo_shape"
                }
            }
        }
    }
}

2. 添加数据

PUT my_index/docs/1000
{
  "name": "中心商场",
  "location": {
    "type": "point",
    "coordinates": [121.392496,31.245827]
  }
}
PUT my_index/docs/1001
{
  "name": "城北商场",
  "location": {
    "type": "point",
    "coordinates": [121.392496,31.30]
  }
}
PUT my_index/docs/1002
{
  "name": "城南商场",
  "location": {
    "type": "point",
    "coordinates": [121.392496,31.013]
  }
}
PUT my_index/docs/1003
{
  "name": "城西商场",
  "location": {
    "type": "point",
    "coordinates": [121.821,31.245827]
  }
}
PUT my_index/docs/1004
{
  "name": "城东商场",
  "location": {
    "type": "point",
    "coordinates": [122.392496,31.245827]
  }
}

上例中大量的方括号可能看起来让人困惑,不过实际上 GeoJSON的语法非常简单.

  1. 用一个数组表示 经纬度 坐标点 [lon,lat]

  2. 一组坐标点放到一个数组来表示一个多边形[[lon,lat],[lon,lat], ... ]

  3. 一个多边形( polygon )形状可以包含多个多边形;第一个表示多边形的外轮廓,后续的多边形表示第一个多边形内部的空洞

[
  [[lon,lat],[lon,lat], ... ],  # main polygon
  [[lon,lat],[lon,lat], ... ],  # hole in main polygon
  ...
]

3. 查询

比如说查询 查询指定位置10KM范围内的大商场信息数据。

GET my_index/docs/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_shape": {
          "location": {
            "shape": {
              "type": "circle",
              "radius": "10km",
              "coordinates": [121.392496, 31.3]
            }
          }
        }       
      }
    }

  }
}

返回结果集

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1,
    "hits": [
      {
        "_index": "my_index",
        "_type": "docs",
        "_id": "1001",
        "_score": 1,
        "_source": {
          "name": "城北商场",
          "location": {
            "type": "point",
            "coordinates": [
              121.392496,
              31.3
            ]
          }
        }
      },
      {
        "_index": "my_index",
        "_type": "docs",
        "_id": "1000",
        "_score": 1,
        "_source": {
          "name": "中心商场",
          "location": {
            "type": "point",
            "coordinates": [
              121.392496,
              31.245827
            ]
          }
        }
      }
    ]
  }
}

发现有两个商场符合条件。
后面有geo_shape更复杂的应用,在这里我们的重点和学习geo_shape这种类型概念和简单使用。

你可能感兴趣的:(ElasticSearch)