这篇主要记录一下学习陈硕同学的对下面这道题的算法思想与代码。

题目是这样的:

有10个文件,每个文件1G,每个文件的每行存放的都是用户的query(请自己随机产生),每个文件的query都可能重复。要求你按照query的频度排序。

(当然,这里的重点是大文件,所以10个1G的文件,或者1个10G的文件,原理都是一样的)

陈硕的代码在这里:

https://gist.github.com/4009225

这是一段非常漂亮的代码,解法与代码都非常值得一看。

【解法】

基本步骤就是不断读入文件,并做初步统计,到了某个内存的极限时写出文件,写的方式是按query的哈希值分配到10个不同的文件中,直到读完所有文件内容,然后把这10个文件中的query按count排序,并10路归并排序出最后结果。

shuffle

从命令行传入输入文件,逐行读入,并存放在一个hashmap中,边读边统计<query, count>,到map的size到达指定size时(10*1000*1000, 主要是考虑内存容量),把这个hashmap的内容先写出去,写到10个文件的第hash(query) % 10个中去,这保证了相同的query肯定在同一个文件中。 这样,直到把文件读完。所以如果输入文件总大小为10G的话,每个文件大小为 <1G (因为相同的query并合并了),可以进行单文件内存内处理。注意此时虽然相同的query在同一文件中,他们可能是分布在好几个地方的,如:

query1 10
query2 5
query3 3
query1 3
query4 3
query 2 7

reduce

把每个文件中相同query合并,并将query按count排序。

merge

10个有序的文件,通过归并排序得到最后的结果。归并的方式是通过一个10个元素的堆,相比于两两迭代归并排序,这大大减少了读文件的时间。

【运行】

该程序只在linux下运行,并需要boost,ubunut下,先安装boost:

apt-get install libboost-dev

然后编译,该程序用到了c++ 0x的feature,所以需要-std=c++0x:

g++ sort.cpp -o sort -std=c++0x

在运行前,需要准备输入数据,这里用lua随机产生:(https://gist.github.com/4045503)

-- updated version, use a table thus no gc involved
local file = io.open("file.txt", "w")
local t = {}
for i = 1, 500000000 dolocal n = i % math.random(10000)local str = string.format("This is a number %d\n", n)table.insert(t, str)if i % 10000 == 0 thenfile:write(table.concat(t))                t = {}end
end

好,开始运行:

sort file.txt

结果如下:

$ time sort file.txt
processing file.txt
shuffling done
reading shard-00000-of-00010
writing count-00000-of-00010
reading shard-00001-of-00010
writing count-00001-of-00010
reading shard-00002-of-00010
writing count-00002-of-00010
reading shard-00003-of-00010
writing count-00003-of-00010
reading shard-00004-of-00010
writing count-00004-of-00010
reading shard-00005-of-00010
writing count-00005-of-00010
reading shard-00006-of-00010
writing count-00006-of-00010
reading shard-00007-of-00010
writing count-00007-of-00010
reading shard-00008-of-00010
writing count-00008-of-00010
reading shard-00009-of-00010
writing count-00009-of-00010
reducing done
merging done

real 19m18.805s
user 14m20.726s
sys 1m37.758s

在我的32位Ubuntu11.10虚拟机上, 分配了1G内存,1个2.5G的CPU core, 处理一个15G的文件,花了19m分钟。

【学习】

  • 把query按哈希值分配到不同的文件,保证想通过query在同一个文件中,漂亮
  • 10路归并排序,用一个最大(小)堆来做,减少了文件读写,漂亮
  • LocalSink, Shuffler, Source等很小的类来封装、解耦一些特别的的任务,结构十分漂亮
  • 一些我不熟悉的知识:
    • __gnu_cxx::__sso_string, gnu short string optimization, 这里有跟更多的说明
    • boost::function , boost::bind
    • 使用map的[] operator时,插入数据根据默认构造函数初始化,对于int默认则是为0
    • C++ 0x的for each:for (auto kv : queries)
    • boost::noncopyable:不能被copy的类从此继承
    • std::hash<string>(): 返回一个针对string的hash functor
    • boost::ptr_vector:boost针对每个container都一共了一个ptr的版本,这个比单纯的使用vector<shared_ptr<T>>要更高效
    • unlink: delete的一个文件
    • std::unordered_map<string, int64_t> queries(read_shard(i, nbuckets)):使用了move sematic,不然效率会很低
    • std::pair定义了 < operator,先比较第一个元素

学习:大文件统计与排序相关推荐

  1. 5亿整数的大文件,怎么排序 ?面试被问傻!

    来源 | 程序员追风 编辑 | Carol 出品| CSDN云计算(ID:CSDNcloud) 最近一家公司,面试官一上来,就问了我这么一个问题,我一脸懵逼,决定记录一下. 问题 给你1个文件bigd ...

  2. 头条面试官:5 亿整数的大文件,如何排序 ?

    点击上方蓝色"终端研发部",选择"设为星标" 学最好的别人,做最好的我们 作者:foreach_break 来源:https://blog.csdn.net/g ...

  3. 含有5亿个整数的大文件,如果排序?

    给你1个文件bigdata,大小4663M,5亿个数,文件中的数据随机,如下一行一个整数: 619630235576816121580203934520950061746773793431220163 ...

  4. 多路归并排序_字节跳动面试:5 亿整数的大文件,如何排序 ?

    最近,面试头条,面试官一上来,就问了我这么一个问题,我一脸懵逼,决定记录一下. 问题 给你1个文件bigdata,大小4663M,5亿个数,文件中的数据随机,如下一行一个整数: 6196302 355 ...

  5. 大文件 多路归并 排序

    1 题目 这一种题目的描述,大概有以后两种: 题目1:一个大文件在一台服务器上存不下,需要存放在多台服务器上,将这个大文件的内容进行排序. 题目2:一个大文件100G,存储在磁盘上,现在需要对这个文件 ...

  6. python3 大文件去重

    目录 一.生成待去重数据 二.通过set按行去重 1. 按原值比较 2. 按md5比较 三.二路归并 一.生成待去重数据 每行是固定位数的数字串 import os from random impor ...

  7. 第五章 shell学习之文件的排序、合并和分割

    sort命令 sort [选项] [输入文件] 选项: -c 测试文件是否已经排序,如果未被排序则输出第一个未被排序的记录 -k 指定排序的域 -m 合并两个已排序的文件,合并的文件也已经排序,如so ...

  8. 使用shell统计字符串出现的次数,并从大到小进行排序显示

    需求说明:对文档中的字符串进行统计,并进行排序后(从大到小),显示出前2条记录 构造的test.txt内容如下: a 12332 a 2323 a 234234 b 232 c 23432 c 34 ...

  9. Linux大文件格式,linux – 用于打印大文件的命令,按大小以人类可读的格式排序...

    我写了一个简单的 shell脚本来查找大文件,主要是为了节省一些打字.这项工作正在完成: find $dir -type f -size +"$size"M -printf '%s ...

  10. 59.排序好的大数据创建索引文件,并实现大文件的二分查找,根据索引百万数据秒读数据...

    创建索引 1 //创建索引 2 struct index 3 { 4 //保存每行偏移的位置 5 int *pindex; 6 //文件的总长度 7 int length; 8 }allindex;/ ...

最新文章

  1. UVa 11174 - Stand in a Line
  2. SpringMVC 框架系列之初识与入门实例
  3. 单防区扩展模块怎么用_Zens推出模块化可扩展无线充电器 可为6台设备同时供电...
  4. iOS之深入解析单例的实现和销毁的底层原理
  5. 针对双系统ubuntu16.04卡死及系统没有声音解决方法
  6. 用 subsetting 限制连接池中的连接数量
  7. win7和mysql乱码,win7 mysql中文乱码怎么处理
  8. 再谈布局,栅栏式自适应布局的学习和实现(calc自适应布局)
  9. jQuer实时监控input对table进行筛选
  10. top刷新间隔_还在用top监控CPU?我们都在用glances
  11. 360怎样修改wifi服务器地址,360安全路由器IP地址设置的具体操作方法介绍
  12. 被动与主动信息收集 | 系统性学习 | 无知的我费曼笔记
  13. nmp i报错git --no-replace-objects ls-remote
  14. JsonObject生成Json字符串有转意字符
  15. Unit nginx.service entered failed state(nginx启动失败)
  16. 利用TL-WR842N(V4)进行路由桥接搭建WDS出现的问题
  17. 计算机专业退休有退休金,我参加工作42年,国家公务员退休,二级警督,退休工资为什么按2014年10月份的工资计算机退休费...
  18. 港美股券商架构最佳实践
  19. uniApp的基本教程
  20. 软件工程测试工程师自我评价,测试工程师自我评价

热门文章

  1. 数据挖掘十大算法-决策树的实现
  2. javascript学习-常用内置对象
  3. Android使用adb命令查看CPU信息
  4. Django项目实战之用户头像上传与访问
  5. 关于URL大小写问题
  6. 动态添加table表格内容,填充审批意见。
  7. HMM学习(2)-Generating Patterns
  8. cocos2d-x-2.2.1环境搭建
  9. spring boot 报错
  10. MongoDB的日志系统