天天看點

【原創】分布式之redis的三大衍生資料結構

引言

說起

redis

的資料結構,大家可能對五大基礎資料類型比較熟悉:

String

Hash

List

Set

Sorted Set

。那麼除此之外,還有三大衍生資料結構,大家平時是很少接觸的,即:

bitmaps

hyperloglog

geo

另外,我覺得,這三個資料結構,隻能說是錦上添花。真正在項目中,我還真沒用過。

下面大家來看看這三大資料結構的定義和用途

bitmaps

定義

說到這個

bitmaps

,其實它就是

String

,但它可以對

String

的位進行操作。然後呢,這個位操作,有自己的指令,是以和操作

String

redis

指令又不大一樣!

可以這麼了解

bitmaps為一個以位為機關的數組,數組的每個單元隻能存儲0和1

下面舉個例子,比如我們要做一個set操作,

key

w

value

h

,那麼執行如下指令

127.0.0.1:6379> set w h     OK     127.0.0.1:6379> get w     "h"           

那麼

h

的ASCII為

0110 1000

接下來,你可以用位指令

getbit

指令取出,取出每一位的内容。

127.0.0.1:6379> getbit w 0 #用getbit擷取w第0位的值     (integer) 0     127.0.0.1:6379> getbit w 1 #用getbit擷取w第1位的值     (integer) 1     127.0.0.1:6379> getbit w 2 #用getbit擷取w第2位的值     (integer) 1     127.0.0.1:6379> getbit w 3 #用getbit擷取w第3位的值     (integer) 0           

用途

網上傳言,此結構用來統計一定時間内的,活躍的使用者數,使用

bitmap

的結構比傳統的

set

結構省空間。然而,這種用途有很大的局限性,我後文會說到。先說一下,網上的說法。

假設有30個使用者,其中有5個使用者,在

2018-10-04

這天登陸了。假設這5個使用者的userid=2,4,8,11,12。

那麼,我們假設key為

users:2018-10-04

,将其

value

值用于記錄使用者登陸資訊。那麼為了記錄上述5個使用者登陸過,我們将該

value

值的第2位,第4位,第8位,第11位,第12位設為1,即執行下述指令

127.0.0.1:6379> setbit users:2018-10-04 2 1     (integer) 0     127.0.0.1:6379> setbit users:2018-10-04 4 1     (integer) 0     127.0.0.1:6379> setbit users:2018-10-04 8 1     (integer) 0     127.0.0.1:6379> setbit users:2018-10-04 11 1     (integer) 0     127.0.0.1:6379> setbit users:2018-10-04 12 1     (integer) 0           

這個時候,比如你要判斷userid=11的使用者,在2018-10-04這天,有沒有登陸過,就執行下述指令

127.0.0.1:6379> getbit users:2018-10-04 11     (integer) 1           

結果為1,就代表使用者登陸過。如果傳回結果為0,則代表使用者沒登陸過。

如果要統計,2018-10-04,這一天登陸的使用者數,可以執行下面的指令

127.0.0.1:6379> bitcount users:2018-10-04     (integer) 5           

上面的指令就可以統計出,2018-10-04,這一天5個使用者登陸過。

ok,到這裡大家就查不多能明白了。

先說一下,這裡的

userid=2,4,8,11,12

,可以了解為偏移量。比如實際項目中的userid位1000002,那麼偏移量就是2。大家在項目中,可以靈活變通。

然而這種方式有一個局限性。我們在實際項目中,如果userid是使用uuid生成的,那麼,你要如何根據這些userid生成偏移量?莫非你還要去找一個hash函數,生成偏移量?就算找到了相應的hash函數,你能確定一定不發生hash碰撞,導緻偏移量一緻?

是以,大家了解即可。

HyperLogLog

HyperLogLog

并不是一種資料結構,而是一種算法,可以利用極小的記憶體空間完成獨立總數的統計。

其實,大家可能對該算法比較陌生。我們

java

中有一個庫叫

stream-lib

,其中也實作了

HyperLogLog

算法。我大概說一下該算法的原理,我不想去長篇大論的搬出數學論文來,大家看着也無聊,這裡

Hyper

指的是超級的意思,它的前世是LogLog算法。這裡部落客蜻蜓點水的裝13一下,大家能領悟到精髓即可。

假設有如下對話

我:"小曲啊,假設啊,我一輪丢5次硬币,丢了很多輪之後,發現這幾輪中,最多出現連續的2次反面1次正面,你能猜出來我丢了多少輪麼!"

小曲:"應該沒幾輪吧,頂多就七八輪。"

我:"卧槽,這麼機智,怎麼算的?"

小曲:"很簡單啊,正反面機率都是1/2,連着二次反面,一次正面。不就是1/21/21/2麼!"

我:"那要是最多出現連續的4次反面1次正面呢?"

小曲:"那應該是很多很多輪吧!"

我:"果然機智!"

上述聊天,出自我和同僚曲之間的,日常互吹!如有雷同,純屬巧合!

好了,原理講完了!隻是他的估算算法比較複雜!沒這麼簡單而已!而且這麼估,誤差還比較大!下面給出算法的僞代碼。

輸入:一個集合     輸出:集合的獨立總數     算法:          max = 0          對于集合中的每個元素:                    hashCode = hash(元素)                    num = hashCode二進制表示中最前面連續的0的數量                    if num > max:                        max = num          最後的結果是2的(max + 1)次幂           

需要說明的是

hashCode = hash(元素)           

就是把你的輸入元素,映射成二進制長串。映射成二進制長串後,就可以類比到我最先說的抛硬币的結果了。至于最後的結果為什麼用

(max+1)

,大家可以去查文獻。畢竟這文章是在講

redis

,不是在講這個算法。而且這個算法,後面還經過了一系列演進,比如将入參集合分為m個部分,然後将

m

個部分的結果求一個平均數

(avg)

,最後以2的

(avg + 1)

次幂,來估計獨立總數!這些讀者有興趣可以自行查詢!

這個結構可以非常省記憶體的去統計各種計數,比如注冊

IP

數、每日通路

IP

數。當然,存在誤差!Redis官方給出的數字是0.81%的失誤率。

用法也很簡單如下所示

127.0.0.1:6379> pfadd ips:2018-10-04 "127.0.0.1" "127.0.0.2" "127.0.0.3" "127.0.0.4"      (integer) 1     127.0.0.1:6379> pfcount ips:2018-10-04     (integer) 4           

上面就是示範了,2018-10-04這天,約4個ip登陸了系統!

網上有一張和傳統集合結構的占用空間對比圖,貼出來,給大家看看

【原創】分布式之redis的三大衍生資料結構

注意了,再強調一次,使用此結構是存在誤差的!比如你

pfadd

了一百萬條資料進去,結果

pfcount

的結果可能就999756條!

Geo

Geo可以用于存儲經緯度、計算兩地之間的距離、範圍計算等。其底層實作是zset。

主要有以下六組指令

  • geoadd

    :增加某個地理位置的坐标。
  • geopos

    :擷取某個地理位置的坐标。
  • geodist

    :擷取兩個地理位置的距離。
  • georadius

    :根據給定地理位置坐标擷取指定範圍内的地理位置集合。
  • georadiusbymember

    :根據給定地理位置擷取指定範圍内的地理位置集合
  • geohash

    :擷取某個地理位置的geohash值。

我這裡直接貼官網文檔的例子,大家有興趣可以自行查詢.

首先,先給key增加兩個坐标

redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"     (integer) 2           

其次,計算兩個坐标之間的舉例

redis> GEODIST Sicily Palermo Catania     "166274.15156960039"           

最後,計算距離經緯度

(15,37)

距離

100km

200km

範圍内的坐标有哪些

redis> GEORADIUS Sicily 15 37 100 km     1) "Catania"     redis> GEORADIUS Sicily 15 37 200 km     1) "Palermo"     2) "Catania"           

總結,我目前還沒涉及到和地圖有關的業務,是以該結構用的還比較少。大家根據項目具體需求使用即可!

作者:孤獨煙

出處: http://rjzheng.cnblogs.com/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。如果覺得還有幫助的話,可以點一下右下角的【推薦】。