在20mb平面文件数据库(PHP)中搜索整个单词的最快方法

时间:2015-03-23 01:56:23

标签: php search flat-file

我有20MB平面文件数据库,大约有500k行,只允许[a-z0-9-]个字符,平均7个单行,没有空行或重复行:

平面文件数据库:

put-returns-between-paragraphs
for-linebreak-add-2-spaces-at-end
indent-code-by-4-spaces-indent-code-by-4-spaces

我正在搜索whole words only并从此数据库中提取first 10k results

到目前为止,如果在数据库的前20k行中找到10k匹配,则此代码可以正常工作,但如果这个单词很少,那么脚本必须搜索所有500k行,这个速度要慢10倍。

设定:

$cats = file("cats.txt", FILE_IGNORE_NEW_LINES);
$search = "end";
$limit = 10000;

搜索:

foreach($cats as $cat) {
    if(preg_match("/\b$search\b/", $cat)) {
        $cats_found[] = $cat;
        if(isset($cats_found[$limit])) break;
    }
}

我的PHP技能和知识有限,我不能也不知道如何使用sql,所以这是我能做到的最好的,但我需要一些建议:

  • 这是正确的代码吗,foreach和preg_match有问题吗?
  • 我应该将大文件拆分成较小的文件,如果是的话是什么尺寸?
  • 最后,sql会更快,多少? (未来的选择)

感谢您阅读本文并对不良英语感到抱歉,这是我的第三语言。

2 个答案:

答案 0 :(得分:2)

如果大多数的行不包含搜索到的字词,则可以较少执行preg_match(),如下所示:

foreach ($lines as $line) {
    // fast prefilter...
    if (strpos($line, $word) === false) {
        continue;
    }
    // ... then proper search if the line passed the prefilter
    if (preg_match("/\b{$word}\b/", $line)) {
        // found
    }
}

但是,它需要在实际情况下进行基准测试。

答案 1 :(得分:1)

这可能会让你逐行阅读,虽然你的内存可能会耗尽:

  

(可能需要调整你的php.ini memory_limit和max_execution_time或通过cli运行)

$rFile = fopen( 'inputfile.txt', 'r' );
$iLineNumber = 0;
$sSearch = '123';
$iLimit  = 5000;
while( !feof( $rFile ) )
{
    if( $iLineNumber > $iLimit )
    {
        break;
    }
    $sLine = fgets( $rFile );
    if( preg_match("/\b$sSearch\b/", $sLine, $aMatches ) ) 
    {
        $aCats[] = $aMatches[ 0 ];
    }
    ++$iLineNumber;
}
var_dump( $aCats );

我的建议是将文件重新格式化为sql import 并使用数据库。平面文件搜索速度明显变慢。

  

INFILE:

put-returns-between-paragraphs
for-linebreak-add-2-spaces-at-end
indent-code-by-4-spaces-indent-code-by-4-spaces
put-returns-between-paragraphs
for-linebreak-add-2-spaces-at-end
indent-code-by-4-spaces-indent-code-by-4-spaces
put-returns-between-paragraphs
123
for-linebreak-add-2-spaces-at-end
indent-code-by-4-spaces-indent-code-by-4-spaces
put-returns-between-paragraphs
for-linebreak-add-2-spaces-at-end
indent-code-by-4-spaces-indent-code-by-4-spaces
123
put-returns-between-paragraphs
for-linebreak-add-2-spaces-at-end
indent-code-by-4-spaces-indent-code-by-4-spaces
  

输出:

array(2) {
  [0]=>
  string(3) "123"
  [1]=>
  string(3) "123"
}

它从匹配中包装了一个额外的数组,所以我们必须使用[0]