大文件 多路归并 排序

1 题目

这一种题目的描述,大概有以后两种:

  • 题目1:一个大文件在一台服务器上存不下,需要存放在多台服务器上,将这个大文件的内容进行排序。
  • 题目2:一个大文件100G,存储在磁盘上,现在需要对这个文件的内容进行排序,而内存装不下整个文件。

2 分割为小文件+多路归并排序

大文件+分割+多路归并排序
基本思路:

  1. step1:分割+排序
    从头开始将大文件 F i l e File File的一个小部分读入内存中,将这一小部分进行排序,然后将排序后的这一小部分写入到一个独立的小文件 f i l e 1 file_1 file1中。循环前面的步骤,生成了一堆内部有序的小文件 f i l e 1 file_1 file1 f i l e 2 file_2 file2 f i l e 3 file_3 file3、… 、 f i l e N file_N fileN
  2. step2:多路归并
    将每一个小文件的第一个数取出,即每一个小文件里的最小数,对这些数进行归并排序,将这些数里的最小数字 n u m i num_i numi(来自 f i l e i file_i filei )写入大文件的第一行,此即整个大文件里的最小数字。
    将文件 f i l e i file_i filei的行数指针+1,取出文件 f i l e i file_i filei行数指针当前所指的数字,放入内存中,将大文件的行数指针+1。
    继续前面的循环,直到所有小文件都遍历完成。
    参考文献:100G 数据,只有 100M 内存,怎么排序?

3 归并排序程序

package com.mergeSort;

public class MergeSort {

	public static void main(String[] args) {
		int[] num = {9,1,8,2,7,3,6,4,5};
		mergeSort(num,0,num.length-1);//注意,后面使用的是闭区间,所以传入num.length-1
		for (int i = 0; i < num.length; i++) {
			System.out.print(num[i] + " ");
		}
	}
	
	public static void mergeSort(int[] num,int start,int end) {
		if(start < end) {//划分,直至一个分段中只剩一个元素,即start==end时,停止递归
			int mid = (start + end)/2;
			mergeSort(num, start, mid);
			mergeSort(num, mid+1, end);
			merge(num, start, mid, end);//当上面两个mergeSort都返回,即两个分段都是1后,将两个分段合并。
		}
	}

	//将num的[start,mid]、[mid+1,end]两个区间合并
	private static void merge(int[] num, int start, int mid, int end) {
		int[] tempNum = new int[end-start+1];
		int indexTemp = 0,left = start,right = mid+1;//注意:left遍历[start,mid],right遍历[mid+1,end]
		
		while(left <= mid && right <= end) {
			if(num[left] <= num[right]) {
				tempNum[indexTemp ++] = num[left ++];
			}else {
				tempNum[indexTemp ++] = num[right ++];
			}
		}
		
		while(left <= mid) tempNum[indexTemp ++] = num[left ++];
		while(right <= end) tempNum[indexTemp ++] = num[right ++];
		
		int p = start;
		for (int i = 0; i < tempNum.length; i++) {
			num[p ++] = tempNum[i]; 
		}
	}
}

4 具体的描述

海量数据排序——如果有1TB的数据需要排序,但只有32GB的内存如何排序处理?
1、外排序
  传统的排序算法一般指内排序算法,针对的是数据可以一次全部载入内存中的情况。但是面对海量数据,即数据不可能一次全部载入内存,需要用到外排序的方法。外排序采用分块的方法(分而治之),首先将数据分块,对块内数据按选择一种高效的内排序策略进行排序。然后采用归并排序的思想对于所有的块进行排序,得到所有数据的一个有序序列。

例如,考虑一个1G文件,可用内存100M的排序方法。首先将文件分成10个100M,并依次载入内存中进行排序,最后结果存入硬盘。得到的是10个分别排序的文件。接着从每个文件载入9M的数据到输入缓存区,输出缓存区大小为10M。对输入缓存区的数据进行归并排序,输出缓存区写满之后写在硬盘上,缓存区清空继续写接下来的数据。对于输入缓存区,当一个块的9M数据全部使用完,载入该块接下来的9M数据,一直到所有的9个块的所有数据都已经被载入到内存中被处理过。最后我们得到的是一个1G的排序好的存在硬盘上的文件。

2、1TB数据使用32GB内存如何排序
  ①、把磁盘上的1TB数据分割为40块(chunks),每份25GB。(注意,要留一些系统空间!)
  ②、顺序将每份25GB数据读入内存,使用quick sort算法排序。
  ③、把排序好的数据(也是25GB)存放回磁盘。
  ④、循环40次,现在,所有的40个块都已经各自排序了。(剩下的工作就是如何把它们合并排序!)
  ⑤、从40个块中分别读取25G/40=0.625G入内存(40 input buffers)。
  ⑥、执行40路合并,并将合并结果临时存储于2GB 基于内存的输出缓冲区中。当缓冲区写满2GB时,写入硬盘上最终文件,并清空输出缓冲区;当40个输入缓冲区中任何一个处理完毕时,写入该缓冲区所对应的块中的下一个0.625GB,直到全部处理完成。

3、继续优化
  磁盘I/O通常是越少越好(最好完全没有),那么如何降低磁盘I/O操作呢?关键就在第5和第6步中的40路输入缓冲区,我们可以先做8路merge sort,把每8个块合并为1路,然后再做5-to-1的合并操作。
  再深入思考一下,如果有多余的硬件,如何继续优化呢?有三个方向可以考虑:
  使用并发:如多磁盘(并发I/O提高)、多线程、使用异步I/O、使用多台主机集群计算。
  提升硬件性能:如更大内存、更高RPM的磁盘、升级为SSD、Flash、使用更多核的CPU。
  提高软件性能:比如采用radix sort、压缩文件(提高I/O效率)等。
原文链接:https://blog.csdn.net/FX677588/article/details/72471357

5 Hive中order by的底层原理

order by 的底层原理即本文所讲的思想。

6 order by 、sort by、distribute by、cluster by的区别

order by进行全局排序,只会启动一个reducer。
sort by 在单个reducer内部排序,不保证全局排序,会根据文件的数量启动多个reducer。
distribute by:分组,就是在mapreduce程序中的patition分区过程,将同一分区的数据发送给一个reducer。
cluster by:如果sort by与distribute by 使用的键相同,可以使用cluster by代替distribute by + sort by。但是cluster by只能按照升序排序,不能指定排序规则。

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张之海

若有帮助,客官打赏一分吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值