F.56. seg — тип данных для отрезков или интервалов чисел с плавающей точкой #
Этот модуль реализует тип данных seg
для представления отрезков или интервалов чисел с плавающей точкой. Тип seg
может выражать отсутствие уверенности в границах интервала, что позволяет применять его для представления лабораторных измерений.
Данный модуль считается «доверенным», то есть его могут устанавливать обычные пользователи, имеющие право CREATE
в текущей базе данных.
F.56.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.56.2. Синтаксис #
Внешнее представление интервала образуется одним или двумя числами с плавающей точкой, соединёнными оператором диапазона (..
или ...
). Кроме того, интервал можно задать центральной точкой плюс/минус отклонение. Также этот тип позволяет сохранить дополнительные индикаторы достоверности (<
, >
или ~
). (Однако индикаторы достоверности игнорируются всеми встроенными операторами.) Допустимые представления показаны в Таблице F.36; некоторые примеры приведены в Таблице F.37.
В Таблице F.36 символы x
, y
и delta
обозначают числа с плавающей точкой. Перед значениями x
и y
, но не delta
, может быть добавлен индикатор достоверности.
Таблица F.36. Внешнее представление seg
| Одно значение (интервал нулевой длины) |
| Интервал от x до y |
| Интервал от x - delta до x + delta |
| Открытый интервал с нижней границей x |
.. | Открытый интервал с верхней границей x |
Таблица F.37. Примеры допустимых вводимых значений 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...2 , либо 1 .. 2 , либо 1..2 (пробелы вокруг оператора диапазона игнорируются) |
Так как оператор ...
часто используется в источниках данных, он принимается в качестве альтернативного написания оператора ..
. К сожалению, это порождает неоднозначность при разборе: неясно, какая верхняя граница имеется в виду в записи 0...23
— 23
или 0.23
. Для разрешения этой неоднозначности во входных числах seg
перед десятичной точкой всегда должна быть минимум одна цифра.
В качестве меры предосторожности, seg
не принимает интервалы с нижней границей, превышающей верхнюю, например: 5 .. 2
.
F.56.3. Точность #
Значения seg
хранятся внутри как пары 32-битных чисел с плавающей точкой. Это значит, что числа с более чем 7 значащими цифрами будут усекаться.
Числа, содержащие 7 и меньше значащих цифр, сохраняют изначальную точность. То есть, если запрос возвращает 0.00, вы можете быть уверены, что конечные нули не являются артефактами форматирования: они отражают точность исходных данных. Количество ведущих нулей не влияет на точность: значение 0.0067 будет считаться имеющим только две значащих цифры.
F.56.4. Использование #
Модуль seg
включает класс операторов индекса GiST для значений seg
. Операторы, поддерживаемые этим классом операторов, перечислены в Таблице F.38.
Таблица F.38. Операторы seg для GiST
Оператор Описание |
---|
Первый |
Первый |
Первый |
Первый |
Два отрезка |
Два отрезка |
Первый |
Первый |
Также для типа seg
поддерживаются стандартные операторы сравнения, показанные в Таблица 9.1. Эти операторы сначала сравнивают (a) с (c), и если они равны, сравнивают (b) с (d). Результат сравнения позволяет упорядочить значения образом, подходящим для большинства случаев, что полезно, если вы хотите применять ORDER BY с этим типом.
F.56.5. Примечания #
Примеры использования можно увидеть в регрессионном тесте sql/seg.sql
.
Механизм, преобразующий (+-)
в обычные диапазоны, не вполне точно определяет число значащих цифр для границ. Например, он добавляет дополнительную цифру к нижней границе, если результирующий интервал включает степень десяти:
postgres=> select '10(+-)1'::seg as seg; seg --------- 9.0 .. 11 -- должно быть: 9 .. 11
Производительность индекса-R-дерева может значительно зависеть от начального порядка вводимых значений. Может быть очень полезно отсортировать входную таблицу по столбцу seg
; пример можно найти в скрипте sort-segments.pl
.
F.56.6. Благодарности #
Первый автор: Джин Селков мл. <selkovjr@mcs.anl.gov>
, Аргоннская национальная лаборатория, Отдел математики и компьютерных наук
Я очень благодарен в первую очередь профессору Джо Геллерштейну (https://dsf.berkeley.edu/jmh/) за пояснение сути GiST (http://gist.cs.berkeley.edu/). Я также признателен всем разработчикам Postgres в настоящем и прошлом за возможность создать свой собственный мир и спокойно жить в нём. Ещё я хотел бы выразить признательность Аргоннской лаборатории и Министерству энергетики США за годы постоянной поддержки моих исследований в области баз данных.