1 题目
这一种题目的描述,大概有以后两种:
- 题目1:一个大文件在一台服务器上存不下,需要存放在多台服务器上,将这个大文件的内容进行排序。
- 题目2:一个大文件100G,存储在磁盘上,现在需要对这个文件的内容进行排序,而内存装不下整个文件。
2 分割为小文件+多路归并排序
基本思路:
- 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。 - 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只能按照升序排序,不能指定排序规则。