官网说明
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+SortBy
order by
全局排序,但是只有一个reduce,因此在数据量很大的情况下,效率很低
sort by
单个reduce内有效,但是全局无序,要想实现和order by 一样的效果,必须要进行一次归并排序(下面讲),控制个数:set mapred.reduce.tasks=xxx 如果是spark则是控制partitions
distribute by
按照指定的字段把数据分散到不同的reduce中去,但是如果你按照网上的写法,请注意控制map task的个数,适用场景:输入输出文件大小不均匀,小文件很多的场景
cluster by
cluster by = distribute by+sort by
思考
如何在sort后面进行归并排序?
其实归并排序的算法不难,分而治之,但是实际上要结合sort by实现order by的效果,从而达到全局有效,并且效率很高,博主因为时间问题,没有具体的实现,在这里提供一个思路:
归并排序的算法
import java.util.Arrays;
/*
归并排序
*/
public class MergeSort {
public static void main(String[] args) {
int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
int[] temp = new int[arr.length];
mergeSort(arr, 0, arr.length - 1, temp);
System.out.println(Arrays.toString(arr));
}
// 分+和
public static void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2; // 中间索引
// 向左递归进行分解
mergeSort(arr, left, mid, temp);
// 向右递归分解
mergeSort(arr, mid + 1, right, temp);
// 每分解一次就合并一次
merge(arr, left, mid, right, temp);
}
}
/**
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
// System.out.println("xxx");
int i = left; // 左边有序序列的初始索引
int j = mid + 1; // 右边有序序列的初始索引 // 中间索引+1 就是第二个数组的第一个元素
int t = 0; // 指向temp数组的当前索引
// 先把左右两边(有序)的数据按照规则填充到temp里面去
// 直到左右两边的有序序列,有一边处理完毕为止
while (i <= mid && j <= right) {
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//即将左边的当前元素,填充到 temp数组
//然后 t++, i++
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else { //反之,将右边有序序列的当前元素,填充到temp数组
temp[t++] = arr[j++];
}
}
// 把有剩余数据的一边的数据依次填充到temp去
while (i <= mid) { // 左边还有剩余
temp[t++] = arr[i++];
}
while (j <= right) {
temp[t++] = arr[j++];
}
// 将temp数组的元素拷贝到arr
//注意,并不是每次都拷贝所有
t = 0;
int tempLeft = left;
while (tempLeft <= right) {
arr[tempLeft++] = temp[t++];
}
}
}
自定义函数请参考order by的类,参考其实现
如何在大量数据的情况下取出top10
可以用sort by 然后limit 10 排序完成后再用order by 来实现最终的全局排序