Ефективно търсене на няколко низа в текстов файл

Използвам egrep, за да търся точни съвпадения на няколко низа в много дълъг файл (1 милион реда):

egrep "\<string1\>|<\string2\>" my_file

Но отнема твърде много време дори да се намерят само два низа. Изглежда, че търси всеки низ по общите редове на файла, дори когато намери среща. Наистина знам, че файлът съдържа само едно срещане на всеки низ. След това бих искал да знам как да накарам egrep да спре да търси низ, след като намери среща с него и да потърси следващия от списъка. Или ако има друг начин да направите това ефективно.

Благодаря.


person saloua    schedule 05.10.2012    source източник
comment
Колко струни искате да търсите? Шепа или нещо като няколко хиляди?   -  person Jo So    schedule 05.10.2012


Отговори (3)


Има -m опция, която ограничава броя на съвпаденията:

-m NUM, --max-count=NUM
     Stop reading a file after NUM matching lines.

Не можете обаче да го използвате директно с вашия сложен шаблон, защото тогава ще получите само 1 ред за всички подмодели. Това, което можете да направите, е да преминете през вашите подмодели, извиквайки fgrep -m 1:

for pat in $patterns; do
    fgrep -m 1 $pat my_file
done

P.S. Друг вариант е да използвате сложния шаблон, както правите, и да посочите броя на съвпаденията, равен на броя на подмоделите, но това ще доведе до по-бавно сравнение за всеки файлов ред.

person Lev Levitsky    schedule 05.10.2012
comment
Благодаря за вашият отговор. Получих го с --max-count=NUM - person saloua; 05.10.2012
comment
Настрана: Като се има предвид, че OP знае, че всеки низ се появява най-много веднъж на файл, средното ускоряване от --max-count=1 е само 200%. - person Jo So; 05.10.2012
comment
Мисля, че сложният модел със съвпадения, равен на брой подмодели, всъщност ще бъде най-бърз; вижте отговора ми за обяснение. - person Gordon Davisson; 06.10.2012

Как трябва да оптимизирате търсенето зависи от това какъв алгоритъм използва вашата реализация на grep. „Традиционният“ алгоритъм за egrep е да компилира модела в детерминиран краен автомат. Ако не знаете какво е това, не се притеснявайте: важното е, че компилирането отнема малко време, но след като това стане, става доста бързо и скоростта му не зависи от сложността на модела, който търси за. Всъщност, след като компилацията е направена, egrep всъщност е по-бърз от fgrep -- което означава, че fgrep е най-бърз при малки файлове, egrep е най-бърз при големи файлове.

Поне това е ситуацията за традиционните реализации на [ef]grep. Мисля, че повечето съвременни реализации са адаптивни и ще превключват алгоритмите в зависимост от ситуацията (напр. Мисля, че съвременните fgreps ще превключват в режим на компилиран DFA за достатъчно големи файлове). За да разберете кое е най-бързото за вашето внедряване(ия), наистина трябва да опитате някои времеви експерименти.

Мога обаче да ви дам няколко препоръки: Първо, избягвайте да изпълнявате търсенето повече от веднъж (напр. да изпълнявате fgrep за всяка дума), защото това ще означава сканиране на файла многократно. Второ, не се притеснявайте да минимизирате броя низове, които търси, защото ако сте в най-добрия възможен режим, това така или иначе няма да има значение. Трето, използвайте предложението на @Lev за -m, за да го накарате да спре, след като намери това, от което се нуждае (въпреки че съм почти сигурен, че това ще бъде единично търсене и за двете думи с -m2).

person Gordon Davisson    schedule 06.10.2012
comment
Много хубав отговор, благодаря. Най-накрая ме накара да отида и да потърся DFA :) - person Lev Levitsky; 06.10.2012

Не съм сигурен, но може би този е по-бърз:

grep -e '<pattern1>' -e '<pattern2>' -e '<pattern3>' your_file

-F също може да ускори нещата, мисля, че вашите модели всъщност не са модели. Освен това мисля, че ако изходът ви е оцветен, grep няма друг избор освен да търси всички модели.

person Michael Krelin - hacker    schedule 05.10.2012
comment
Замених шаблона на думата с низ, така е по-добре :) Трябва да използвам egrep, защото избягвам циклично изхвърляне на масива, съдържащ търсените низове. След това просто използвам разширението на параметъра, за да получа тогава, както съм написал. И накрая използвайте egrep, за да намерите тези. - person saloua; 05.10.2012
comment
Все още не съм сигурен защо ви трябва egrep. С какво е по-добър от grep -F -e 'string1' -e 'string2' -e 'string3' your_file. Опитахте ли го, BTW? - person Michael Krelin - hacker; 05.10.2012
comment
И да, както предлага Лев, добавянето на -m 2 към този команден ред също трябва да подобри нещата, отначало не разбрах, че имате само един съответстващ ред за всеки шаблон, а не само един шаблон на ред. - person Michael Krelin - hacker; 05.10.2012