Skip to content

F.39. seg — 线段或浮点间隔的数据类型#

F.39.1. 基本原理
F.39.2. 语法
F.39.3. 精度
F.39.4. 用法
F.39.5. 注释
F.39.6. 鸣谢

此模块实现了一个数据类型seg,用于表示线段或浮点间隔。seg可以表示区间端点的模糊性,这使其特别适用于表示实验室测量值。

此模块被认为是“受信任的”,也就是说,它可以由具有当前数据库的CREATE权限的非超级用户安装。

F.39.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.39.2. 语法#

区间的外部表示使用一个或两个浮点数形成,这些浮点数由范围运算符(.....)连接。或者,可以将其指定为中心点加或减偏差。也可以存储可选的确定性指示符(<>~)。(但是,所有内置运算符都忽略确定性指示符。)表 F.28概述了允许的表示;表 F.29显示了一些示例。

表 F.28中,xydelta表示浮点数。可以为xy(但不能为*delta*)加上确定性指示符。

表 F.28.seg外部表示

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

表 F.29. 有效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 .. 21..2 相同(范围运算符周围的空格会被忽略)

由于...运算符在数据源中广泛使用,因此允许将其作为..运算符的替代拼写。不幸的是,这会造成解析歧义:无法明确0...23中的上界是23还是0.23。可以通过要求seg输入中所有数字的小数点前至少有一个数字来解决此问题。

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

F.39.3. 精度#

seg值在内部存储为 32 位浮点数对。这意味着具有 7 位以上有效数字的数字将被截断。

具有 7 位或更少有效数字的数字将保留其原始精度。也就是说,如果您的查询返回 0.00,则可以确定尾随零不是格式化的结果:它们反映了原始数据的精度。前导零的数量不会影响精度:值 0.0067 被认为只有 2 位有效数字。

F.39.4. 用法#

seg模块包含一个针对seg值的 GiST 索引运算符类。GiST 运算符类支持的运算符显示在表 F.30中。

表 F.30. Seg GiST 运算符

运算符

说明

seg << segboolean

第一个 seg 是否完全在第二个 seg 的左侧?如果 b < c,则 [a, b] << [c, d] 为 true。

seg >> segboolean

第一个 seg 是否完全在第二个 seg 的右侧?如果 a > d,则 [a, b] >> [c, d] 为 true。

seg &< segboolean

第一个 seg 是否不延伸到第二个 seg 的右侧?如果 b <= d,则 [a, b] &< [c, d] 为 true。

seg &> segboolean

第一个 seg 是否不延伸到第二个 seg 的左侧?如果 a >= c,则 [a, b] &> [c, d] 为 true。

seg = segboolean

两个 seg 是否相等?

seg && segboolean

两个 seg 是否重叠?

seg @> segboolean

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

seg <@ segboolean

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

除了上述运算符外,表 9.1中显示的常用比较运算符也可用于类型seg。这些运算符首先将 (a) 与 (c) 进行比较,如果它们相等,则将 (b) 与 (d) 进行比较。在大多数情况下,这会产生相当好的排序结果,如果您想对该类型使用 ORDER BY,这将非常有用。

F.39.5. 注释#

有关使用示例,请参阅回归测试sql/seg.sql

(+-)转换为常规范围的机制在确定边界有效数字时并不完全准确。例如,如果结果区间包含十次幂,它会向较低边界添加一个额外的数字

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

R 树索引的性能在很大程度上取决于输入值的初始顺序。在seg列上对输入表进行排序可能非常有帮助;请参阅脚本sort-segments.pl以获取示例。

F.39.6. 鸣谢#

原作者:Gene Selkov, Jr.<[[email protected]](/cdn-cgi/l/email-protection#4b382e2720243d21390b262838652a2527652c243d)>,数学与计算机科学部,阿贡国家实验室。

我首先要感谢 Joe Hellerstein 教授 (https://dsf.berkeley.edu/jmh/),因为他阐明了 GiST (http://gist.cs.berkeley.edu/) 的要点。我还感谢所有过去和现在的 Postgres 开发人员,因为他们让我能够创造自己的世界并不受干扰地生活在其中。而且,我要感谢阿贡实验室和美国能源部多年来对我数据库研究的忠实支持。