Подтвердить что ты не робот

Быстрый поиск по строкам

У меня есть проблема, что я ищу некоторые рекомендации для решения наиболее эффективного способа. У меня 200 миллионов строк данных размером от 3 до 70 символов. Строки состоят из букв и нескольких специальных символов, таких как тире и символы подчеркивания. Мне нужно иметь возможность быстро искать всю строку или любую подстроку в строке (минимальный размер подстроки - 3). Быстро определяется здесь менее 1 секунды.

В качестве первого разреза я сделал следующее:

  • Создано 38 индексных файлов. Индекс содержит все подстроки, начинающиеся с определенной буквы. Первый 4mb содержит 1 миллион хэш-кодов (начало хэш-цепочек). Остальная часть индекса содержит связанные цепочки списков из хэш-кодов. Мое хеширование очень равномерно распределено. 1 миллион хэш-кодов хранится в ОЗУ и зеркалируется на диск.

  • Когда строка добавляется в индекс, она разбивается на ее не дублирующиеся (внутри себя) 3-значные подстроки символов (когда n - длина строки-1). Так, например, "яблоки" хранятся в индексе "А" как pples, pple, ppl, pp (подстроки также хранятся в индексах "L" и "P" ).

Сервер поиска/добавления работает как демон (на С++) и работает как чемпион. Обычное время поиска меньше 1/2 секунды.

Проблема заключается в начале процесса. Обычно я добавляю 30 000 ключей за раз. Эта часть процесса берет навсегда. В качестве эталона время загрузки в пустой индекс 180 000 ключей переменной длины составляет приблизительно 3 1/2 часа.

Эта схема работает, за исключением очень длительного времени загрузки.

Прежде чем перейти к оптимизации ореолов (или попытке), мне интересно, есть ли лучший способ решить эту проблему. Внешний и задний подстановочные запросы (т.е. Строка типа "% ppl%" в СУБД удивительно медленна (например, в часах в MySQL) для наборов данных, таких больших. Таким образом, казалось бы, что решения СУБД не могут быть и речи. Я не могу использовать полнотекстовый поиск, потому что мы не имеем дело с нормальными словами, но строками, которые могут содержать или не состоять из реальных слов.

4b9b3361

Ответ 1

Из вашего описания загрузка данных занимает все это время, потому что вы имеете дело с I/O, зеркалируя надутые строки на жесткий диск. Это, безусловно, будет узким местом, в основном в зависимости от способа чтения и записи данных на диск.

Возможное улучшение времени выполнения может быть достигнуто с помощью mmap с некоторой политикой LRU. Я уверен, что идея репликации данных состоит в том, чтобы ускорить поиск, но поскольку вы используете - как кажется, - только одна машина, вы узкое место погрузитесь из памяти в поисках ввода-вывода запросы.

Другое решение, которое вас может не интересовать - это также смешно и тревожно (: -, - это разделение данных между несколькими машинами. Учитывая то, как вы структурировали данные, сама реализация может возьмите немного времени, но это будет очень просто. У вас будет:

  • каждая машина получает ответственность за набор ведер, выбранных с использованием чего-то близкого к hash_id(bucket) % num_machines;
  • вставки выполняются локально, с каждой машины;
  • поиск может быть сопряжен каким-либо типом вашего запроса-приложения или просто сгруппирован в группы запросов - если приложение не является взаимным;
  • может даже распространяться интерфейс, учитывая, что вы можете отправить запрос от node и перенаправить запросы на другой node (также кластерные запросы, чтобы избежать чрезмерных затрат ввода-вывода).

Еще один хороший момент в том, что, как вы сказали, данные распределены равномерно - УЖЕ \o/; это, как правило, одна из самых сложных частей распределенной реализации. Кроме того, это будет очень масштабируемо, так как вы можете добавить другую машину всякий раз, когда данные растут по размеру.

Ответ 2

Вместо того, чтобы делать все за один проход, решите проблему в 38 проходов.

Прочитайте каждую из 180 000 строк. Найдите "A" в каждой строке и выпишите материал только в хэш-таблицу "A" . После того, как вы закончите, напишите весь готовый результат хэш-таблицы "A" на диск. (у вас достаточно ОЗУ для хранения всей хэш-таблицы A в памяти - если вы этого не сделаете, сделайте меньше хэш-таблиц. То есть, есть 38 ^ 2 хэш-таблицы по парам начальных букв и имеют 1444 разных таблиц. даже динамически изменять количество букв, из которых сделаны хэш-таблицы, основаны на том, насколько распространенным является их префикс, поэтому они имеют скромный размер. Отслеживание того, как долго такие префиксы не стоят дорого.)

Затем прочитайте каждую из 180 000 строк, ища "B". Etc.

Моя теория заключается в том, что вы делаете медленнее, чем вы могли, из-за того, что вы обманули свой кеш из ваших массивных таблиц.

Следующее, что может помочь, - ограничить, сколько строк вы используете для хэша, чтобы уменьшить размер ваших таблиц.

Вместо того, чтобы делать все 2278 подстроки длиной от 3 до 70 строки длиной 70, если вы ограничили длину хэша на 10 символов, то есть только 508 подстрок длиной от 3 до 10. И может быть не так много столкновений по строкам длиной более 10. Вы могли бы снова иметь длину хэшей динамической - длина х хеша может иметь флаг для "попробуйте хэш X + Y длины, если ваша строка длиннее X, это слишком часто", и в противном случае просто прекращает хеширование. Это может уменьшить количество данных в ваших таблицах за счет более медленного поиска в некоторых случаях.