受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

F.37. seg #

该模块实现了一个用于表示线段或浮点区间的seg数据类型。 seg可以表示区间端点中的不确定性,因此特别适合表示实验室测量结果。

该模块被视为受信任的,也就是说,拥有当前数据库 CREATE权限的非超级用户也可以安装它。

F.37.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.37.2. 语法 #

区间的外部表示由一个或两个浮点数通过范围操作符(.....)连接而成。另一种写法是指定中心点再加减一个 偏差值。还可以存储可选的确定性指示符(<>~)。(不过,所有内置操作符 都会忽略这些确定性指示符。)Table F.26概述了允许的 表示形式;Table F.27给出了一些示例。

Table F.26中,xydelta表示浮点数。 xy前面可以带确定性 指示符,而delta不可以。

Table F.26. seg 外部表示

x 单个值(零长度区间)
x .. y xy的区间
x (+-) delta x - deltax + delta的区间
x .. 下界为x、上界开放的区间
.. x 上界为x、下界开放的区间

Table F.27. 合法 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 ... 2 1...21 .. 21..2相同 (范围操作符两侧的空格会被忽略)

由于...操作符在数据源中被广泛使用,因此允许把它作为 ..操作符的另一种写法。不幸的是,这会带来解析歧义: 无法确定0...23中的上界是23还是 0.23。解决办法是要求seg输入中的所有 数字在小数点前至少有一位数字。

作为合理性检查,seg会拒绝下界大于上界的区间,例如 5 .. 2

F.37.3. 精度 #

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

有效位数不超过 7 位的数字会保留其原始精度。也就是说,如果你的查询返回 0.00,你可以确信末尾的零不是格式化造成的假象,而是反映了原始数据的精度。 前导零的个数不影响精度:值 0.0067 被认为只有 2 位有效数字。

F.37.4. 用法 #

seg模块包含适用于seg值的一个 GiST 索引 操作符类。该 GiST 操作符类支持的操作符见Table F.28

Table F.28. seg GiST 操作符

操作符

描述

seg << segboolean

第一个seg是否完全位于第二个的左侧? [a, b] << [c, d] 在 b < c 时为真。

seg >> segboolean

第一个seg是否完全位于第二个的右侧? [a, b] >> [c, d] 在 a > d 时为真。

seg &< segboolean

第一个seg是否没有向右超出第二个? [a, b] &< [c, d] 在 b <= d 时为真。

seg &> segboolean

第一个seg是否没有向左超出第二个? [a, b] &> [c, d] 在 a >= c 时为真。

seg = segboolean

两个seg是否相等?

seg && segboolean

两个seg是否重叠?

seg @> segboolean

第一个seg是否包含第二个?

seg <@ segboolean

第一个seg是否被第二个包含?


除上述操作符外,Table 9.1中列出的常用 比较操作符也可用于seg类型。这些操作符先比较 (a) 和 (c), 若二者相等,再比较 (b) 和 (d)。这在大多数情况下都能得到相当不错的排序 效果,因此如果你想将该类型用于 ORDER BY,会很有帮助。

F.37.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.37.6. 致谢 #

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

我首先要感谢 Joe Hellerstein 教授 (https://dsf.berkeley.edu/jmh/), 他为我阐明了 GiST (http://gist.cs.berkeley.edu/) 的要旨。 我同样感谢过去和现在所有的 Postgres 开发者, 他们使我得以创造自己的世界并在其中不受打扰地生活。 我还要感谢阿贡实验室以及美国能源部,多年来始终如一地支持我的数据库研究。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。