F.34. seg

这个模块为表示线段或者浮点区间实现了一种数据类型segseg可以表示区间端点中的不确定性,这使得它对表达实验室测量特别有用。

F.34.1. 原理

度量的几何结构通常比一个数字连续区中的一个点更复杂。 一个度量通常是具有一些模糊限制的连续区的一个分段。 由于不确定性和随机性,也因为被度量的值可能天然地就是 一个指示某种情况的区间(例如一种蛋白质的稳态的温度范围), 度量呈现为区间的形式。

只用常识,我们就知道将这类数据存储为区间比存储为数字对更加方便。 实际上,这样做在大部分应用中也更有效。

还是根据常识,限度的模糊性意味着使用传统的数字数据类型会导致信息丢失。 试想:你的仪器读到 6.50,并且你把这个读数输入到数据库。在你取出它时会 得到什么?看看:

test=> select 6.50 :: float8 as "pH";
 pH
---
6.5
(1 row)

在度量世界里,6.50 和 6.5 并不相同。有时候它们可能很不同。实验者们通常会 写下(并且发表)他们信任的数字。6.50 实际上是一个模糊的区间,它被包含于 一个更大的而且更模糊的区间 6.5 中,它们的中心点(可能)是它们唯一共享的 公共特征。我们绝对不希望这类不同的数据项表现得相同。

结论?一种能够记录具有任意可变精度的区间的限度的特殊数据类型是很好的。 这种意义下,每一个数据元素都记录其自身的精度。

来看看这个:

test=> select '6.25 .. 6.50'::seg as "pH";
          pH
------------
6.25 .. 6.50
(1 row)

F.34.2. 语法

一个区间的外部表达由通过范围操作符(..或者...)连接的一个或者两个浮点数构成。 或者,它也可以被指定为一个中心点加上或者减去一个偏差值。 也能够存储可选的确定性指示符(<>或者~)。不过,所有内建操作符会忽略确定性指示符。 表 F-27给出了所有允许的表达形式,表 F-28展示了一些例子。

表 F-27中,xydelta表示浮点数。 xy可以前置一个确定性指示符,但是delta不行。

表 F-27. seg外部表达

x单一值(零长度区间)
x .. yxy的区间
x (+-) deltax - deltax + delta的区间
x ..下界为x的开区间
.. x上界为x的开区间

表 F-28. 合法seg输入的例子

5.0 创建一个零长度的段(一个点)
~5.0 创建一个零长度的段并且在数据中记录~~会被seg操作忽略,但是会被保留为一个注释。
<5.0 在 5.0 创建一个点。<会被忽略,但是被保留为一个注释。
>5.0 在 5.0 创建一个点。>会被忽略,但是被保留为一个注释。
5(+-)0.3 创建一个区间4.7 .. 5.3。注意(+-)标记不会被保留。
50 .. 大于或等于 50 的所有东西
.. 0小于或等于 0 的所有东西
1.5e-2 .. 2E-2 创建一个区间0.015 .. 0.02
1 ... 21...21 .. 2或者1..2相同 (范围操作符周围的空格会被忽略)

由于...被广泛地用在数据源中,它被允许作为..的一种替代。 不幸地是,这会带来解析歧义:分不清0...23的上界是23或者0.23。 通过要求seg输入中所有数字的小数点前至少有一位可以解决这个问题。

作为一种完整性检查,seg会拒绝下界大于上界的区间,例如5 .. 2

F.34.3. 精度

seg值在内部被存储为一对 32 位浮点数。这意味着具有超过 7 个有效位的数字会被截断。

具有 7 个或者更少有效位的数字会保留它们的原有精度。即,如果你的查询返回 0.00, 你可以确信拖尾的零不是人工造成的,它们反映了原始数据的精度。前导零的数量不影响精度: 值 0.0067 被认为只有 2 个有效位。

F.34.4. 用法

seg模块包括了用于seg值的一个 GiST 索引操作符类。 该 GiST 操作符类所支持的操作符在表 F-29中展示。

表 F-29. Seg GiST 操作符

操作符描述
[a, b] << [c, d][a, b] 完全位于 [c, d] 左边。即如果b < c 则 [a, b] << [c, d] 为真,否则为假。
[a, b] >> [c, d][a, b] 完全位于 [c, d] 右边。即如果b > c 则 [a, b] >> [c, d] 为真,否则为假。
[a, b] &< [c, d]重叠或者是在左边 — 这最好读作 "不超过右边"。当 b <= d 时为真。
[a, b] &> [c, d]重叠或者是在右边 — 这最好读作 "不超过左边"。当 a >= c 时为真。
[a, b] = [c, d]相等 — 段 [a, b] 和 [c, d] 是一样的,也就是 a = c 并且 b = d。
[a, b] && [c, d]段 [a, b] 和 [c, d] 重叠。
[a, b] @> [c, d]段 [a, b] 包含段 [c, d],也就是 a <= c 并且 b >= d。
[a, b] <@ [c, d]段 [a, b] 被包含在 [c, d] 中,也就是 >= c 并且 b <= d。

(在 PostgreSQL 8.2 之前,包含操作符 @><@ 分别被 称为@~。这些名称仍然可用,但是已被废弃并且最终会消失。 注意旧的名称与核心几何数据类型之前遵循的习惯相反!)

也提供了标准的 B-树操作符,例如

操作符描述
[a, b] < [c, d]小于
[a, b] > [c, d]大于

这些操作符对除了排序之外的任何实际目的都没有什么意义。 这些操作符首先比较 a 和 c,并且如果它们相等则比较 b 和 d。 在大部分情况下这会得到相当好的排序,如果你想对这种类型使用 ORDER BY, 这会很有用。

F.34.5. 注解

使用的例子,请见回归测试sql/seg.sql

(+-)转换成常规范围的机制在确定边界的有效位数时并不完全准确。 例如,如果结果区间包括一个 10 的幂时,它会加上一个额外的位:

postgres=> select '10(+-)1'::seg as seg;
      seg
---------
9.0 .. 11             -- should be: 9 .. 11

一个 R-树索引的性能很大程度上依赖于输入值的初始顺序。 将输入表以seg列进行排序将会非常有帮助, 例子可见脚本sort-segments.pl

F.34.6. 开发人员

原始作者: Gene Selkov, Jr. , 阿尔贡国家实验室数学和计算机科学部。

我要感谢 Joe Hellerstein 教授 (http://db.cs.berkeley.edu/jmh/)解释了 GiST(http://gist.cs.berkeley.edu/)。 我也要向现在和过去的所有 Postgres 开发者致敬,让我能创造自己的世界并且不受打扰地生活在其中。我也要感谢阿尔贡实验室以及美国能源部多年来对我数据库研究的支持。