過濾器系列(三)—— RSQF

這個過濾器自己是一篇論文中提出的過濾器的簡化版本,去掉了計數功能,我以爲簡化版本應用的可能也很廣,專門寫一篇簡化版本的RSQF。RSQF全稱是rank-and-select based filter,一會咱們會專門來說這個rank-and-select是什麼。
原論文能夠到這裏下載:http://www3.cs.stonybrook.edu/~ppandey/files/SIGMOD17_Talk_CQF_long.pdfpython

過濾器分下面幾部分來說git

Hash函數

這部分不屬於原論文,這部分假設有一個比較好的Hash函數,能夠將原數據hash成n位數據,設n = q + r,這個r實際上控制着過濾器的假陽率和空間大小的平衡。假陽率是\(2^{-r}\),固然若是r越大,空間消耗也越大github

結構

結構部分以下圖所示
image1算法

咱們分別來介紹這個結構中的各部分,其中occupieds這一行是1bit數組,元素只能表示1或0;runends也是1bit數組;remainders內每一個元素佔用r個bit,就是前一部分說的r。這個塊總共有\(2^q\)列,q也是前文說的q。數組

咱們設某一列的下標爲\(i\),則當有元素hash後的前q位對應到這一列的時候,\(occupieds[i] = 1\);咱們把這個元素放到對應位置上,那麼若是有多個元素對應這個位置,咱們要求,把具備相同前q位的元素放到相鄰位置。那麼何時表明結束呢?就是這些前q位相同的元素的最後一個元素對應位置\(runends[i] = 1\)。在圖中,相同顏色的元素其前q位是相同的,也就是說若是不考慮重複,他們都應該存在相同位置上的。函數

算法

def MAY_CONTAIN(Q,x)
"""
查找算法,Q表明存儲結構,x表明要查找的元素
"""
    b = h0(x) #計算hash值,取其前q位
    if Q.occupieds[b] = 0:
        return 0
    t = RANK(Q.occupieds,b)
    k = SELECT(Q.runends,t)
    v = h(x) #計算hash值取其後r位
    while k >= b and Q.runends[k] = 0:
        if Q.remainders[k] = v:
            return 1
        k -= 1
    return false

RANK(Q,i)是找到在位置i以前,數組Q中有多少個1出現過
SELECT(Q,i)是找到數組Q中第i次出現1的位置spa

先經過找到在某個位置以前在occupieds上有多少個1,就表明有多少組相同前q位hash值的元素組,而後經過runends的第i個1,找到目前這個位置對應的組,這樣就能夠精準定位。3d

def find_first_unused_slot(Q,x):
    """
    找到第一個空位置,以便於在插入元素時向後移動元素
    """
    r = rank(Q.occupieds,x)
    s = select(Q.runends)
    while x < s:
        x = s + 1
        r = RANK(Q.occupieds,x)
        s = SELECT(Q.runends,s)
    return x
def insert(Q,x):
    """
    插入一個元素
    實質是先找到一個空位,而後把要插入位置以後的全部元素依次右移,直到把要插入位置空出來爲止
    """
    r = RANK(Q.occupieds,h0(x))
    s = SELECT(Q.runends,r)
    if h0(x) > s:
        Q.remainders[h0(x)] = h1(x)
        Q.runends[h0(x)] = 1
    else:
        s += 1
        n = find_first_unused_slot(Q,s)
        while n > s:
            Q.remainders[n] = Q.remainers[n-1]
            Q.runends[n] = Q.remainers[n-1]
            n -= 1
        Q.remainers[s] = h1(x)
        if Q.occupieds[h0(x)] == 1:
            Q.runends[s-1] = 0
        Q.runends[s] = 1
        Q.occupieds[h0(x)] = 1
    return

原論文中其實還有一個在塊內加速的一個索引方式,在這裏沒有講到,想要詳細瞭解的能夠看原論文。若是想要看帶計數功能版本的過濾器也請看原論文,github上也有公開代碼。https://github.com/splatlab/cqfcode

相關文章
相關標籤/搜索