海量數據判重

海量數據判重

1. 問題描述

對於海量數據,要求判斷一個數據是否已經存在。這個數據很有可能是字符串,例如 URL。

2. HashSet

最直觀的方法是使用 HashSet 存儲,那麼就能以 O(1) 的時間複雜度判斷一個數據是否已經存在。

考慮到數據是海量的,那麼就需要使用拆分的方式將數據拆分到多臺機器上,分別在每臺機器上使用 HashSet 存儲。我們需要使得相同的數據拆分到相同的機器上,可以使用哈希取模的拆分方式進行實現。

3. BitSet

如果海量數據是整數,並且範圍不大時,就可以使用 BitSet 存儲。通過構建一定大小的比特數組,並且讓每個整數都映射到這個比特數組上,就可以很容易地知道某個整數是否已經存在。因爲比特數組比整型數組小的多,所以通常情況下單機就能處理海量數據。

在這裏插入圖片描述
以下是一個 BitSet 的實現,當然在實際開發中可以直接使用語言內置的實現。

class BitSet {
    int[] bitset;

    public BitSet(int size) {
        bitset = new int[(size >> 5) + 1]; // divide by 32
    }

    boolean get(int pos) {
        int wordNumber = (pos >> 5); // divide by 32
        int bitNumber = (pos & 0x1F); // mod 32
        return (bitset[wordNumber] & (1 << bitNumber)) != 0;
    }

    void set(int pos) {
        int wordNumber = (pos >> 5); // divide by 32
        int bitNumber = (pos & 0x1F); // mod 32
        bitset[wordNumber] |= 1 << bitNumber;
    }
}

使用 BitSet 還可以很容易地解決一個整數出現次數的問題,例如使用兩個比特數組就可以存儲 0~3 的信息。其實判重問題也可以簡單看成一個數據出現的次數是否爲 1,因此一個比特數組就夠了。

4. 布隆過濾器

布隆過濾器能夠以極小的空間開銷解決海量數據判重問題,但是會有一定的誤判概率。它主要用在網頁黑名單系統、垃圾郵件過濾系統、爬蟲的網址判重系統。

布隆過濾器也是使用 BitSet 存儲數據,但是它進行了一定的改進,從而解除了 BitSet 要求數據的範圍不大的限制。在存儲時,它要求數據先經過 k 個哈希函得到 k 個位置,並將 BitSet 中對應位置設置爲 1。在查找時,也需要先經過 k 個哈希函數得到 k 個位置,如果所有位置上都爲 1,那麼表示這個數據存在。

由於哈希函數的特點,兩個不同的數通過哈希函數得到的值可能相同。如果兩個數通過 k 個哈希函數得到的值都相同,那麼使用布隆過濾器會將這兩個數判爲相同。

可以知道,令 k 和 m 都大一些會使得誤判率降低,但是這會帶來更高的時間和空間開銷。

布隆過濾器會誤判,也就是將一個不存在的數判斷爲已經存在,這會造成一定的問題。例如在垃圾郵件過濾系統中,會將一個郵件誤判爲垃圾郵件,那麼就收不到這個郵件。可以使用白名單的方式進行補救。

在這裏插入圖片描述

5. Trie

Trie 樹又叫又叫字典樹、前綴樹、單詞查找樹,它是一顆多叉查找樹。與二叉查找樹不同,鍵不是直接保存在節點中,而是由節點在樹中的位置決定。

如果海量數據是字符串數據,那麼就可以用很小的空間開銷構建一顆 Trie 樹,空間開銷和樹高有關。

img

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章