Php 在目录的文件内容中搜索的最快方法

Php 在目录的文件内容中搜索的最快方法,php,file,search,Php,File,Search,我得到了一个目录,其中包含一个程序用户的文件。该目录中大约有70k个json文件 当前的搜索方法是使用glob和foreach。它变得非常慢,占用了服务器。有什么好方法可以更有效地搜索这些文件吗?我在Ubuntu 16.04机器上运行这个,如果需要,我可以使用exec 更新: 这些是json文件,每个文件都需要打开以检查是否包含搜索查询。在文件上循环是相当快的,但是当需要打开每个文件时,它需要花费相当长的时间 不能使用SQL或memcached对它们进行索引,因为我正在使用memcached进行

我得到了一个目录,其中包含一个程序用户的文件。该目录中大约有70k个json文件

当前的搜索方法是使用
glob
foreach
。它变得非常慢,占用了服务器。有什么好方法可以更有效地搜索这些文件吗?我在Ubuntu 16.04机器上运行这个,如果需要,我可以使用
exec

更新:

这些是json文件,每个文件都需要打开以检查是否包含搜索查询。在文件上循环是相当快的,但是当需要打开每个文件时,它需要花费相当长的时间


不能使用SQL或memcached对它们进行索引,因为我正在使用memcached进行其他操作

正如您自己暗示的那样,要使此搜索成为最高效的搜索,您需要将任务移交给为此目的而设计的工具

我说,看看有什么是公平的。此外,看看,然后满足于它是最好的同类在镇上


实验 我在一台低规格的笔记本电脑上用
ack
做了一个小实验。我在19501文件中搜索了一个现有类名。结果如下:

$cd~/Dev/php/packages
$ack-f | wc-l
19501
$time ack PHPUnitSeleniumTestCase | wc-l
10
ack PHPUnitSeleniumTestCase 7.68s用户2.99s系统21%cpu总计48.832
wc-l 0.00s用户0.00s系统0%cpu总计48.822
我做了同样的实验,这次是用。我真的很惊讶:

$time ag PHPUnitSeleniumTestCase | wc-l
10
ag PHPUnitSeleniumTestCase 0.24s用户0.98s系统13%cpu 9.379总计
wc-l 0.00s用户0.00s系统0%cpu总计9.378
结果让我非常兴奋,我继续努力。更好的是:

$time rg PHPUnitSeleniumTestCase | wc-l
10
rg PHPUnitSeleniumTestCase 0.44s用户0.27s系统19%cpu总计3.559
wc-l 0.00s用户0.00s系统0%cpu总计3.558
试用这一系列工具,看看什么最适合您的需要



p.S.ripgrep在这篇帖子下离开了,说。有趣的阅读,精彩的工作。

取决于您是否使用SSD或HDD存储文件,答案不同

硬盘驱动器

在HDD的情况下,最可能的瓶颈不是PHP,而是HDD可以处理的I/O操作数量少。如果可行的话,我强烈建议使用SSD或RAM磁盘

假设您无法将目录移动到SSD。这意味着您被困在硬盘上,硬盘可以执行~70-~200 IOPS(每秒I/O操作,假设您的系统不在RAM的目录中缓存文件)。最好的办法是最小化诸如fstat、filemtime、file\u exists等I/O调用,并专注于读取文件的操作(file\u get\u contents()等)

HDD和操作系统允许HDD控制器对I/O操作进行分组,以绕过可用的低IOPS。例如,如果两个文件在HDD上彼此接近,您可以同时读取两个或多个文件,而只需读取其中一个文件(我在这里简化了内容,但我们不要讨论太多技术细节)。因此,与某些观点相反,一次读取多个文件(例如使用线程程序、xargs等)可能会大大提高性能

不幸的是,只有当这些文件在物理硬盘上彼此接近时,才会出现这种情况。如果你真的想加速事情,你应该“强烈”。首先考虑一下你用什么样的顺序来阅读你的应用程序,因为这对于下一步是至关重要的。一旦你弄明白了,你就可以完全擦除硬盘驱动器(假设你能做到),然后按照你确定的顺序将文件顺序写入。这样可以将文件并排放置,提高并行文件读取时的有效IOPS

接下来,您需要转到shell并使用能够并行处理文件的程序——PHP支持pthreads,但不支持pthreads<如果您计划使用单线程应用程序,带有多个进程的code>xargs(
-P
选项)可能会有所帮助。读取shell_exec()输出并在PHP程序中进行处理

SSD


由于HDD并行处理可能会有所帮助,因此最好先查看代码,因为I/O可能不是问题。

是否可以像SQL数据库那样对其进行脱机索引以减少负载?您应该使用某种形式的缓存。你可以有一个脚本,每隔15分钟(或无论它们如何变化)对图像进行一次索引,并将其保存到数据库中,然后从数据库中获取图像,这应该更快。实际上,我发现使用
glob
的方法比递归迭代器更快,而且我可以更好/更容易地过滤它。您可以尝试基准测试
glob
和递归迭代器,看看什么更快。如果您不想拥有一个关于文件的DBMS表并监视文件夹的更改,我只知道这两个选项。Apache SOLR是一个选项?如果您可以像您所说的那样使用
exec
,那么查看命令
find
grep
在每次调用之前是否刷新了磁盘缓存?如果不是这样的话,那么很可能你是在把苹果和桔子做比较。在第一次测试期间,操作系统必须从驱动器读取文件。它还将把它们放在RAM中进行缓存(前提是您有一些空闲的RAM)。在第二次和第三次测试中,这些文件可能不是从硬盘中读取的,而是从RAM中读取的,这要快几个数量级。刷新磁盘缓存后,运行两次
ack
将产生几乎相同的基准测试。
ag
rg
更好的数字背后的原因在于它们的不同实现。为了100%确定这一点,我刚刚用磁盘缓存刷新做了同样的实验,