可比较性、相等性、有序性和等价性

AGE在基础数据类型(布尔值、字符串、整数和浮点数)和映射中已经具有良好的相等性语义。另外,Cypher对整数、浮点数和字符串在各自类型内的可比较性和有序性也具有良好的语义。

然而,处理不同类型值时的行为偏离了Postgres的定义逻辑和openCypher规范:

  • 不同类型值之间的可比较性是已定义的。这种偏离在作为谓词评估(在WHERE中)的一部分时尤为明显。

  • ORDER BY不会因为传递的值具有不同的类型而失败。

底层的概念模型复杂且有时不一致。这导致比较运算符、相等性、分组和ORDER BY之间的关系不清楚:

  • 可比较性和有序性是一致对齐的,因为所有类型都可以被排序和比较。

  • 相等性和等价性的区别,由IN=DISTINCT和分组暴露出来,在AGE中仅限于测试两个值为null的实例是否相等。

    • 在相等性中,null = nullnull

    • 在等价性中,用于DISTINCT和分组值时,两个null值始终被视为相同的值。

    • 如果null值是列表或映射值的元素,则相等性会以不同的方式处理null值。

概念

openCypher规范中包含四个与相等性和排序相关的不同概念:

可比较性

可比较性用于不等式运算符(>、<、>=、<=),并定义如何比较两个值的基本语义。

相等性

相等性用于等式操作符(=、<>)和列表成员操作符(IN),定义了在这些上下文中确定两个值是否相同的底层语义。相等性还隐式地用于节点和关系模式中的字面量映射,因为这样的字面量映射只是相等性谓词的简写形式。

有序性

有序性用于ORDER BY子句,定义如何对值进行排序的基本语义。

等价性

等价性用于DISTINCT修饰符和投影子句(WITHRETURN)中的分组,定义了在这些上下文中确定两个值是否相同的底层语义。

可比较性和相等性

比较运算符需要符合预期,即相等性和可比较性。但同时,还需要允许对列数据进行排序,确保等价性和有序性。

不幸的是,在PostgreSQL中,可能无法为同一查询实现分别用于相等性和比较操作,以及等价性和有序性操作的独立比较运算符。因此,我们优先考虑等价性和有序性,以允许对输出数据进行排序。

可比较性

可比较性定义在任何一对值之间,如下所述。

  • 数字

    • 不同类型的数字(不包括NaN值和无穷大)在进行数值比较之前,会被强制转换为任意精度的大数(目前不在Cypher类型系统中),然后按升序进行数值比较。

    • 与非数字类型的值进行比较时,遵循可排序性的规则。

    • 浮点数没有足够的精度来表示Agtype整数和Agtype数值范围内的所有整数。当将Agtype整数或数值类型转换为浮点数时,在高值和低值范围内可能会出现意外结果。

    • 整数

      • 整数按升序进行数值比较。

    • 浮点数

      • 浮点数(不包括NaN值和无穷大)按升序进行数值比较。

      • 正无穷大是FLOAT类型,等于自身且大于任何其他数字,但不包括NaN值。

      • 负无穷大是FLOAT类型,等于自身且小于任何其他数字。

      • NaN值彼此可比较,并且大于任何其他浮点数值。

    • 数值

      • 数值按升序进行比较。

  • 布尔值

    • 布尔值的比较规则是:false小于true

    • 与非布尔类型的值进行比较时,遵循可排序性的规则。

  • 字符串

    • 字符串按字典顺序比较,即从字符串的开始到结束逐字符按升序比较。较短字符串中缺失的字符被视为小于任何其他字符。例如,'a' < 'aa'

    • 与非字符串类型的值进行比较时,遵循可排序性的规则。

  • 列表

    • 列表按顺序比较,即从列表的开始到结束逐元素按升序比较。较短列表中缺失的元素被视为小于任何其他值(包括null值)。例如,[1] < [1, 0]但同样[1] < [1, null]

    • 与非列表类型的值进行比较时,遵循可排序性的规则。

  • 映射

    • 映射的比较顺序未指定,由实现决定。

    • 映射的比较顺序必须与下面概述的等价语义一致。因此,任何包含将键映射到null值的条目的映射都是不可比较的。例如,{a: 1} <= {a: 1, b: null}返回null

    • 与非普通映射的值进行比较时,遵循可排序性的规则。

实体

  • 顶点

    • 顶点的比较顺序基于分配的graphid

    • 边的比较顺序基于分配的graphid

  • 路径

    • 路径的比较方式如同它们是从起始节点到结束节点的路径中交替的节点和关系的列表。例如,给定节点n1n2n3和关系r1r2,并且n1 < n2 < n3r1 < r2,那么从n1经过r1n3的路径p1将小于从n2经过r2n1的路径p2

    • 用列表表示:

      p1 < p2
      <=> [n1, r1, n3] < [n1, r2, n2]
      <=> n1 < n1 || (n1 = n1 && [r1, n3] < [r2, n2])
      <=> false || (true && [r1, n3] < [r2, n2])
      <=> [r1, n3] < [r2, n2]
      <=> r1 < r2 || (r1 = r2 && n3 < n2)
      <=> true || (false && false)
      <=> true
      说明

      与非路径的值进行比较时,返回false

  • NULL

    • null与任何其他值(包括其他null值)都不可比较。

不同Agtype之间的可排序性

在使用<<=>>=对不同Agtype进行排序时,从最小值到最大值的顺序为:

  1. Path

  2. Edge

  3. Vertex

  4. Object

  5. Array

  6. String

  7. Bool

  8. Numeric, Integer, Float

  9. NULL

说明

以上顺序在未来的版本中可能会发生变化。