• 利用mongoimport命令导入csv大文件


    最近我同事做了一个PHP项目,其中有一个功能是 上传excel文件并将数据导入mongodb某个集合中。

    通常的做法是 写一个上传文件的页面,然后后端 读取 这个文件,利用phpexcel类库将这个excel文件中的数据读入到某个数组中,

    然后循环写入monogodb的某个集合中。 经过实践成功搞定。文件小的时候一切OK,但是当上传的文件很大的时候,或者说数据量很大的时候,

    上面的办法就发生问题了。有时候后端没有响应,有时候可以成功,但是一般需要很长的时间才能完成任务。

    我们这边测试一下,上传一个33万行*15列的数据量,大概有40M的文件,基本上是无法成功导入。

    无法成功的原因 初步估计为phpexcel类库的原因,

    网上说 一个单元格大致需要1K的内存,所以可能会引起内存分配不够的错误。

    还有个问题是如果是导入2007版的excel的时候,利用php函数simplexml_load_string的时候就已经发生错误了。

    有兴趣的朋友可以 去看一下PHPExcelPHPExcelReaderExcel2007.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:phpworkspaceimportDatapublicphpexcelRTX_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);

  • 相关阅读:
    U盘 格式化 ext3 ext4
    MBR
    CentOS开机的时候卡在进度条一直进不去 F5(是关键)
    redis储存中文,客服端读取出现乱码
    redis 做为缓存服务器 注项!
    redis监控
    keepalived virtual_router_id 44
    你真的会用Gson吗?Gson使用指南
    你真的会用Retrofit2吗?Retrofit2完全教程
    Kotlin 初级读本
  • 原文地址:https://www.cnblogs.com/guoyongrong/p/3587020.html
Copyright © 2020-2023  润新知