情况是这样,我有大概120个文件,里面存放的是已经序列化后的用户在线时间。用户ID是key,时间是value。每个文件是一天的记录。现在有4个月的记录,要统计出每一个用户4个月来总的在线时间。然后取最高的1000个。因为信息存放在不同的文件中,所以要把所有的记录取出,然后将相同key的value相加。总的记录数大概在5500W左右。我现在不知道该如何处理啊

解决方案 »

  1.   


    // 读取所有文件
    $files = scandir("目录名");
    foreach($files as $v){
        if(is_file($v)){
        // 读取文件,做进一步处理
        }
    }至于如何加用户时间,这个帖子已经说了吧?
    http://topic.csdn.net/u/20100825/09/84511f0e-e029-4e93-b956-cfc4aeb87c1d.html
      

  2.   

    你之前的帖子的数据示例,可不是序列化的这个没特别好的办法,只能统计所有数据,最后算最前面的1000条还有,按你前一帖子的示例数据,每天的数据未必是闭合的,是吧??比如A用户昨天登录,今天离线,时间保存在2个不同的文件对不?如果不是,你最好贴出示例数据还是按照前一帖子的示例数据,如果非要php,可以试试:
    逐行读取,遇到online,则将$online['username'] 赋值当前时间,遇到该用户的下一offline,则计算差值,插入数据库文件读取完毕,可以读下一文件,或者将$online非空的部分,写一个新的文件如果逐一读取文件结束,再给数据库用户字段加索引,统计一下
    ----------------------------------------------------------------------
    不过我没这么做过,每个文件大约150万条数据吧,不清楚效率,我觉得你可以试着操作一个文件看看不能忍受,再考虑其他语言吧,不过,原理还是差不多的
      

  3.   

    有几个问题需要确认一下:
    1、你说的 已经序列化后 是指用 serialize 函数的结果吗?
    2、你说的 用户ID是key,时间是value 中的时间是计算好的在线时间,还是什么?
       从 将相同key的value相加 来看,应该是计算好的在线时间由于数据量比较大,最好用数据库做载体:
    新建一表
    create table test (id varchar(20), num int)
    用临时表就可以了
    create temporary table test (id varchar(20), num int)//在循环中
    $files = scandir("目录名");
    foreach($files as $filename){
      //读取文件并反序列化到数组
      if(is_file($filename)){
        $ar = unserialize(file_get_contents($filename));
        //遍历数组将数据插入表
        foreach($ar as $k=>$v) {
          mysql_query("insert into test (id, num) values ('$k', $v)";
        }
      }
    }当全部文件都加载后,执行查询
    select id, sum(num) as num from test group by id order by num desc limit 1000
    如果内存足够大,也可以用纯php代码实现
    $out = array(); //结果数组
    //在循环中
    $files = scandir("目录名");
    foreach($files as $filename){
      //读取文件并反序列化到数组
      if(is_file($filename)){
        $ar = unserialize(file_get_contents($filename));
        //遍历数组将数据加入结果数组
        foreach($ar as $k=>$v) {
          $out[$k] += $v;
        }
      }
    }//当全部文件都加载后
    arsort($out);
    $out = array_slice($out, 0, 1000);
      

  4.   

    是的,已经用原始的数据已经计算好了每天的每个用户的在线时间用serialize序列化用存放。我只处理闭合的数据,不闭合的情况忽略不计。我现在是这么想的:将每个文件循环读取进来进行遍历,声明一个数组 h 用于存放4个月每个用户总的在线时间,取一个 k 判断这个在 h 中是否存在,如果存在将 v 相加,如果不存在 k 加入 h 。判断完之后都将 K 从原数组中删除。当然时间依旧会花很多,但是空间应该能节约吧。我就爬跑起来的时候内存被吃光,高手看下是否可行。另外排序到是没什么问题,我写了一个堆排序,不过很奇怪我用200W的数据做了一个测试,发现跟PHP内置的快速排序asort效率一样不知道是我写的那个堆排序不够优化还是asort用了什么更优秀的算法
      

  5.   

    先灌到数据库里,然后想怎么折腾就怎么折腾 :)
    ■□■□■□■□■□■□■□■
    □             □
    ■  忍以明志 勤以致远  ■
    □             □
    ■□■□■□■□■□■□■□■
    基于CSDN论坛提供的插件扩展功能,自己做了个签名档工具,分享给大家,欢迎技术交流 :)
      

  6.   

    因为格式很固定,可以自己建索引文件来处理
    首先定义一个用户的区分方法,把所有用户分到100到200个区间,分别对应不同的文件
    然后从数据文件读取用户信息,计算在线时间,累加到索引文件中
    最后从每个文件中取最前面的一些用户进行比较
    整体难度不大,就是处理起来比较麻烦不想自己动手写索引的话可以用lucence来实现索引
      

  7.   

    1、做一张临时表存储数据,汇总所有数据后计算
    2、使用Memcached缓存处理数据,把文件的内容压入缓存 进行计算
    其中涉及到一些算法及排序
    3、每个文件新建一个数据表 联合查询 再排序