cube

Этот модуль реализует тип данных cube для представления многомерных кубов.

Этот модуль считается «доверенным», то есть его могут устанавливать обычные пользователи с правом CREATE в текущей базе данных.

Синтаксис

В Таблице 2 показаны допустимые внешние представления типа cube. Буквы x, y и т. д. обозначают числа с плавающей запятой.

Таблица 2. Внешние представления кубов

Внешний синтаксисЗначение
xОдномерная точка (или одномерный интервал нулевой длины)
(x)То же, что и выше
x1,x2,...,xnТочка в n-мерном пространстве, представленная внутри как куб нулевого объема
(x1,x2,...,xn)То же, что и выше
(x),(y)Одномерный интервал, начинающийся в точке x и заканчивающийся в y, либо наоборот; порядок значения не имеет
[(x),(y)]То же, что и выше
(x1,...,xn),(y1,...,yn)n-мерный куб, представленный парой диагонально противоположных углов
[(x1,...,xn),(y1,...,yn)]То же, что и выше

В каком порядке вводятся противоположные углы куба, не имеет значения. Функции, принимающие тип cube, автоматически меняют углы местами, если нужно создать единое внутреннее представление «левый нижний — правый верхний». Когда эти углы совмещаются, в cube для экономии пространства хранится только один угол с флагом «является точкой».

Пробелы во входных данных игнорируются, так что [(x),(y)] не отличается от [ ( x ), ( y ) ].

Точность

Значения хранятся внутри как 64-битные числа с плавающей запятой. Это означает, что числа с более чем 16 значащими цифрами будут усекаться.

Применение

В Таблице 3 показаны специальные операторы, предоставляемые для работы с типом cube.

Таблица 3. Операторы для кубов

ОператорОписание
cube && cube → booleanКубы пересекаются?
cube @> cube → booleanПервый куб содержит второй?
cube <@ cube → booleanПервый куб содержится во втором?
cube -> integer → float8Извлекает n-ю координату куба (считая с 1).
cube ~> integer → float8Извлекает n-ю координату куба, считая следующим образом: n = 2 * k - 1 обозначает нижнюю границу куба k-й размерности, а n = 2 * k обозначает верхнюю границу k-й размерности. Отрицательные n обозначают обратное значение соответствующей положительной координаты. Этот оператор разработан для поддержки KNN-GiST.
cube <-> cube → float8Вычисляет евклидово расстояние между двумя кубами.
cube <#> cube → float8Вычисляет расстояние городских кварталов (метрику L-1) между двумя кубами.
cube <=> cube → float8Вычисляет расстояние Чебышева (метрику L-бесконечность) между двумя кубами.

Помимо операторов, показанных выше, для типа cube имеются обычные операторы сравнения, показанные в Таблице 1 раздела Функции и операторы сравнения. Эти операторы сначала сравнивают первые координаты, и если они равны, сравнивают вторые и т. д. Они предназначены в основном для поддержки класса операторов индекса В-дерева для типа cube, который может быть полезен, например, если вы хотите создать наложить ограничение UNIQUE на столбец типа cube. В других случаях эта сортировка не очень полезна с практической точки зрения.

Модуль cube также предоставляет класс операторов индекса GiST для значений cube. Индекс GiST для cube можно использовать для поиска значений при помощи операторов =, &&, @> и <@ в предложениях WHERE.

Кроме того, индекс GiST для cube можно использовать для поиска ближайших соседей при помощи операторов метрики <->, <#> и <=> в предложениях ORDER BY. Например, ближайшего соседа точки в трехмерном пространстве (0.5, 0.5, 0.5) можно эффективно найти так:

SELECT c FROM test ORDER BY c <-> cube(array[0.5,0.5,0.5]) LIMIT 1;

Оператор ~> можно также использовать таким образом, чтобы эффективно выбрать первые несколько значений, отсортированных по выбранной координате. Например, чтобы получить первые несколько кубов, упорядоченных по возрастанию первой координаты (левого нижнего угла), можно использовать следующий запрос:

SELECT c FROM test ORDER BY c ~> 1 LIMIT 5;

А чтобы получить двумерные кубы, упорядоченные по убыванию первой координаты (правого верхнего угла):

SELECT c FROM test ORDER BY c ~> 3 DESC LIMIT 5;

В Таблице 4 показаны все доступные функции.

Таблица 4. Функции для работы с кубами

ФункцияОписаниеПример(ы)
cube ( float8 ) → cubeСоздает одномерный куб, у которого обе координаты равны.cube(1) → (1)
cube ( float8, float8 ) → cubeСоздает одномерный куб.cube(1, 2) → (1),(2)
cube ( float8[] ) → cubeСоздает куб нулевого объема, используя координаты, определяемые массивом.cube(ARRAY[1,2,3]) → (1, 2, 3)
cube ( float8[], float8[] ) → cubeСоздает куб с координатами правого верхнего и левого нижнего углов, определяемыми двумя массивами, которые должны быть одинаковой длины.cube(ARRAY[1,2], ARRAY[3,4]) → (1, 2),(3, 4)
cube ( cube, float8 ) → cubeСоздает новый куб, добавляя размерность к существующему кубу с одинаковым значением новой координаты для обоих углов. Это полезно для поэтапного построения кубов из вычисляемых значений.cube('(1,2),(3,4)'::cube, 5) → (1, 2, 5),(3, 4, 5)
cube ( cube, float8, float8 ) → cubeСоздает новый куб, добавляя размерность к существующему кубу. Это полезно для поэтапного построения кубов из вычисляемых значений.cube('(1,2),(3,4)'::cube, 5, 6) → (1, 2, 5),(3, 4, 6)
cube_dim ( cube ) → integerВозвращает число размерностей куба.cube_dim('(1,2),(3,4)') → 2
cube_ll_coord ( cube, integer ) → float8Возвращает значение n-й координаты левого нижнего угла куба.cube_ll_coord('(1,2),(3,4)', 2) → 2
cube_ur_coord ( cube, integer ) → float8Возвращает значение n-й координаты правого верхнего угла куба.cube_ur_coord('(1,2),(3,4)', 2) → 4
cube_is_point ( cube ) → booleanВозвращает true, если куб является точкой, то есть если два определяющих его угла совпадают.cube_is_point(cube(1,1)) → t
cube_distance ( cube, cube ) → float8Возвращает расстояние между двумя кубами. Если оба куба являются точками, вычисляется обычная функция расстояния.cube_distance('(1,2)', '(3,4)') → 2.8284271247461903
cube_subset ( cube, integer[] ) → cubeСоздает новый куб из существующего, используя список индексов размерностей из массива. Может применяться для получения конечных точек в одном измерении, для удаления измерений или изменения их порядка.cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[2]) → (3),(7)
cube_subset(cube('(1,3,5),(6,7,8)'), ARRAY[3,2,1,1]) → (5, 3, 1, 1),(8, 7, 6, 6)
cube_union ( cube, cube ) → cubeСоздает объединение двух кубов.cube_union('(1,2)', '(3,4)') → (1, 2),(3, 4)
cube_inter ( cube, cube ) → cubeСоздает пересечение двух кубов.cube_inter('(1,2)', '(3,4)') → (3, 4),(1, 2)
cube_enlarge ( c cube, r double, n integer ) → cubeУвеличивает размер куба на заданный радиус r как минимум в n измерениях. Если радиус отрицательных, куб, наоборот, уменьшается. Все определенные размерности изменяются на величину радиуса r. Координаты левого нижнего угла уменьшаются на r, а координаты правого верхнего угла увеличиваются на r. Если координата левого нижнего угла становится больше соответствующей координаты правого верхнего угла (это происходит, только когда r < 0), обе координаты устанавливаются в свое среднее значение. Если n превышает число определенных размерностей и куб увеличивается (r > 0), то добавляются дополнительные размерности, недостающие до n; в качестве начального значения для дополнительных координат используется 0. Эта функция полезна для создания вокруг точки ограничивающих прямоугольников с целью поиска ближайших точек.cube_enlarge('(1,2),(3,4)', 0.5, 3) → (0.5, 1.5, -0.5),(3.5, 4.5, 0.5)

Поведение по умолчанию

Я полагаю, что это объединение:

select cube_union('(0,5,2),(2,3,1)', '0');
cube_union
-------------------
(0, 0, 0),(2, 5, 2)
(1 row)

не противоречит здравому смыслу, как и это пересечение

select cube_inter('(0,-1),(1,1)', '(-2),(2)');
cube_inter
-------------
(0, 0),(1, 0)
(1 row)

Во всех бинарных операциях с кубами разных размерностей я полагаю, что куб с меньшей размерностью будет декартовой проекцией; т. е. в опущенных в строковом представлении координатах находятся нули. Значит, показанные выше примеры равнозначны следующим:

cube_union('(0,5,2),(2,3,1)','(0,0,0),(0,0,0)');
cube_inter('(0,-1),(1,1)','(-2,0),(2,0)');

В следующем предикате включения применяется синтаксис точек, хотя фактически второй аргумент представляется внутри кубом. Этот синтаксис избавляет от необходимости определять отдельный тип точек и функции для предикатов (box,point).

select cube_contains('(0,0),(1,1)', '0.5,0.5');
cube_contains
--------------
t
(1 row)

Примечания

Примеры использования можно увидеть в регрессионном тесте sql/cube.sql.

Во избежание некорректного применения этого типа, число размерностей кубов ограничено значением 100. Если вы хотите его увеличить, его можно изменить в cubedata.h.

Благодарности

Оригинальный автор: Джин Селков мл. (selkovjr@mcs.anl.gov), Аргоннская национальная лаборатория, Отдел математики и компьютерных наук.

Я благодарен в первую очередь профессору Джо Геллерштейну (https://dsf.berkeley.edu/jmh/) за пояснение сути GiST (http://gist.cs.berkeley.edu/) и его бывшему студенту, Энди Донгу, за пример, написанный для Illustra. Я также признателен всем разработчикам Postgres в настоящем и прошлом за возможность создать мой собственный мир и спокойно жить в нем. Еще я хотел бы выразить признательность Аргоннской лаборатории и Министерству энергетики США за годы постоянной поддержки моих исследований в области баз данных.

Небольшие изменения в этот пакет внес Бруно Вольф III (bruno@wolff.to) в августе/сентябре 2002 г. В том числе он перешел от одинарной к двойной точности и добавил несколько новых функций.

Дополнительные изменения внес Джошуа Рейх (josh@root.net) в июле 2006 г. В частности, он добавил cube(float8[], float8[]), подчистил код и перевел его на протокол вызовов версии V1 с устаревшего протокола V0.