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.