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 имеются обычные операторы сравнения, показанные в таблице Операторы сравнения. Эти операторы сначала сравнивают первые координаты, и если они равны, сравнивают вторые и т. д. Они предназначены в основном для поддержки класса операторов индекса В-дерева для типа 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.


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

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

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

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

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