Php 从大文本文件获取数据的最快方法
我正在下载一些文件,每个文件都是100mb大小,压缩为.gz。当我解压缩它们时,它们的大小是350MB 在此文件中,在语言的开头有一些标识,如英语的Php 从大文本文件获取数据的最快方法,php,performance,bigdata,Php,Performance,Bigdata,我正在下载一些文件,每个文件都是100mb大小,压缩为.gz。当我解压缩它们时,它们的大小是350MB 在此文件中,在语言的开头有一些标识,如英语的en,德语的de 旁边有一些我需要保存的数字。此文件中的一行示例如下所示 de Gemeinschaft\u nicht-anerkanner\u staten 1 10446 正如我所说的,这个文件非常大,我有多个文件(多个文件中总共有大约1tb的数据,每个文件有300mb的数据) 现在,我正在做以下工作: 由于还有其他语言,我首先只得到以de开头
en
,德语的de
旁边有一些我需要保存的数字。此文件中的一行示例如下所示
de Gemeinschaft\u nicht-anerkanner\u staten 1 10446
正如我所说的,这个文件非常大,我有多个文件(多个文件中总共有大约1tb的数据,每个文件有300mb的数据)
现在,我正在做以下工作:
de
开头的语言preg#u match_all('#^(de\s+.*)#m',file_get_contents('tmpfile.txt'),$matches)代码>
然后我得到了名称
,它是一行中的第二列,应该是
在我们的示例中,Gemeinschaft\u nicht-anerkanner\u staten
现在,我正在查看是否存在该特定名称和当前日期的数据库条目。如果没有,我将它保存到数据库中,否则,我通过增加一个特定的数字来“udpate”它。然而,我从今天上午11点就开始写这篇文章了,目前只有21572篇文章,而且还远没有结束。获取所有数据可能需要几周的时间。有没有比像我这样做更快的方法?这是我正在使用的代码
请注意,正如我所说的,从5月1日开始,我每小时下载一个文件,这意味着我有24个文件,每个文件100mb(解压300mb),大约120天(4个月),这使得我必须浏览2880个文件
<?php
// some requires
// some settings
ignore_user_abort(true);
set_time_limit(0);
ini_set('memory_limit',-1);
// some information about the url and file type
$baseUrl = 'http://dumps.wikimedia.org/other/pagecounts-raw/';
$baseName = 'pagecounts-';
$fileName = '.gz';
// i want to get a file for every hour since the 1st May
$begin = new DateTime('2014-05-01 00:00:00');
$end = new DateTime(date('Y-m-d H:i:s'));
$interval = new DateInterval('PT1H');
$dateRange = new DatePeriod($begin, $interval, $end);
iterating through every hour
foreach ($dateRange as $date){
/**
* @var DateTime $date
*/
// building the download url
$url = $baseUrl . $date->format('Y') . '/' . $date->format('Y-m') . '/' . $baseName . $date->format('Ymd-H0000') . $fileName;
print 'Now doing file: ' . $url . '<br>';
// downloading the file
file_put_contents("tmpfile.gz", fopen($url , 'r'));
// unzipping
unzipfile('tmpfile.gz');
// getting only german articles
preg_match_all('#^(de\s+.*)#m', file_get_contents('tmpfile.txt'), $matches);
$matches = $matches[0];
foreach ($matches as $match){
// getting the informations
$info = explode(' ', $match);
//check if already exists in database
$pageStatistic = new Pagestatistic();
$state = $pageStatistic->loadFrom([
'articleName' => urldecode($info[1]),
'articleLanguage' => 'de',
'pageViewsDate' => $date->format('Y-m-d')
]);
if ($state){
$pageStatistic->articlePageViews = $pageStatistic->articlePageViews + $info[2];
} else {
$pageStatistic->articleName = urldecode($info[1]);
$pageStatistic->articleLanguage = 'de';
$pageStatistic->articlePageViews = $info[2];
$pageStatistic->pageViewsDate = $date->format('Y-m-d');
}
// save/update
$pageStatistic->save();
}
}
//method to unzip files
function unzipfile($fileName){
$buffer_size = 4096;
$out_file_name = str_replace('.gz', '.txt', $fileName);
$file = gzopen($fileName, 'rb');
$out_file = fopen($out_file_name, 'wb');
while(!gzeof($file)) {
fwrite($out_file, gzread($file, $buffer_size));
}
fclose($out_file);
gzclose($file);
}
从文本文件中提取数据似乎没问题。这里的瓶颈是您的数据库活动。一般的建议是尝试成批处理,这会显著提高吞吐量。350MB文件上的正则表达式?祝你好运为什么不逐行阅读,一次只读一行你的逻辑呢?代替正则表达式,您可以在空格上分解并检查第一部分是否为de
,等等。不要使用file\u get\u contents
,因为它会将您的所有数据加载到内存中,也就是说,只有350mb的ram才能加载文件。接下来,您要对文件内容进行预匹配,这也是您正在做的一件高内存使用率的事情。相反,使用fopen获取文件句柄,逐行读取文件,并仅对该行应用正则表达式。您可以使用strpos()
查找语言,也就是说,因为strpos更快,所以不使用正则表达式。kingkero-正则表达式“非常快”。获取所有结果所需时间不到1秒。是db插入花费了很多时间@SergioTulentsev你说的是多查询,而不是对每个匹配都执行一个查询吗?嗨,谢谢你的回答,我会“修复”正则表达式和下载的问题,但问题仍然存在,因为插入需要时间,正则表达式只需不到1秒的时间。多重查询能解决这个问题吗?