- PVSM.RU - https://www.pvsm.ru -

Потребность в пространственном поиске возникает довольно часто. Равно как и в пространственном JOIN’е — нахождении пересечения двух наборов пространственных объектов. Далеко не всегда хочется привлекать тяжелую артиллерию. Что ж, попробуем придумать способ решить проблему “малой кровью, могучим ударом”.
Известно, что индексирование более чем одномерных объектов представляет собой существенную проблему, хотя, потребность в этом достаточно велика. Возникающие трудности носят объективный характер т.к. что бы мы ни делали, файл индекса на физическом носителе последователен (одномерен) и мы обязаны предоставить некоторый порядок обхода плоскости (пространства). При этом есть интуитивное желание расположить близкие в пространстве точки не очень далеко и в индексном файле. К сожалению, без разрывов это невозможно.
Отношение к пространственному индексированию в GIS сообществе вообще двоякое. С одной стороны, изрядное количество членов данного сообщества уверено, что проблемы то никакой и нет, случись такая необходимость, они справились бы с ней на два счета. А с другой стороны, есть мнение, что “все уже украдено до нас”, большинство современных СУБД как-то умеют решать данную проблему, некоторые довольно давно и, в целом, успешно.
Как это часто бывает, то, что мы не видим суслика, не означает, что его нет. Как только объемы данных существенно вырастают, обнаруживается, что само построение пространственного индекса может представлять проблему т.к. либо алгоритм выходит за рамки определения, либо время построения становится неприемлемо большим, либо поиск неэффективным … Как только пространственные данные начинают интенсивно меняться, пространственный индекс может начать деградировать. Перестройка индекса помогает, но ненадолго.
Здесь мы рассмотрим самый простой случай индексации пространственных данных — работу с точечными объектами. Будем использовать честное кодирование координат с помощью заметающей кривой. Конечно, есть и другие методы, pixel-block индексы, R-деревья, квадродеревья, на худой конец. Возможно, это тема для другой статьи, но сейчас мы описываем именно работу с точечными объектами именно с помощью заметающей кривой.
Не будем утверждать, что предложенный метод идеален, но у него как минимум два достоинства — он очень прост и весьма эффективен. С его помощью буквально «на коленке» можно решать вполне серьезные задачи.
В качестве данных возьмем звездный атлас и его имитации случайными числами. Каждый набор данных состоит из некоторого числа объектов, каждый из которых описывается:
Наборов данных у нас несколько:
Идея заметающей кривой заключается в том, чтобы пронумеровать дискретное пространство. Пространственный объект представляется точкой в N-мерном пространстве. Точка на плоскости представляет сама себя, прямоугольный экстент, описывающий плоскую фигуру — это 4-мерная точка etc. Такая точка – число фиксированной длины, с которым довольно просто иметь дело. В частности, такое число можно поместить в обычное B-дерево. Поисковый запрос разбивается на непрерывные отрезки заметающей кривой и для каждого отрезка выполняется подзапрос. Все точки, попавшие в интервалы подзапросов – искомые.
Таким образом, нам нужна кривая, которая посетит каждую точку нашего (двумерного в данном случае) дискретного пространства. Какие возможны варианты?

В отличие от Z-order’а, данная кривая обладает непрерывностью, что позволяет осуществлять поиск чуть эффективнее, значительным недостатком является относительно высокая стоимость вычисления координат из значения и наоборот.
Третий вариант с самоподобием 2Х2: X-образная кривая пересекает сама себя и автор не знает прецедента ее использования для пространственной индексации.
Известны также, кривая Мура [2]– аналог кривой Гильберта, кривая Серпинского [3], кривая Госпера [4], …

Таким образом получаем блоки 8Х8 со строчной разверткой внутри, которые сами образуют между собой строчную развертку.
Но это для демонстрации принципа. Для индексации будем делать блоки по 17 бит. Если интересует, почему 17, об этом позже.
| Dataset | Disk Size (Кb) | Build Time | MEM size (Mb) |
|---|---|---|---|
| 55M | 211,250 | 6’45’’ | 40 |
| 526M | 1,767,152 | 125’ | 85 |
| USNO-SA2.0 | 376,368 | 4’38’’ | 40 |
| USNO-A2.0 | 3,150,000 | 125’ | 85 |
Где:
В нижеследующих таблицах приведены значения, характерные для запросов на построенном индексе. Приведены суммарные значения для 100,000 поисков по случайно выбранным (в заселенной области, конечно) квадратным экстентам.
| Extent Size | Time (sec) | NObj | RDisk | σ(RDisk) |
|---|---|---|---|---|
| 2x2 | 58 | 23 | 118,435 | 0.39 |
| 4x4 | 59 | 100 | 118,555 | 0.39 |
| 10x10 | 59 | 600 | 118,918 | 0.4 |
| 20x20 | 60 | 2,622 | 119,221 | 0.4 |
| 120x120 | 62 | 89,032 | 123,575 | 0.45 |
| 1200x1200 | 98 | 8,850,098 | 174,846 | 0.82 |
| 7200x7200 | 408 | 318,664,063 | 567,137 | 1.3 |
Где:
| Extent Size | Time (sec) | NObj | RDisk |
|---|---|---|---|
| 2x2 | 738 | 110 | 185,672 |
| 4x4 | 741 | 445 | 185,734 |
| 10x10 | 730 | 2,903 | 186,560 |
| 20x20 | 774 | 11,615 | 187,190 |
| 120x120 | 800 | 421,264 | 196,080 |
| 1200x1200 | 1200 | 42,064,224 | 307,904 |
| 7200x7200 | 3599 | 1,514,471,480 | 1,442,489 |
Где колонки аналогичны 55M.
Обращает на себя внимание, что, в то время, как число обращений к диску изменилось незначительно (на треть), время выполнения запросов выросло более чем в 10 раз – результат отсутствия эффективного кэширования файла индекса операционной системой.
| Extent Size | Time (sec) | NObj | RDisk | σ(RDisk) |
|---|---|---|---|---|
| 2x2 | 48 | 28 | 143,582 | 0.5 |
| 4x4 | 50 | 115 | 143,887 | 0.5 |
| 10x10 | 45 | 657 | 144,085 | 0.5 |
| 20x20 | 45 | 2,585 | 144,748 | 0.51 |
| 120x120 | 47 | 94,963 | 151,223 | 0.56 |
| 1200x1200 | 80 | 9,506,746 | 224,016 | 0.97 |
| 7200x7200 | 387 | 345,165,845 | 842,853 | 2.97 |
Где колонки аналогичны 55M
| Extent Size | Time (sec) | NObj | RDisk | σ(RDisk) |
|---|---|---|---|---|
| 2x2 | ~600 | ~130 | ~200,200 | ~0.4 |
| 4x4 | ~600 | ~500 | ~200,200 | ~0.4 |
| 10x10 | ~600 | ~3,000 | ~200,200 | ~0.4 |
| 20x20 | ~600 | ~12,000 | ~200,200 | ~0.4 |
| 120x120 | ~600 | ~450,000 | ~250,200 | ~0.5 |
| 1200x1200 | ~1,000 | ~45,000,000 | ~300,200 | ~1.4 |
| 7200x7200 | ~3500 | ~1,600,000,000 | ~1,500,200 | ~2.0 |
Где колонки аналогичны 526M
В нижеследующих таблицах приведены значения, характерные для join’ов индексов. Под join’ом мы понимаем поиск всех объектов, расположенных в пределах некоторого экстента. Например, если параметром запроса является 0.25 arc second, то для каждого элемента из одного индекса будет выполнен поиск во втором индексе с экстентом +- 0.25, т.е. квадрат со сторонами 0.5x0.5 arc second и центром в референтной точке.
| Extent Size | Time (sec) | NObj |
|---|---|---|
| 0.5x0.5 | 175 | 2 |
| 2x2 | 191 | 410 |
| 6x6 | 212 | 4,412 |
Где:
| Extent Size | Time (sec) | NObj |
|---|---|---|
| 0.5x0.5 | 150 | 925 |
| 2x2 | 165 | 13,815 |
| 6x6 | 181 | 122,295 |
Где колонки аналогичны USNO-SA2.0 vs USNO-SA2.0.
| Extent Size | Time (sec) | NObj |
|---|---|---|
| 0.5x0.5 | 1601 | 0 |
| 2x2 | 1813 | 916 |
| 6x6 | 2180 | 9943 |
Где колонки аналогичны USNO-SA2.0 vs USNO-SA2.0.
Для начала отметим важные моменты:
Итак, попробуем понять как устроены данные.
Так как же всё-таки осуществляется поиск?
Даже немного обидно, до чего всё просто.
Описанная работа проводилась в 2004 году в соавторстве с Александром Артюшиным из замечательной компании DataEast [5]. На тот момент автор и сам был сотрудником этой компании и, да, публикация осуществляется с их согласия, спасибо Евгению Моисееву emoiseev [6].
Железо в те времена было не чета нынешнему, но принципиальные моменты не изменились.
Автор: zzeng
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/38776
Ссылки в тексте:
[1] ftp://ftp.nofs.navy.mil: https://www.pvsm.ruftp://ftp.nofs.navy.mil
[2] Мура : http://en.wikipedia.org/wiki/Moore_curve
[3] Серпинского: http://en.wikipedia.org/wiki/Sierpi%C5%84ski_curve
[4] Госпера: http://en.wikipedia.org/wiki/Gosper_curve
[5] DataEast: http://www.dataeast.ru/
[6] emoiseev: http://habrahabr.ru/users/emoiseev/
[7] Источник: http://habrahabr.ru/post/186564/
Нажмите здесь для печати.