Самый быстрый подход к поиску в содержимом файла каталога

У меня есть каталог, содержащий файлы для пользователей программы, которые у меня есть. В этом каталоге содержится около 70 тыс. Json-файлов.

Текущий метод поиска использует glob и foreach . Он становится довольно медленным и запугивает сервер. Есть ли хороший способ более эффективно искать эти файлы? Я запускаю это на машине Ubuntu 16.04, и я могу использовать exec если это необходимо.

Обновить:

Тезисы – это json-файлы, и каждый файл нужно открыть, чтобы проверить, содержит ли он поисковый запрос или нет. Зацикливание файлов происходит довольно быстро, но когда нужно открыть каждый файл, это займет довольно много времени.

Они не могут быть проиндексированы с использованием SQL или memcached, поскольку я использую memcached для некоторых других вещей.

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

Я говорю: выходите за пределы grep и смотрите, что еще лучше, чем ack . Кроме того, см. ag а затем ripgrep на ripgrep поскольку это лучший в своем роде в городе.


эксперимент

Я немного экспериментировал с ack на ноутбуке с низким удельным весом. Я искал имя существующего класса в 19 512 файлах. Вот результаты:

 $ cd ~/Dev/php/packages $ ack -f | wc -l 19501 $ time ack PHPUnitSeleniumTestCase | wc -l 10 ack PHPUnitSeleniumTestCase 7.68s user 2.99s system 21% cpu 48.832 total wc -l 0.00s user 0.00s system 0% cpu 48.822 total 

Я сделал тот же эксперимент, на этот раз с ag . И это меня действительно удивило:

 $ time ag PHPUnitSeleniumTestCase | wc -l 10 ag PHPUnitSeleniumTestCase 0.24s user 0.98s system 13% cpu 9.379 total wc -l 0.00s user 0.00s system 0% cpu 9.378 total 

Я был так взволнован результатами, я продолжил и попробовал ripgrep . Даже лучше:

 $ time rg PHPUnitSeleniumTestCase | wc -l 10 rg PHPUnitSeleniumTestCase 0.44s user 0.27s system 19% cpu 3.559 total wc -l 0.00s user 0.00s system 0% cpu 3.558 total 

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


Оригинальный автор PS ripgrep оставил комментарий в этом сообщении, сказав, что ripgrep быстрее, чем {grep, ag, git grep, ucg, pt, sift} . Интересная прочитанная, потрясающая работа.

В зависимости от того, используете ли вы SSD или HDD для хранения ответов на файлы, они отличаются.

жесткий диск

В случае с HDD наиболее вероятным узким местом является не PHP, но может работать небольшое количество операций ввода-вывода. Я бы настоятельно рекомендовал перейти на SSD или использовать RAM-диск, если это возможно.

Предположим, вы не можете переместить каталог на SSD. Это означает, что вы застряли на жестком диске, который может работать от ~ 70 до 200 IOPS (операция ввода-вывода в секунду, если ваша система не кэширует файлы в каталоге в ОЗУ). Лучше всего минимизировать вызовы ввода-вывода, такие как fstat, filemtime, file_exists и т. Д., И сосредоточиться на работе, которая читает файлы (file_get_contents () и т. Д.).

HDD и операционная система позволяют контроллерам жестких дисков группировать операции ввода-вывода, чтобы получить доступ к низким IOPS. Например, если два файла находятся близко друг к другу на жестком диске, вы можете прочитать их или несколько из них по стоимости чтения только одного из них (я упрощаю ситуацию здесь, но давайте не будем вводить слишком технические детали). Таким образом, вопреки некоторым убеждениям, считывающим сразу несколько файлов (например, с помощью потоковой программы, xargs и т. Д.), Можно значительно повысить производительность.

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

Затем вам нужно перейти в оболочку и использовать программу, которая может обрабатывать файлы параллельно – у PHP есть поддержка pthreads, но не спускайте этот маршрут. xargs с несколькими процессами (опция -P ) может быть полезна, если вы планируете использовать однопоточное приложение. Прочитайте вывод shell_exec () и обработайте его в своей программе PHP.

SSD

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