欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-23 15:45:44
...

概念

在上个小节,我们学习了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