grep но индексируемый? - PullRequest
       14

grep но индексируемый?

14 голосов
/ 12 октября 2011

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

Есть ли утилита командной строки, похожая на grep, которая имеет возможность индексирования?

Ответы [ 7 ]

9 голосов
/ 11 августа 2012

Решения, приведенные ниже, довольно просты.Есть много угловых случаев, которые они не охватывают:

  • поиск начала строки ^
  • имена файлов, содержащие \ n или: не удастся
  • имена файлов, содержащиепробел не удастся (хотя это можно исправить с помощью GNU Parallel вместо xargs)
  • поиск строки, совпадающей с путем к другим файлам, будет неоптимальным

Хорошая частьРешения заключаются в том, что они очень просты в реализации.

Решение 1: один большой файл

Факт: поиск очень медленный, чтение одного большого файла часто быстрее.

Учитывая эти факты, идея состоит в том, чтобы просто создать индекс, содержащий все файлы со всем их содержимым - каждая строка с добавлением имени файла и номера строки:

Индексировать каталог:

find . -type f -print0 | xargs -0 grep -Han . > .index

Используйте индекс:

grep foo .index

Решение 2: один большой сжатый файл

Факт: жесткие диски работают медленно.Ищу очень медленно.Многоядерные процессоры нормальны.

Так что может быть быстрее прочитать сжатый файл и распаковать его на лету, чем читать несжатый файл - особенно если у вас достаточно оперативной памяти для кэширования сжатого файла, но недостаточно длянесжатый файл.

Index a dir:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

Используйте индекс:

pbzcat .index | grep foo

Решение 3: используйте индекс для поиска потенциальных кандидатов

Создание индекса может занять много времени, и вам может не потребоваться делать это для каждого отдельного изменения в каталоге.

Чтобы ускорить это, используйте индекс только для определения имен файлов, которые могут совпадать исделать реальный grep через эти (мы надеемся, ограниченное количество) файлов.Это обнаружит файлы, которые больше не совпадают, но не обнаружит новые файлы, которые соответствуют.

sort -u необходим, чтобы избежать многократного поиска одного и того же файла.

Index a dir:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

Используйте индекс:

pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo

Решение 4: добавьте к индексу

Повторное создание полного индекса может бытьочень медленно.Если большая часть директории остается прежней, вы можете просто добавить в индекс новые измененные файлы.Индекс снова будет использоваться только для поиска потенциальных кандидатов, поэтому, если файл больше не соответствует, он будет обнаружен при просмотре текущего файла.

Индекс в каталоге:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

Добавитьк индексу:

find . -type f -newer .index -print0 | xargs -0 grep -Han . | pbzip2 >> .index

Используйте индекс:

pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo

Это может быть даже быстрее, если вы используете pzstd вместо pbzip2 / pbzcat.

Решение 5: используйте git

git grep может выполнить поиск в репозитории git.Но он, похоже, выполняет много операций поиска и в 4 раза медленнее в моей системе, чем решение 4.

Хорошая часть заключается в том, что индекс .git меньше, чем .index.bz2.

Index a dir:

git init
git add .

Добавить к индексу:

git add .

Использовать индекс:

git grep foo

Решение 6: оптимизировать git

Git помещает свои данные во множество небольших файлов.Это приводит к поиску.Но вы можете попросить git сжать маленькие файлы в несколько больших файлов:

git gc --aggressive

Это занимает некоторое время, но очень эффективно упаковывает индекс в несколько файлов.

Теперь вы можетеdo:

find .git  -type f | xargs cat >/dev/null
git grep foo

git будет много искать в индексе, но, выполнив сначала cat, вы поместите весь индекс в ОЗУ.

Добавление в индексаналогично решению 5, но время от времени запускайте git gc, чтобы избежать большого количества маленьких файлов, и git gc --aggressive, чтобы сэкономить больше места на диске, когда система простаивает.

git не освобождаетместо на диске, если вы удалите файлы.Поэтому, если вы удаляете большие объемы данных, удалите .git и снова выполните git init; git add ..

3 голосов
/ 13 января 2016

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

Не обращаясь к части способности индексирования, Git grep будет иметь с Git 2.8 (Q1 2016) возможность работать параллельно!

См. commit 89f09dd , коммит 044b1f3 , коммит b6b468b (15 декабря 2015 г.) Виктор Лещук (vleschuk) .
(объединено Junio ​​C Hamano - gitster - в commit bdd1cc2 , 12 января 2016 г.)

grep: добавьте --threads=<num> option и grep.threads configuration

"git grep" теперь можно настроить (или указать из командной строки), сколько потоков использовать при поиске в файлах рабочего дерева.

grep.threads:

Количество grep рабочих потоков для использования.

3 голосов
/ 22 августа 2013

Существует проект https://code.google.com/p/codesearch/, который способен создавать индекс и выполнять быстрый поиск в индексе. Регулярные выражения поддерживаются и вычисляются с использованием индекса (на самом деле, только подмножество регулярных выражений может использовать индекс для фильтрации набора файлов, а затем реальное регулярное выражение переоценивается для сопоставленных файлов).

Индекс из codesearch обычно составляет 10-20% от размера исходного кода, построение индекса происходит быстро, как при запуске классического grep 2 или 3 раза, а поиск почти мгновенный.

Идеи, использованные в проекте поиска кода, взяты с сайта Google Code Search (RIP). Например. индекс содержит карту от n-граммов (3-граммы или каждый 3-байтовый набор, найденный в ваших источниках) до файлов; и регулярное выражение переводится в 4 грамма при поиске.

PS А в источниках C / C ++ есть ctags и cscope для навигации. Ctags может найти объявления / определения, cscope более эффективен, но имеет проблемы с C ++.

PPS, а также есть инструменты на основе clang для языков C / C ++ / ObjC: http://blog.wuwon.id.au/2011/10/vim-plugin-for-navigating-c-with.html и clang-complete

1 голос
/ 17 апреля 2019

Мы используем инструмент для индексации очень больших файлов журналов и эффективного поиска в них.Это было с открытым исходным кодом.Я не знаю, насколько хорошо он масштабируется до большого количества файлов.По умолчанию он многопоточен, он ищет внутри сжатых файлов и кэширует индексы ранее найденных файлов.

https://github.com/purestorage/4grep

1 голос
/ 22 августа 2013

ack - это инструмент поиска кода, который оптимизирован для программистов, особенно для программистов, работающих с большими деревьями разнородного исходного кода: http://beyondgrep.com/

Это некоторые из ваших примеров поиска, где вы хотите искать только определенный типфайл, как только файлы Java?Тогда вы можете сделать

ack --java function

ack не индексирует исходный код, но это может не иметь значения в зависимости от того, на что похожи ваши шаблоны поиска.Во многих случаях только поиск определенных типов файлов дает необходимое ускорение, потому что вы также не ищете все эти другие файлы XML и т. Д.

И если ack не делает это за вас, здесьсписок инструментов, предназначенных для поиска исходного кода: http://beyondgrep.com/more-tools/

0 голосов
/ 22 августа 2015

Поскольку вы упоминаете различные виды текстовых файлов, которые на самом деле не являются кодом, я предлагаю вам взглянуть на GNU ID utils .Например:

cd /tmp
# create index file named 'ID'
mkid -m /dev/null  -d text /var/log/messages.*
# query index
gid -r 'spamd|kernel'

Эти инструменты ориентированы на токены, поэтому запросы к строкам токенов невозможны.В emacs есть минимальная интеграция для команды gid.

Для более конкретного случая индексации исходного кода я предпочитаю использовать GNU global , который я считаю более гибким.Например:

cd sourcedir
# index source tree
gtags .
# look for a definition
global -x main
# look for a reference
global -xr printf
# look for another kind of symbol
global -xs argc

Global изначально поддерживает C / C ++ и Java, и с небольшим количеством настроек может быть расширен для поддержки многих других языков.Он также имеет очень хорошую интеграцию с emacs: последовательные запросы суммируются, а обновление исходного файла эффективно обновляет индекс.Однако я не знаю, что он может индексировать обычный текст (пока).

0 голосов
/ 12 октября 2011

Эта статья grep-cache содержит скрипт для кэширования результатов grep. Его примеры запускались на windows с установленными инструментами linux, поэтому его легко можно использовать на nix / mac с небольшими изменениями. В любом случае, это в основном просто скрипт на Perl.

Кроме того, сама файловая система (при условии, что вы используете * nix) часто кэширует недавно прочитанные данные, что приводит к ускорению будущего времени grep, поскольку grep эффективно выполняет поиск в виртуальной памяти вместо диска.

Кэш обычно находится в /proc/sys/vm/drop_caches, если вы хотите стереть его вручную, чтобы увидеть увеличение скорости от некэшированного до кэшированного grep.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...