大数据排序,理论上支持个100亿条没问题吧,o(∩_∩)o 哈哈 --给爱吃大肉包补充了注释
来源:互联网 发布:互换身体的网络电影 编辑:程序博客网 时间:2024/06/10 21:21
爱吃大肉包在文章《大数据排序,理论上支持个100亿条没问题吧,o(∩_∩)o 哈哈》中给出了一个大数据排序的源码。经过运行,成功了。
万恶的是,这人没写注释,读起来很不方便,因此,在自己机器上添加了注释后 ,上传上来。
做了一些小改动,
①为了可以重复测试,增加了删除目录下的所有文件的方法
②增加了计算耗时的方法
③增加了System.out.println();的方法,打印最后的结果集(数据量小时可以直观的查看结果。)主要是便于理解这个思路。
文章的原路径是:http://www.oschina.net/code/snippet_867417_19341?p=2#comments 点击打开链接
问题来自《Programming Perl》
楔子: 问题:假设一个文件中有9亿条不重复的9位整数,现在要求对这个文件进行排序。
一般解题思路: 1、将数据导入到内存中 2、将数据进行排序 (比如插入排序、快速排序) 3、将排序好的数据存入文件
难题: 一个整数为4个字节即使使用数组也需要900,000,000 * 4byte = 3.4G内存对于32位系统,访问2G以上的内存非常困难,而且一般设备也没有这么多的物理内存将数据完全导入到内存中的做法不现实。
其他解决办法: 1、导入数据库运算 2、分段排序运算 3、使用bit位运算
解决方案一:数据库排序 将文本文件导入到数据库,让数据库进行索引排序操作后提取数据到文件
优点:操作简单缺点:运算速度慢,而且需要数据库设备。
解决方案二:分段排序 操作方式:规定一个内存大小,比如200M,200M可以记录52428800条记录,我们可以每次提取5000万条记录到文件进行排序,要装满9位整数需要20次,所以一共要进行20次排序,需要对文件进行20次读操作
缺点: 编码复杂,速度也慢(至少20次搜索)
关键步骤:先将整个9位整数进行分段,亿条数据进行分成20段,每段5000万条,在文件中依次搜索0~5000万,50000001~1亿…… 将排序的结果存入文件
解决方案三:bit位操作 思考下面的问题: 一个最大的9位整数为999999999 这9亿条数据是不重复的,可不可以把这些数据组成一个队列或数组,让它有0~999999999(10亿个)元素数组下标表示数值,节点中用0表示这个数没有,1表示有这个数,判断0或1只用一个bit存储就够了
下面是我添加注释后的代码 ,第二种思路
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.FilenameFilter;import java.io.IOException;import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Random;/** * * @author Hejinbin QQ 277803242 email qing878@gmail.com */public class BigDataSort {public final static String SMALL_FILE_PATH = "e://temp//BigData//";public final static int BIG_NUM_LINE = 1000000;// 务必保证BIG_NUM_LINE 是// SMALL_FILE_LINE的倍数public final static String ORING_FILE_PATH = "e://temp//BigData//bigData.txt";public final static int SMALL_FILE_LINE = 100000; // 1M for 1 small fileprivate File tempFiles[];public BigDataSort() throws IOException {// 补充方法 删除所有文件deleteAllFile();// 删除所有的。temp文件deleteAlltempFile();// 将BIG_NUM_LINE条int值,放到指定的文件ORING_FILE_PATH中,每行一个createBigsortNums();// 拆分成小文件排序,(需要明确计算出小文件的大小不能超出可用内存)【编程珠玑 programming perl】中的问题beSmallFileAndSort();unitFileToSort();}private void createBigsortNums() throws IOException {BufferedWriter writer = new BufferedWriter(new FileWriter(ORING_FILE_PATH));Random random = new Random();for (int i = 0; i < BIG_NUM_LINE; i++) {writer.write(String.valueOf(random.nextInt(100000000)));writer.newLine();// add a new line . in order to show easy by file}writer.close();}private void beSmallFileAndSort() throws IOException {BufferedReader bigDataFile = new BufferedReader(new FileReader(ORING_FILE_PATH));List<Integer> smallLine = null;String str = "";// 根据大文件和小文件的数量,生成n个小文件int fileCount = BIG_NUM_LINE / SMALL_FILE_LINE;tempFiles = new File[fileCount];for (int i = 0; i < tempFiles.length; i++) {tempFiles[i] = new File(SMALL_FILE_PATH + "sortTempFile" + i+ ".temp");BufferedWriter smallWtite = new BufferedWriter(new FileWriter(tempFiles[i]));smallLine = new ArrayList<Integer>();// 向n个文件中插入字符串,每个文件长度为small_file_line,最后一个装入剩余数量for (int j = 0; j < SMALL_FILE_LINE; j++) {smallLine.add(Integer.parseInt(bigDataFile.readLine()));}// 使用Collections的排序Collections.sort(smallLine);// 逐行写入文件for (Object num : smallLine.toArray()) {smallWtite.write(num + "\n");}// 每写完一个文件,需要将IO流关闭smallWtite.close();}}private void unitFileToSort() throws IOException {File tempFile = null;// 以第一个文件为基准,其余的文件向第一个文件写入临时文件for (int i = 1; i < tempFiles.length; i++) {tempFile = sortBySmallFile(tempFiles[0], tempFiles[i]);// 删除第一个文件tempFiles[0].delete();// 将合并后的临时文件放入第一个文件中,此时,第一个文件已经是0,...i个文件的合并后的结果tempFiles[0] = tempFile;}tempFile.renameTo(new File(ORING_FILE_PATH + "sortResult.txt"));BufferedReader br = new BufferedReader(new FileReader(new File(ORING_FILE_PATH + "sortResult.txt")));// String str = "";// while (null != (str = br.readLine())) {// System.out.println(str);// }打印比较耗时br.close();}/** * * @param fromFile * 第一个文件 A (为了便于注释,将文件命名为 A 、B ,结果文件命名为C) * @param toFile * 第二个文件 B * @return * @throws IOException */public static File sortBySmallFile(File fromFile, File toFile)throws IOException {BufferedReader fromRd = new BufferedReader(new FileReader(fromFile));BufferedReader toTempRd = new BufferedReader(new FileReader(toFile));// 临时的排序的结果文件 CFile newSortFile = new File(SMALL_FILE_PATH + fromFile.getName()+ ".temp");// File newSortFile = new File(SMALL_FILE_PATH + "sortTempFile.temp");BufferedWriter newSortFileWt = new BufferedWriter(new FileWriter(newSortFile));int index = -1;int toPoint = -1;// 【1-0】判断此流是否已准备好被读取。如果缓冲区不为空,或者底层字符流已准备就绪,则缓冲的字符流准备就绪。while (fromRd.ready()) {index = Integer.parseInt(fromRd.readLine());if (index < toPoint) {// 【1-1】 第一个文件A中的数值 小于 第二个文件B的数值,将第一个文件数值写入C,newSortFileWt.write(String.valueOf(index));newSortFileWt.newLine();// 跳出此次循环,进入下一个循环continue;} else {// 【1-2】 第一个文件A中的数值 大于 第二个文件B的数值,(-1时,首次读取B中的数值)将第二个文件数值写入C,if (toPoint != -1) {newSortFileWt.write(String.valueOf(toPoint));newSortFileWt.newLine();}// 继续读取第二个文件中的数值}while (toTempRd.ready()) {// 【2-0】 读取第二个文件中的数值toPoint = Integer.parseInt(toTempRd.readLine());if (toPoint < index) {// 【2-1】 第二个文件B中的数值 小于// 第一个文件A的数值,(先读的A,因此,index不肯为-1)将第二个文件数值写入C,newSortFileWt.write(String.valueOf(toPoint));newSortFileWt.newLine();// 继续读取第二个文件} else {// 【2-2】 第二个文件B中的数值 大于 第一个文件A的数值, 将第一个文件数值写入C,newSortFileWt.write(String.valueOf(index));newSortFileWt.newLine();// 停止读取第二个文件B的while循环break;}}// 隐藏的逻辑:当A先读完,则B中的数值为较大数值,第二层的while语句会将B中的数值读出并写入C// 若B先读完,A中的值较大,则执行注释中的【1-2】部分的代码,因为B文件已读完,toTempRd.ready()为false,不在执行【2-0】部分去读取B文件}newSortFileWt.write(String.valueOf(index > toPoint ? index : toPoint));newSortFileWt.newLine();newSortFileWt.close();fromRd.close();toTempRd.close();// toFile.delete();return newSortFile;}private void deleteAllFile() {File f = new File(SMALL_FILE_PATH);File[] files;if (f.isDirectory()) {files = f.listFiles();for (File var : files) {var.delete();}}}private void deleteAlltempFile() {File f = new File(SMALL_FILE_PATH);File[] files;if (f.isDirectory()) {// 获取.temp结尾的文件files = f.listFiles(new FilenameFilter() {public boolean accept(File dir, String name) {if (name.endsWith(".temp")) {return true;}return false;}});for (File var : files) {var.delete();}}}public static void main(String[] args) throws IOException {Long before = System.currentTimeMillis();BigDataSort bigDataSort = new BigDataSort();Long after = System.currentTimeMillis();System.out.println("共耗用 " + (after - before) + " 毫秒");// 1000000 100000共耗用 2575 毫秒// 10000000 1000000共耗用 共耗用 21510 毫秒// 推论, 100亿,20000秒}// 一般分成10个文件后,需要19个临时小文件然后删除,确实挺高潮....}
- 大数据排序,理论上支持个100亿条没问题吧,o(∩_∩)o 哈哈 --给爱吃大肉包补充了注释
- 期中奖拿到了将近15个,失之东隅,收之桑榆吧,o(∩_∩)o...哈哈!!!
- 开始写blog了,o(∩_∩)o...哈哈
- 开始看协议了O(∩_∩)O哈哈~
- 在CSDN安家了。o(∩_∩)o 哈哈
- 自由了 O(∩_∩)O哈哈~
- 能写博客了,O(∩_∩)O哈哈~
- 博客成立了o(∩_∩)o 哈哈
- O(∩_∩)O哈哈~
- o(∩_∩)o...哈哈
- O(∩_∩)O哈哈~
- O(∩_∩)O哈哈~
- O(∩_∩)O哈哈~
- O(∩_∩)O哈哈~
- Hoho,今天在这里安家了,哈哈O(∩_∩)O哈哈~
- 工资又涨了1.5个,哈哈,已经涨了4次了,最近rp爆发啦O(∩_∩)O哈哈~
- 今天给宝宝大采购了o(∩_∩)o...
- 我做到了 我坚持下来了!O(∩_∩)O哈哈~
- Java 设计模式详解
- <httpHandlers>的配置和使用
- hdoj 4417
- web.xml中load-on-startup的作用
- SQL中OBJECT_ID,OBJECT_NAME,OBJECT_DEFINITION的用法
- 大数据排序,理论上支持个100亿条没问题吧,o(∩_∩)o 哈哈 --给爱吃大肉包补充了注释
- Cocos2d-X 3.0 创建项目
- 利用闪回技术单行恢复
- StageFright框架流程解读
- eclipse自动提示功能没了的解决办法
- 定时监测程序运行的情况以及自动重启程序
- 【jquery】jquery获取浏览器的高度、宽度及滚动条的高度
- IOS开发常用的开源类库2
- 1111111111111111111111