LINUX.ORG.RU

Задача выборки по критериям


0

1

Здравствуйте. Есть интерестная задача: Нужно написать максимально быстрый алгоритм поиска по 10 000 000 обьектам состоящих из 4х полей:

0-100

0-1000000

0-200

0-200

Возможны запросы типа диапазона.

Использовать нужно интерпретируемый язык. Python\Ruby - не суть важно. Вопрос несколько концептуальный.

На текущий момент делаю так, для каждого поля есть хеш. Значениями которого являются массив id обьектов этого ключа. Если запрос без диапозонов - все работает практически мгновенно. Для диапазона дергаю все возможные значения. В конце, делаю обьединение всех массивов и получаю результат. Не уверен что это самый оптимальный алгоритм. Вопрос в том, как строить индекс по этому добру чтобы быстро бегать? Как оптимизировать запросы по диапозону? Что почитать?

Ответ на: комментарий от jerk-of-all-trades

Предполгагаем что имена полей следущие: a, b, c, d. Прототип функции: filter (85, [50000, 70000], 180, 70) На выходе должен быть массив или id обьектов или сами обекты.

Еще что-то?

libbkmz ()

Зачем тебе хеш, если требуется диапазоны? Тут твоя ошибка.

У тебя 4-ре ключа, для каждого строй дерево. Заведи числовой ID для каждой записи. Добейся что бы по запросу Fi(min,max) (i=1..4) выдавался отсортированный список ID записей, у которых i-ое поле в заданном диапазоне. Пересечение 4-х отсортированных списков, даст тебе нужный набор записей.

AlexVR ★★★★★ ()
Ответ на: комментарий от AlexVR

Я именно так и делаю. Но для диапозонов запрос выполняется под 10 сек. А если указатьв се поля лиапозонами, причем большими, за 10минут не завершился процесс.

Hash - это название Массива из руби. Из питона - Dict.

libbkmz ()
Ответ на: комментарий от crowbar

Решение нужно в обход БД. Нужно сделать чисто на ЯП. Без сторонних вещей

libbkmz ()
Ответ на: комментарий от AlexVR

Смотри, примерно по первому полю которое от 0-100. У меня ассоциативный массив, у которого ключи 0-100. Содержимое ключа 1 => [4,7,9,10,20,24.....10 000 000] У каждого поля примерно по 100, 1000000, 200, 200 записей соответсвенно. Тоесть, когда у меня запрос идет прямыми значениями, я делаю примерно следующее:

a[85] & b[60000] & c[180] & d[70]

И на выходе получаю массив, обычно не больше 1к элементов. Отрабатывает меньше чем за 100мс. Момент следующий, когда у меня диапозон, я делаю следующее (в упрощенном варианте):

a[85] & (b[50000] | b[50001] | b[50002] ... b[59999] | b[60000]) & c[180] & d[70]

Беда в том, что второе поле от 0 и до 1 ляма, и диапозоны могут выдавать огромные массивы. Все эти операции очень затратны по времени. Я не уверен что смогу сильно сэкономить, если заменю ассоциативный массив(Ruby Hash) на дерево поиска, или любое другое. Вытаскивание списка id обьектов удовлетворяющих одному условию - это не медленная задача. Задача Провернуть пересечение с обьединением на массивах содержаших миллионы значений - вот в чем моя текущая проблема.

Если строить дерево(можно хеш - не суть важно), то как его делать для нескольких ключей сразу? Если посчитать все возможные варианты для 4х полей 100*1000000*200*200 = 4e12. Т.е. 4триллиона возможных комбинаций. Но, так как обьектов всего 10миллионов, могут быть как повторяющиеся, так и не быть комбинаций вообще.

PS

& - пересечение массивов

| - обьединение массивов

libbkmz ()
Ответ на: комментарий от libbkmz

Сейчас только заметил, что у тебя маленькие диапазоны значений у полей. Используй для хранения списков ключей честные массивы (например, ndarray для Python), тогда время доступа к списку будет O(1).

Следующая задача - быстрое объединение списков. http://habrahabr.ru/post/63539/. Получишь 4-ре штуки

Далее ищи пересечение двух списков, но только правильно, а не через Ж*** как большинство решений в интернете

AlexVR ★★★★★ ()
Ответ на: комментарий от libbkmz

Иногда структуры с вертикальной иерархией вверху и горизонатально внизу (если можно так выразиться) бывают полезны. Что-то вроде unrolled linked list / rope / etc. Для второго индекса можно попробовать кучу, с литьями из 4к элементов.

anonymous ()

Посмотрел я тут, что по времени выполнения/потребления памяти получается. Это только на Си переписывать и выдавать интерфейсы для Python/Ruby.

В питоне ndarray и тот не спасает.

AlexVR ★★★★★ ()
Ответ на: комментарий от AlexVR

Именно. Я даже посчитал, если правильную структуру сварганить, то на 10лямов обьектов будет примерно 100мб потребление памяти, без индексов. А в рубях у меня под 3гига в среднем, что не кисло.

libbkmz ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.