F.57. seg
Этот модуль реализует тип данных seg
для представления отрезков или интервалов чисел с плавающей точкой. Тип seg
может выражать отсутствие уверенности в границах интервала, что позволяет применять его для представления лабораторных измерений.
F.57.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.57.2. Синтаксис
Внешнее представление интервала образуется одним или двумя числами с плавающей точкой, соединёнными оператором диапазона (..
или ...
). Кроме того, интервал можно задать центральной точкой плюс/минус отклонение. Также этот тип позволяет сохранить дополнительные индикаторы достоверности (<
, >
или ~
). (Однако индикаторы достоверности игнорируются всеми встроенными операторами.) Допустимые представления показаны в Таблице F.42; некоторые примеры приведены в Таблице F.43.
В Таблице F.42 символы x
, y
и delta
обозначают числа с плавающей точкой. Перед значениями x
и y
, но не delta
, может быть добавлен индикатор достоверности.
Таблица F.42. Внешнее представление seg
| Одно значение (интервал нулевой длины) |
| Интервал от x до y |
| Интервал от x - delta до x + delta |
| Открытый интервал с нижней границей x |
.. | Открытый интервал с верхней границей x |
Таблица F.43. Примеры допустимых вводимых значений 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.57.3. Точность
Значения seg
хранятся внутри как пары 32-битных чисел с плавающей точкой. Это значит, что числа с более чем 7 значащими цифрами будут усекаться.
Числа, содержащие 7 и меньше значащих цифр, сохраняют изначальную точность. То есть, если запрос возвращает 0.00, вы можете быть уверены, что конечные нули не являются артефактами форматирования: они отражают точность исходных данных. Количество ведущих нулей не влияет на точность: значение 0.0067 будет считаться имеющим только две значащих цифры.
F.57.4. Использование
Модуль seg
включает класс операторов индекса GiST для значений seg
. Операторы, поддерживаемые этим классом операторов, перечислены в Таблице F.44.
Таблица F.44. Операторы seg для GiST
Оператор | Описание |
---|---|
[a, b] << [c, d] | [a, b] полностью находится левее [c, d]. То есть, [a, b] << [c, d] — true, если b < c, и false в противном случае. |
[a, b] >> [c, d] | [a, b] полностью находится правее [c, d]. То есть, [a, b] >> [c, d] — true, если a > d, и false в противном случае. |
[a, b] &< [c, d] | Пересекает или левее — Ещё лучше это читается как «не простирается правее». Результатом будет true, когда b <= d. |
[a, b] &> [c, d] | Пересекает или правее — Ещё лучше это читается как «не простирается левее». Результатом будет true, когда 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], то есть, a >= c и b <= d. |
(До версии PostgreSQL 8.2 операторы включения @>
и <@
обозначались соответственно как @
и ~
. Эти имена по-прежнему действуют, но считаются устаревшими и в конце концов будут упразднены. Заметьте, что старые имена произошли из соглашения, которому раньше следовали ключевые геометрические типы данных!)
Также поддерживаются стандартные операторы для B-дерева, например:
Оператор | Описание |
---|---|
[a, b] < [c, d] | Меньше |
[a, b] > [c, d] | Больше |
Эти операторы не имеют большого смысла ни для какой практической цели, кроме сортировки. Эти операторы сначала сравнивают (a) с (c), и если они равны, сравнивают (b) с (d). Результат сравнения позволяет упорядочить значения образом, подходящим для большинства случаев, что полезно, если вы хотите применять ORDER BY с этим типом.
F.57.5. Замечания
Примеры использования можно увидеть в регрессионном тесте sql/seg.sql
.
Механизм, преобразующий (+-)
в обычные диапазоны, не вполне точно определяет число значащих цифр для границ. Например, он добавляет дополнительную цифру к нижней границе, если результирующий интервал включает степень десяти:
postgres=> select '10(+-)1'::seg as seg; seg --------- 9.0 .. 11 -- должно быть: 9 .. 11
Производительность индекса-R-дерева может значительно зависеть от начального порядка вводимых значений. Может быть очень полезно отсортировать входную таблицу по столбцу seg
; пример можно найти в скрипте sort-segments.pl
.
F.57.6. Благодарности
Первый автор: Джин Селков мл. <selkovjr@mcs.anl.gov>
, Аргоннская национальная лаборатория, Отдел математики и компьютерных наук
Я очень благодарен в первую очередь профессору Джо Геллерштейну (https://dsf.berkeley.edu/jmh/) за пояснение сути GiST (http://gist.cs.berkeley.edu/). Я также признателен всем разработчикам Postgres в настоящем и прошлом за возможность создать свой собственный мир и спокойно жить в нём. Ещё я хотел бы выразить признательность Аргоннской лаборатории и Министерству энергетики США за годы постоянной поддержки моих исследований в области баз данных.