阿里云技术面试红宝书-008 统计出现频率最高的前100个url

274 阅读2分钟

题目描述

淘宝 web 服务器上有 1 个 access 日志文件,记录着用户访问的 url,url 总数100 亿以上,每个 url 约占 64 字节,这些 url 可能存在重复,在一个内存只有 2G 的机器上,统计出访问频率最高的前100 个 URL。

考察点

  1. MapReduce 思想,利用中间文件存储,分而治之。
  2. 排序算法

解决方案

内存 2G = 2 ^ 11 byte, 64 byte = 2^6 byte 2^11/2^6 = 2 ^ 5 = 32 分成约100个文件

  1. 对url做hash运算,然后对将结果对100求余,放入以此余数为结尾的文件中(由于hash特性,所有相同url都会被放入到同一个文件中)
  2. 分别对100个文件中的url进行统计,统计各url的出现次数
  3. 对100个文件url的统计次数取前100个(使用堆排序),如此之后,每个文件最多会有100条记录
  4. 100个文件 * 每个文件的记录数100 = 10000,对些10000个文件进行排序,取出前100个,即为访问频率最高的100个URL(可以借鉴小顶堆思想,构建100个元素的堆,始终保持堆中是访问频率最高的前100个URL)

小顶堆调整

package alibaba;

import java.util.Arrays;
import java.util.Random;

public class SmallTopHeapSortTest {
    public static class SmallHeapBox {
        int sz;
        int half;
        int[] arr;
        public SmallHeapBox(int n) {
            this.sz = n + 1;
            this.half = this.sz / 2;
            this.arr = new int[this.sz];
        }

        public boolean insert(int value) {
            int top = 1;
            if (arr[top] > value) {
                return false;
            }
            arr[top] = arr[arr.length - 1];
            arr[arr.length - 1] = value;
            for (int i = half; i >= 1; i--) {
                int right = 2 * i + 1;
                if (right < this.sz && this.arr[right] < this.arr[i]) {
                    swap(this.arr, i, right);
                }
                int left = 2 * i;
                if (left < this.sz && this.arr[left] < this.arr[i]) {
                    swap(this.arr, i, left);
                }
            }
            return true;
        }
        public int[] obtainResult() {
            return this.arr;
        }

        private void swap(int[] arr, int i, int j) {
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    }
    
    //测试代码
    public static void main(String[] args) {
        int N = 1000;
        int[] arr = new int[N];
        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt(200);
        }
        SmallHeapBox smallHeapBox = new SmallHeapBox(N);
        for (int i = 0; i < arr.length; i++) {
            smallHeapBox.insert(arr[i]);
        }
        Arrays.sort(arr);
        int[] result = smallHeapBox.obtainResult();
        Arrays.sort(result);
        for (int i = 0; i < N; i++) {
            if (arr[i] != result[i + 1]) {
                System.out.println("不一致");
            }
            System.out.printf("", arr[i]);
        }
    }
}