语法-空间值

Neo
Neo
2022-03-17 / 0 评论 / 64 阅读

本节内容源自Cypher官方手册V4.4版,笔者对其进行学习、翻译、记录。

Cypher 内置了对处理空间值(点)的支持,并且底层数据库支持将这些点值存储为节点和关系上的属性。

简介

Neo4j 仅支持一种类型的空间几何,即具有以下特征的点:

  • 每个点可以有 2 或 3 个维度。这意味着它包含 2 个或 3 个 64 位浮点值,它们一起称为Coordinate。

  • 每个点还将与一个特定的坐标参考系统(CRS) 相关联,该坐标参考系统确定Coordinate中值的含义。

  • Point的实例和Point的列表可以分配给节点和关系属性。

  • 具有Point或List(Point)属性的节点可以使用空间索引进行索引。这适用于所有 CRS(以及 2D 和 3D)。创建空间索引没有特殊语法,因为它支持使用现有索引。

  • 距离函数适用于所有 CRS 以及 2D 和 3D 中的点,但前提是这两个点具有相同的 CRS(因此也具有相同的维度)。

坐标参考系统

支持四种坐标参考系统 (CRS),每一种都属于以下两种类型之一:地球上的地理坐标建模点,或欧几里得空间中的笛卡尔坐标建模点:

  • 地理坐标参考系

    • WGS-84:经度、纬度 (x, y)

    • WGS-84-3D:经度、纬度、高度(x、y、z)

  • 笛卡尔坐标参考系

    • 笛卡尔:x,y

    • 笛卡尔 3D:x、y、z

不同坐标系内的数据是完全无法比较的,不能隐式地从一个坐标系转换到另一个坐标系。即使它们都是笛卡尔坐标系或地理坐标系也是如此。例如,如果您使用 2D 范围搜索 3D 点,您将得不到任何结果。但是,它们可以排序,如排序和值比较中更详细讨论的那样。

地理坐标参考系

支持两个地理坐标参考系统 (CRS),对地球上的点进行建模:

  • WGS 84 2D

    • WGS 84 CRS中的 2D 地理点通过以下两种方式之一指定:

      • longitude和latitude(如果指定了这些,但crs不是,则crs假定为WGS-84)

      • x和y(在这种情况下crs必须指定,或将被假定为Cartesian)

    • 可以使用名称“wgs-84”或 SRID 4326 指定此 CRS,如Point(WGS-84)中所述

  • WGS 84 3D

    • WGS 84 CRS中的 3D 地理点通过以下两种方式之一指定:

      • longitude,latitude或者heightor z(如果指定了这些,但crs不是,则crs假定为WGS-84-3D)

      • x,y和z(在这种情况下crs必须指定, 或将被假定为Cartesian-3D)

    • 可以使用名称“wgs-84-3d”或 SRID 4979 指定此 CRS,如Point(WGS-84-3D)中所述

latitude和longitude字段的单位是十进制度,需要使用 Cypher 语法指定为浮点数。不能使用任何其他格式,例如“度、分、秒”。字段height的单位是米。将地理点传递给distance函数时,结果将始终以米为单位。如果坐标的格式或单位不受支持,则必须显式转换它们。例如,如果传入$height的是一个以公里为单位的字符串字段,则需要键入height: toFloat($height) * 1000. 同样,如果distance期望函数的结果以公里为单位返回,则需要显式转换。例如:RETURN point.distance(a,b) / 1000 AS km。演示传入和传出值转换的示例是:

WITH
  point({latitude:toFloat('13.43'), longitude:toFloat('56.21')}) AS p1,
  point({latitude:toFloat('13.10'), longitude:toFloat('56.41')}) AS p2
RETURN toInteger(point.distance(p1, p2)/1000) AS km
42

笛卡尔坐标参考系

支持两个笛卡尔坐标参考系统 (CRS),在欧几里得空间中建模点:

  • 笛卡尔二维

    • 笛卡尔CRS中的 2D 点由包含坐标值x的地图指定y

    • 可以使用名称“笛卡尔”或 SRID 7203 指定此 CRS,如Point(Cartesian)中所述

  • 笛卡尔 3D

    • 笛卡尔CRS中的 3D 点由包含x、y和z坐标值的地图指定

    • 可以使用名称“cartesian-3d”或 SRID 9157 指定此 CRS,如Point(Cartesian-3D)中所述

x、y和z字段的单位未指定,可以表示用户想要表示的任何内容。这也意味着,当两个笛卡尔点传递给距离函数时,结果值的单位将与原始坐标相同。对于二维和三维点都是如此,因为所使用的毕达哥拉斯方程可以推广到任意数量的维度。但是,正如无法将地理点与笛卡尔点进行比较一样,也无法计算二维点与三维点之间的距离。如果需要这样做,请显式地将一种类型转换为另一种类型。例如:

WITH
  point({x: 3, y: 0}) AS p2d,
  point({x: 0, y: 4, z: 1}) AS p3d
RETURN
  point.distance(p2d, p3d) AS bad,
  point.distance(p2d, point({x: p3d.x, y: p3d.y})) AS good
5.0

空间瞬间

创建点

所有点类型均由两个组件创建:

  • 包含 2 个或 3 个浮点值(64 位)的坐标

  • 定义坐标中值的含义(可能还有单位)的坐标参考系统(或 CRS)

对于大多数用例,没有必要明确指定 CRS,因为它将从用于指定坐标的键中推导出来。应用两条规则从坐标推导出 CRS:

  • 按键选择:

    • 如果使用键指定坐标latitude并且longitudeCRS 将被假定为Geographic并且因此是WGS-84或WGS-84-3D。

    • 如果改为使用x和y,则默认 CRS 将是Cartesian或Cartesian-3D

  • 维数:

    • 如果坐标中有 2 个维度,x&y或longitude&latitude则 CRS 将是 2D CRS

    • 如果坐标中有第三维,z或者height,CRS将是 3D CRS

所有字段都以point显式命名参数的映射形式提供给函数。由于地理坐标和笛卡尔坐标之间的矛盾约定,我们特别不支持坐标字段的有序列表,其中地理坐标通常y在之前x(latitude之前longitude)列出。例如,请参见以下查询,该查询返回在四个受支持的 CRS 中的每一个中创建的点。请特别注意原始point函数调用中坐标的顺序和键,以及这些值如何在结果中显示:

RETURN
  point({x: 3, y: 0}) AS cartesian_2d,
  point({x: 0, y: 4, z: 1}) AS cartesian_3d,
  point({latitude: 12, longitude: 56}) AS geo_2d,
  point({latitude: 12, longitude: 56, height: 1000}) AS geo_3d
cartesian_2dcartesian_3dgeo_2dgeo_3d
point({x: 3.0, y: 0.0, crs: 'cartesian'})point({x: 0.0, y: 4.0, z: 1.0, crs: 'cartesian-3d'})point({x: 56.0, y: 12.0, crs: 'wgs-84'})point({x: 56.0, y: 12.0, z: 1000.0, crs: 'wgs-84-3d'})

对于地理坐标,重要的是要注意该latitude值应始终位于区间内[-90, 90],超出此范围的任何其他值都会引发异常。该longitude值应始终位于区间内[-180, 180],并且此范围之外的任何其他值都将被环绕以适应此范围。该height值和任何笛卡尔坐标都没有明确限制,任何在有符号 64 位浮点类型允许范围内的值都将被接受。

访问点的组件

正如我们使用地图语法构造点一样,我们也可以将组件作为实例的属性来访问。
|组件|描述|类型|范围、格式|WGS-84|WGS-84-3D|Cartesian|Cartesian-3D|
|-------|-------|-------|-------|-------|-------|-------|-------|
|instant.x|坐标的第一个元素|Float|数字文字,范围取决于CRS|√|√|√|√|
|instant.y|坐标的第二个元素|Float|数字文字,范围取决于CRS|√|√|√|√|
|instant.z|坐标的第三个元素|Float|数字文字,范围取决于CRS||√||√|
|instant.latitude|地理坐标系的第二个元素,赤道以北度|Float|数字文字,-90.0到90.0|√|√|||
|instant.longitude|地理CRS坐标的第一个元素,本初子午线以东度|Float|数字文字,-180.0到180.0|√|√|||
|instant.height|地理CRS坐标的第三个元素,位于基准面(WGS-84)定义的椭球面上方米处|Float|数字文字,范围仅受基础64位浮点类型限制||√|||
|instant.crs|CRS的名称|String||√|√|√|√|
|instant.srid|CRS的内部Neo4j ID|Integer||√|√|√|√|

以下查询显示如何提取笛卡尔 2D点值的分量:

WITH point({x: 3, y: 4}) AS p
RETURN
  p.x AS x,
  p.y AS y,
  p.crs AS crs,
  p.srid AS srid

以下查询显示了如何提取WGS-84 3D点值的分量:

WITH point({latitude: 3, longitude: 4, height: 4321}) AS p
RETURN
  p.latitude AS latitude,
  p.longitude AS longitude,
  p.height AS height,
  p.x AS x,
  p.y AS y,
  p.z AS z,
  p.crs AS crs,
  p.srid AS srid

空间索引

如果在特定的:Label(property)组合上有索引,并且在具有该标签的节点上为该属性指定了空间点,则该节点将在空间索引中被索引。对于空间索引,Neo4j在基础的广义B+树上使用2D或3D空间填充曲线。点将存储在最多四个不同的树中,四个坐标参考系各一个。这允许使用与其他属性类型完全相同的语法和行为进行相等和范围查询。如果使用两个范围谓词(定义最小点和最大点),这将有效地生成边界框查询。此外,在适当的条件下,使用距离函数的查询也可以使用索引,如“空间距离搜索”一节所述。

可比性和可排序性

空间值的可比性和有序性取决于即将发布的未来版本的变化。这意味着依赖于使用不等式运算符比较两点的查询,⇐, >, 和>=,或按ORDER BY n.point的查询将需要重写。

最有效的方法是明确指定排序。例如,通过在笛卡尔坐标中使用point.x,point.y或在地理坐标中使用point.longitudepoint.latitude