利用mongoimport命令導入csv大文件


最近我同事做了一個PHP項目,其中有一個功能是 上傳excel文件並將數據導入mongodb某個集合中。

通常的做法是 寫一個上傳文件的頁面,然后后端 讀取 這個文件,利用phpexcel類庫將這個excel文件中的數據讀入到某個數組中,

然后循環寫入monogodb的某個集合中。 經過實踐成功搞定。文件小的時候一切OK,但是當上傳的文件很大的時候,或者說數據量很大的時候,

上面的辦法就發生問題了。有時候后端沒有響應,有時候可以成功,但是一般需要很長的時間才能完成任務。

我們這邊測試一下,上傳一個33萬行*15列的數據量,大概有40M的文件,基本上是無法成功導入。

無法成功的原因 初步估計為phpexcel類庫的原因,

網上說 一個單元格大致需要1K的內存,所以可能會引起內存分配不夠的錯誤。

還有個問題是如果是導入2007版的excel的時候,利用php函數simplexml_load_string的時候就已經發生錯誤了。

有興趣的朋友可以 去看一下PHPExcel\PHPExcel\Reader\Excel2007.php 里面的load方法。

為此 我們做了一些嘗試

1 ini_set('memory_limit', '1G');//適當放大腳本執行內存的限制

2 set_time_limit(0);//不要讓腳本過期

3 將文件壓縮之后上傳,然后在后端解壓之后,在處理。

4 根據http://phpexcel.codeplex.com/discussions/242712 這個指示改寫了程序

5 放棄使用phpexcel改用其他的excel類庫。

嘗試的結果 都不成功。

 

后來想 要不將excel文件改成csv文件 是否可行。嘗試如下

 將那個40M的文件先手工方式 轉換成csv文件,上傳該文件。

嘗試1:

利用phpexcel讀取文件內容  

結果如下:

發生了錯誤,原來phpexcel中其實沒有專門處理csv文件的類。

嘗試2: 

改用php原生的文件讀取函數fgetcsv()。

結果如下:

成功導入,但是性能很差,處理的時間很長,大概需要30分鍾。客戶無法忍受。

 

最后 利用mongodb自帶的mongoimport工具可以上傳csv文件

命令如下

mongoimport -h localhost --port 27017 -d test222 -c c21 -f REG,PROV,CITY,STORE,CHN,ACCOUNTREF_CD,ACCOUNTTYPE,KEY_CUST,PDT_CAT,SKU_CD,PDT_NAME,CAL_MON_CD,CAL_WEEK_CD,DT_ID,OS,OOS,VOID --ignoreBlanks --file "D:\phpworkspace\importData\public\phpexcel\RTX_NON_COMP_OSA3.csv" --type csv

執行結果,讓人興奮不已,不到1分鍾的時間就導入成功。

由此,我們想到了一個辦法,可不可以利用 php的函數system ()或exec()命令執行mongoimport命令

經過嘗試,發現是可行的,但是只能以 php xxx.php的方式才能運行而不能用http://xxx/xxx.php方式。可能跟執行權限有關吧。

 

所以調整思路

1 創建一個uploadfile.php文件,專門處理網頁上上傳文件,將上傳的文件,放入指定的某個目錄中

2 創建一個loaddatatomongo.php文件,專門利用php的函數system ()或exec()命令執行mongoimport命令,

  將那個目錄下的文件內容導入到mongodb的集合中,並在處理完成之后,將該文件刪除。

3 將第2步所建立的php文件通過計划任務來執行。crontab 中增加 php loaddatatomongo.php 命令

經過一番的折騰,終於成功實現了在很短的時間將csv文件內容導入到mongo中去。

這個過程中發生了一下的問題匯總如下

1 mongoimport 導入csv文件的時候,這個csv文件必須是utf8編碼方式的,否則無法導入

 通過運用調用linux命令 /usr/bin/iconv -t UTF-8 文件a.csv -o 文件b.csv 解決

2  上傳的文件是zip壓縮的文件,需要需要一個解壓的命令

 通過運用調用linux命令 unzip  文件.zip 解決

3 在linux系統中直接執行運行 php loaddatatomongo.php 可以成功轉換,而通過計划任務執行的時候,卻始終不成功

新建一個shell執行文件,比如說 ss.sh,將crontab計划任務表中 php loaddatatomongo.php 的部分,改成 ss.sh

然后將 php loaddatatomongo.php 命令放在這個shell腳本,最后在這個shell腳本里面頭上增加export LANG=zh_CN.GB18030命令

 

php部的源代碼發布出來,以供參考

//讀取文件信息

$arrayFileInfo = get_headers($arrayExcel['file']);

$strZipName = uniqid().'.zip';
$file = file_get_contents($arrayExcel['file']);
$strCsvNow = substr($arrayExcel['name'], 0,-3).'csv';
$strCsvNow2 = 'new'.substr($arrayExcel['name'], 0,-3).'csv';
$tmpfname = APPLICATION_PATH.'/../cache/'.$strZipName;
file_put_contents($tmpfname, $file); //寫入臨時ZIP文件

//文件解壓命令
$strVim0 = 'unzip '.$tmpfname;

//utf8轉換命令
$strVim1 = '/usr/bin/iconv -t UTF-8 '.$strCsvNow.' -o '.$strCsvNow2;

//構造mongoimport命令
$strVim2 = '/usr/local/mongodb/bin/mongoimport -h 10.0.0.31 --port 27017 -d umav3 -c '.$strCollect.' -f ';
$arrayRemoveQuery = array();
foreach ($arrayStructure as $key => $val)
{
if($key <2)
$arrayRemoveQuery[$val['alias']] = $val['name'];
$strVim2.= $val['alias'].',';
}
$strVim2 = substr($strVim2, 0,-1);
$strVim2.=' --ignoreBlanks --file '.$strCsvNow2.' --type csv';

//執行命令
system($strVim0,$retval1);
system($strVim1,$retval2);
system($strVim2,$retval3);

//文件刪除
unlink($strZipName);
unlink($strCsvNow);
unlink($strCsvNow2);

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM