L'approccio più veloce per cercare all'interno del contenuto di una directory

Ho una directory che contiene i file per gli utenti di un programma che ho. Ci sono circa 70 mila file json in quella directory.

Il metodo di ricerca corrente utilizza glob e foreach . Sta diventando piuttosto lento e sta registrando il server. C'è un buon modo per cercare tra questi file in modo più efficiente? Sto eseguendo questo su una macchina Ubuntu 16.04 e posso usare exec se necessario.

Aggiornare:

Questi sono file json e each file deve essere aperto per verificare se contiene o less la query di ricerca. Fare il loop dei file è abbastanza veloce, ma quando è necessario aprire each file, ci vuole un po 'di tempo.

Questi non possono essere indicizzati usando SQL o memcached, dato che sto usando memcached per alcune altre cose.

Come hai insinuato te stesso, per rendere ansible la ricerca più performante, devi consegnare il task a uno strumento progettato per questo scopo.

Dico, andare oltre grep e vedere cosa c'è di meglio di ack . Inoltre, vedere ag e quindi accontentarsi di ripgrep quanto è il migliore del suo genere in città.


Sperimentare

Ho fatto un piccolo esperimento con ack su un laptop a bassa specifica. Ho cercato un nome di class esistente all'interno di 19.501 file. Ecco i risultati:

 $ 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 

Ho fatto lo stesso esperimento, questa volta con ag . E mi ha davvero sorpreso:

 $ 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 

Ero così entusiasta dei risultati, ho continuato e ripgrep provato anche a ripgrep . Anche meglio:

 $ 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 

Sperimenta con questa famiglia di strumenti per vedere quale è la soluzione più adatta alle tue esigenze.


L' autore originale di PS ripgrep ha lasciato un commento sotto questo post, dicendo che ripgrep è più veloce di {grep, ag, git grep, ucg, pt, sift} . Lettura interessante, lavoro favoloso.

A seconda che tu stia utilizzando SSD o HDD per memorizzare i file, la risposta è diversa.

HDD

Nel caso dell'HDD, il collo di bottiglia più probabile non è PHP, ma è ansible gestire un numero basso di HDD di operazioni I / O. Consiglio vivamente di passare a SSD o utilizzare il disco RAM se è fattibile.

Supponiamo che tu non sia in grado di spostare la directory su SSD. Significa che sei bloccato su HDD che può eseguire tra ~ 70- ~ 200 IOPS (operazione I / O al secondo, supponendo che il tuo sistema non memorizzi i file nella directory nella RAM). La soluzione migliore è ridurre al minimo le chiamate I / O come fstat, filemtime, file_exist ecc. E concentrarsi sulle operazioni che leggono i file (file_get_contents (), ecc.).

L'HDD e il sistema operativo consentono ai controller HDD di raggruppare le operazioni di I / O per ridurre gli IOPS disponibili. Ad esempio, se due file sono vicini tra loro su HDD, puoi leggerli entrambi o più a costo di leggerne solo uno (sto semplificando le cose qui, ma non entriamo nei dettagli troppo tecnici). Quindi, contrariamente ad alcune convinzioni che leggono più file contemporaneamente (ad esempio utilizzando programmi con thread, xargs, ecc.) Potrebbero migliorare notevolmente le performance.

Sfortunatamente questo sarà solo il caso se questi file sono vicini l'uno all'altro sull'HDD fisico. Se vuoi davvero accelerare le cose, devi prima considerare in quale ordine leggenetworking i file usando l'applicazione poiché è fondamentale per il prossimo passo. Una volta capito, puoi cancellare completamente l'unità HDD (supponendo che tu possa farlo) e scrivere i file in sequenza nell'ordine in cui ti sei sistemato. In questo modo i file devono essere affiancati e migliorare l'IOPS effettivo quando i file paralleli vengono letti.

Quindi è necessario passare alla shell e utilizzare un programma in grado di elaborare i file in parallelo – PHP ha il supporto per i pthread ma non scende lungo quella rotta. xargs con più processi (opzione -P ) potrebbe essere utile se si prevede di utilizzare un'applicazione a thread singolo. Leggi l'output di shell_exec () ed elaboralo nel tuo programma PHP.

SSD

Come con l'elaborazione parallela dell'HDD potrebbe essere d'aiuto, sarebbe meglio comunque vedere il codice prima perché l'I / O potrebbe non essere il problema.