Быстрый поиск по списку wildcard-правил
От: okman Беларусь https://searchinform.ru/
Дата: 07.07.17 08:17
Оценка:
Привет!

Подскажите, пожалуйста, хороший (т.е. эффективный в плане скорости) алгоритм для следующей задачи.

На вход функции подается текстовая строка. Нужно проверить, совпадает ли она по маске с
хотя бы одной строкой из списка правил. Каждое правило — это текстовая строка, которая может
содержать wildcard-символ *. Приведу пример:

Ввод: /path/hello.txt
Правила: *.pdf;*.txt;*someapp*;*path*/*ello*

(здесь будут совпадения по *.txt и по *path*/*ello*)

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

Список правил формируется динамически, во время работы программы, поэтому строить из него
какую-то предкомпилированную модель нельзя. Также нельзя использовать средства с динамической
генерацией кода (JIT и т.п.) — такие ограничения среды.

Хочется найти не столько реализацию (C/C++), сколько описание самого алгоритма.

Спасибо!
Re: Быстрый поиск по списку wildcard-правил
От: wildwind Россия  
Дата: 07.07.17 11:45
Оценка: 1 (1) +2
Здравствуйте, okman, Вы писали:

O>Список правил формируется динамически, во время работы программы, поэтому строить из него

O>какую-то предкомпилированную модель нельзя. Также нельзя использовать средства с динамической
O>генерацией кода (JIT и т.п.) — такие ограничения среды.

При таких ограничениях быстро не будет ИМХО.

Можно поддерживать три структуры: префиксное дерево, суффиксное дерево и список шаблонов вида *someapp*. Проверяем сначала по префиксам/суффиксам, затем по остальной части шаблона.
Re: Быстрый поиск по списку wildcard-правил
От: α Российская Империя  
Дата: 07.07.17 12:10
Оценка:
Здравствуйте, okman, Вы писали:

O>(здесь будут совпадения по *.txt и по *path*/*ello*)


Из теории БД известно, что выражение like '%что-то%' сразу делает индексы неэффективными и приводит к полному скану таблицы
Если бы можно было упростить задачу запретив использовать паттерны в начале и/или конце строки, тогда какое-то готовое эффективное алгоритмическое решение можно будет прикрутить
Re[2]: Быстрый поиск по списку wildcard-правил
От: Слава  
Дата: 07.07.17 12:48
Оценка:
Здравствуйте, α, Вы писали:

α>Из теории БД известно, что выражение like '%что-то%' сразу делает индексы неэффективными и приводит к полному скану таблицы


И что, даже триграммный поиск не помогает?
Re[2]: Быстрый поиск по списку wildcard-правил
От: wildwind Россия  
Дата: 07.07.17 16:23
Оценка: +1
Здравствуйте, α, Вы писали:

α>Из теории БД известно, что выражение like '%что-то%' сразу делает индексы неэффективными


Это смотря какие индексы. Другое дело, что в данной задаче индекс не построить, т.к. набор входных данных заранее не известен.
Re: Быстрый поиск по списку wildcard-правил
От: SergH Россия  
Дата: 07.07.17 22:03
Оценка:
Здравствуйте, okman, Вы писали:

O>Подскажите, пожалуйста, хороший (т.е. эффективный в плане скорости) алгоритм для следующей задачи.


O>На вход функции подается текстовая строка. Нужно проверить, совпадает ли она по маске с

O>хотя бы одной строкой из списка правил. Каждое правило — это текстовая строка, которая может
O>содержать wildcard-символ *. Приведу пример:

O>Ввод: /path/hello.txt

O>Правила: *.pdf;*.txt;*someapp*;*path*/*ello*

O>(здесь будут совпадения по *.txt и по *path*/*ello*)


O>Предполагаем, что такие проверки выполняются много-много раз в секунду, а сам список правил

O>содержит тысячи и даже миллионы элементов. Хотелось бы не проходить по всему списку, а
O>использовать что-то вроде двоичного поиска.

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

Но получится ли сделать его вменяемым я не уверен.
Я когда-то писал статью про такие автоматы http://rsdn.org/article/alg/nka.xml
Автор(ы): Сергей Холодилов
Дата: 30.07.2007
В статье описан маленький, но всё равно интересный кусочек теории вычислений. Предназначение статьи – послужить наживкой, заглотив которую, читатели уже сами продолжат изучение этой теории.
Делай что должно, и будь что будет
Re: Быстрый поиск по списку wildcard-правил
От: bzig  
Дата: 09.07.17 17:27
Оценка: 11 (2)
O> Хотелось бы не проходить по всему списку, а использовать что-то вроде двоичного поиска.

O>Список правил формируется динамически, во время работы программы, поэтому строить из него

O>какую-то предкомпилированную модель нельзя.

Посчитать частоту константных символов в каждом правиле, на основе этой частоты простроить дерево поиска — так ты будешь уменьшать количество правил, а там уже перебором проверять.

Этот способ, конечно, работает для не очень длинных строк — чем длиннее и разнообразнее строка, тем больше правил будут подходить по частоте константных символов. Зато к обновлению правил очень дружественый.
Re: Быстрый поиск по списку wildcard-правил
От: sergey2b ЮАР  
Дата: 14.07.17 19:42
Оценка:
Здравствуйте, okman, Вы писали:

aho corasick
Re: Быстрый поиск по списку wildcard-правил
От: Тёмчик Австралия жж
Дата: 09.08.17 02:39
Оценка:
Здравствуйте, okman, Вы писали:

O>На вход функции подается текстовая строка. Нужно проверить, совпадает ли она по маске с

O>хотя бы одной строкой из списка правил. Каждое правило — это текстовая строка, которая может
O>содержать wildcard-символ *. Приведу пример:

O>Предполагаем, что такие проверки выполняются много-много раз в секунду, а сам список правил

O>содержит тысячи и даже миллионы элементов. Хотелось бы не проходить по всему списку, а
O>использовать что-то вроде двоичного поиска.

Делал почти такое недавно, там надо наиболее подходящее одно правило выбрать и списка подходящих, и само правило уже задано регуляркой. Нагрузка- десятки правил, проверка ну скажем 10 в секунду. Сделал с модифицированной регуляркой и перебором.
Тебе действительно нужен мега- FSA один на все правила, а у меня было сделано по отдельному автомату на правило. Если разберешься- выложи здесь. Мне тоже интересно.

В принципе, wildcard- это существенное упрощение задачи. Сделать типа суффиксного дерева, в узлах прицепить ключик и хранить в каком-то виде данные мемоизации (как копия массива на поток исполнения, а ее представление описано твоим суффиксным деревом).
Re: Быстрый поиск по списку wildcard-правил
От: mikadi Россия  
Дата: 09.08.17 12:20
Оценка:
Здравствуйте, okman, Вы писали:

O>Список правил формируется динамически, во время работы программы, поэтому строить из него

O>какую-то предкомпилированную модель нельзя.

А почему нельзя? Можно же при модификации/добавлении правила сразу модифицировать вспомогательную структуру данных, разве нет?
Если могут быть только джокеры ('*'), а не полноценная регулярка, то может сработать такой вариант: каждое правило вида *Строка1*Строка2*Строка3* представляем в виде массива [Строка1, Строка2, Строка3]. Т.е. разбиваем по джокерам. Отдельно рядом с массивом храним признак наличия джокера в начале и в конце шаблона. Все такие фрагменты (строки без джокеров) из всех шаблонов складываем в одну структуру типа суффиксного дерева (сохраняя при этом информацию, в какие шаблоны входит каждая строка). Далее:
    Входную строку прогоняем по суффиксному дереву и определяем, какие фрагменты каких шаблонов там есть.
    Отбираем шаблоны, для которых в строке присутствуют все фрагменты
    Смотрим, есть ли шаблон(ы), для которых строки присутствуют в нужном порядке.
Шаги 2 и 3 уже работают с небольшим объёмом данных, по идее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.