平常我們我接觸最多的是5個入門級數據結構:String,Hash,List,Set,Sorted Set。本文介紹3個高級數據結構:Bitmaps,Hyperloglogs,GEO。
Bitmapsbitmaps不是一個真實的數據結構。而是String類型上的一組面向bit操作的集合。由於strings是二進位安全的blob,並且它們的最大長度是512m,所以bitmaps能最大設置2^32個不同的bit。
bit操作被分為兩組:
Bitmaps的最大優點就是存儲信息時可以節省大量的空間。例如在一個系統中,不同的用戶被一個增長的用戶ID表示。40億(2^32=4*1024*1024*1024≈40億)用戶只需要512M內存就能記住某種信息,例如用戶是否登錄過。
Bits設置和獲取通過SETBIT 和GETBIT 命令,用法如下:
SETBIT key offset value
GETBIT key offset
使用實例:
127.0.0.1:6380> setbit dupcheck 10 1
(integer) 0
127.0.0.1:6380> getbit dupcheck 10
(integer) 1
SETBIT命令第一個參數是位編號,第二個參數是這個位的值,只能是0或者1。如果bit地址超過當前string長度,會自動增大string。
Bitmaps示意圖GETBIT命令指示返回指定位置bit的值。超過範圍(尋址地址在目標key的string長度以外的位)的GETBIT總是返回0。三個操作bits組的命令如下:
bitmaps一般的使用場景:
例如,想像一下你想知道訪問你的網站的用戶的最長連續時間。你開始計算從0開始的天數,就是你的網站公開的那天,每次用戶訪問網站時通過SETBIT命令設置bit為1,可以簡單的用當前時間減去初始時間並除以3600*24(結果就是你的網站公開的第幾天)當做這個bit的位置。
這種方法對於每個用戶,都有存儲每天的訪問信息的一個很小的string字符串。通過BITCOUN就能輕易統計某個用戶連續訪問網站的天數。另外通過調用BITPOS命令,或者客戶端獲取並分析這個bitmap,就能計算出最長停留時間。
HyperLogLogsHyperLogLog是用於計算唯一事物的概率數據結構(從技術上講,這被稱為估計集合的基數)。如果統計唯一項,項目越多,需要的內存就越多。因為需要記住過去已經看過的項,從而避免多次統計這些項。
然而,有一組算法可以交換內存以獲得精確度:在redis的實現中,您使用標準錯誤小於1%的估計度量結束。這個算法的神奇在於不再需要與需要統計的項相對應的內存,取而代之,使用的內存一直恆定不變。最壞的情況下只需要12k,就可以計算接近2^64個不同元素的基數。或者如果您的HyperLogLog(我們從現在開始簡稱它為HLL)已經看到的元素非常少,則需要的內存要要少得多。
在redis中HLL是一個不同的數據結構,它被編碼成Redis字符串。因此可以通過調用GET命令序列化一個HLL,也可以通過調用SET命令將其反序列化到redis伺服器。
HLL的API類似使用SETS數據結構做相同的任務,SETS結構中,通過SADD命令把每一個觀察的元素添加到一個SET集合,用SCARD命令檢查SET集合中元素的數量,集合裡的元素都是唯一的,已經存在的元素不會被重複添加。
而使用HLL時並不是真正添加項到HLL中(這一點和SETS結構差異很大),因為HLL的數據結構只包含一個不包含實際元素的狀態,API是一樣的:
127.0.0.1:6380> PFADD hll a b c d d c
(integer) 1
127.0.0.1:6380> PFCOUNT hll
(integer) 4
127.0.0.1:6380> PFADD hll e
(integer) 1
127.0.0.1:6380> PFCOUNT hll
(integer) 5
PFMERGE命令說明:
PFMERGE destkey sourcekey [sourcekey ...]
Merge N different HyperLogLogs into a single one.
用法(把hll1和hll2合併到hlls中):
127.0.0.1:6380> PFADD hll1 1 2 3
(integer) 1
127.0.0.1:6380> PFADD hll2 3 4 5
(integer) 1
127.0.0.1:6380> PFMERGE hlls hll1 hll2
OK
127.0.0.1:6380> PFCOUNT hlls
HLL數據結構的一個使用場景就是計算用戶每天在搜索框中執行的唯一查詢,即搜索頁面UV統計。而Bitmaps則用於判斷某個用戶是否訪問過搜索頁面。這是它們用法的不同。
GEORedis的GEO特性在 Redis3.2版本中推出,這個功能可以將用戶給定的地理位置(經度和緯度)信息儲存起來,並對這些信息進行操作。GEO相關命令只有6個:
經緯度具體的限制,由EPSG:900913/EPSG:3785/OSGEO:41001規定如下:
有效的經度從-180度到180度。
有效的緯度從-85.05112878度到85.05112878度。
當坐標位置超出上述指定範圍時,該命令將會返回一個錯誤。
GEOHASH:GEOHASH key member [member …],返回一個或多個位置元素的標準Geohash值,它可以在http://geohash.org/使用。查詢例子:http://geohash.org/sqdtr74hyu0.(可以通過谷歌了解Geohash原理,或者戳Geohash基本原理:https://www.cnblogs.com/tgzhu/p/6204173.html)。
GEOPOS:GEOPOS key member [member …],從key裡返回所有給定位置元素的位置(經度和緯度)。
GEODIST:GEODIST key member1 member2 [unit],返回兩個給定位置之間的距離。GEODIST命令在計算距離時會假設地球為完美的球形。在極限情況下,這一假設最大會造成0.5%的誤差。
指定單位的參數unit必須是以下單位的其中一個:
m 表示單位為米(默認)。
km 表示單位為千米。
mi 表示單位為英裡。
ft 表示單位為英尺。
GEORADIUS:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count],以給定的經緯度為中心, 返回鍵包含的位置元素當中, 與中心的距離不超過給定最大距離的所有位置元素。這個命令可以查詢某城市的周邊城市群。
GEORADIUSBYMEMBER:GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count],這個命令和GEORADIUS命令一樣,都可以找出位於指定範圍內的元素,但是GEORADIUSBYMEMBER的中心點是由給定的位置元素決定的,而不是像 GEORADIUS那樣,使用輸入的經度和緯度來決定中心點。
指定成員的位置被用作查詢的中心。
GEO的6個命令用法示例如下:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
redis> GEOHASH Sicily Palermo Catania
1) "sqc8b49rny0"
2) "sqdtr74hyu0"
redis> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.361389338970184"
2) "38.115556395496299"
2) 1) "15.087267458438873"
2) "37.50266842333162"
3) (nil)
redis> GEODIST Sicily Palermo Catania
"166274.15156960039"
redis> GEORADIUS Sicily 15 37 100 km
1) "Catania"
redis> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"
redis> GEORADIUSBYMEMBER Sicily Agrigento 100 km
1) "Agrigento"
2) "Palermo"