平常我們我接觸最多的是5個(gè)入門級(jí)數(shù)據(jù)結(jié)構(gòu):String,Hash,List,Set,Sorted Set。本文介紹3個(gè)高級(jí)數(shù)據(jù)結(jié)構(gòu):Bitmaps,Hyperloglogs,GEO。
Bitmaps
bitmaps不是一個(gè)真實(shí)的數(shù)據(jù)結(jié)構(gòu)。而是String類型上的一組面向bit操作的集合。由于strings是二進(jìn)制安全的blob,并且它們的最大長(zhǎng)度是512m,所以bitmaps能最大設(shè)置2^32個(gè)不同的bit。
bit操作被分為兩組:
- 恒定時(shí)間的單個(gè)bit操作,例如把某個(gè)bit設(shè)置為0或者1。或者獲取某bit的值。
- 對(duì)一組bit的操作。例如給定范圍內(nèi)bit統(tǒng)計(jì)(例如人口統(tǒng)計(jì))。
Bitmaps的最大優(yōu)點(diǎn)就是存儲(chǔ)信息時(shí)可以節(jié)省大量的空間。例如在一個(gè)系統(tǒng)中,不同的用戶被一個(gè)增長(zhǎng)的用戶ID表示。40億(2^32=4*1024*1024*1024≈40億
)用戶只需要512M內(nèi)存就能記住某種信息,例如用戶是否登錄過。
Bits設(shè)置和獲取通過SETBIT 和GETBIT 命令,用法如下:
SETBIT key offset value
GETBIT key offset
使用實(shí)例:
127.0.0.1:6380> setbit dupcheck 10 1
(integer) 0
127.0.0.1:6380> getbit dupcheck 10
(integer) 1
SETBIT命令第一個(gè)參數(shù)是位編號(hào),第二個(gè)參數(shù)是這個(gè)位的值,只能是0或者1。如果bit地址超過當(dāng)前string長(zhǎng)度,會(huì)自動(dòng)增大string。
GETBIT命令指示返回指定位置bit的值。超過范圍(尋址地址在目標(biāo)key的string長(zhǎng)度以外的位)的GETBIT總是返回0。三個(gè)操作bits組的命令如下:
- BITOP 執(zhí)行兩個(gè)不同string的位操作.,包括AND,OR,XOR和NOT.
- BITCOUNT 統(tǒng)計(jì)位的值為1的數(shù)量。
- BITPOS 尋址第一個(gè)為0或者1的bit的位置(尋址第一個(gè)為1的bit的位置:bitpos dupcheck 1; 尋址第一個(gè)為0的bit的位置:bitpos dupcheck 0).
bitmaps一般的使用場(chǎng)景:
- 各種實(shí)時(shí)分析.
- 存儲(chǔ)與對(duì)象ID關(guān)聯(lián)的節(jié)省空間并且高性能的布爾信息.
例如,想象一下你想知道訪問你的網(wǎng)站的用戶的最長(zhǎng)連續(xù)時(shí)間。你開始計(jì)算從0開始的天數(shù),就是你的網(wǎng)站公開的那天,每次用戶訪問網(wǎng)站時(shí)通過SETBIT命令設(shè)置bit為1,可以簡(jiǎn)單的用當(dāng)前時(shí)間減去初始時(shí)間并除以3600*24(結(jié)果就是你的網(wǎng)站公開的第幾天)當(dāng)做這個(gè)bit的位置。
這種方法對(duì)于每個(gè)用戶,都有存儲(chǔ)每天的訪問信息的一個(gè)很小的string字符串。通過BITCOUN就能輕易統(tǒng)計(jì)某個(gè)用戶歷史訪問網(wǎng)站的天數(shù)。另外通過調(diào)用BITPOS命令,或者客戶端獲取并分析這個(gè)bitmap,就能計(jì)算出最長(zhǎng)停留時(shí)間。
HyperLogLogs
HyperLogLog是用于計(jì)算唯一事物的概率數(shù)據(jù)結(jié)構(gòu)(從技術(shù)上講,這被稱為估計(jì)集合的基數(shù))。如果統(tǒng)計(jì)唯一項(xiàng),項(xiàng)目越多,需要的內(nèi)存就越多。因?yàn)樾枰涀∵^去已經(jīng)看過的項(xiàng),從而避免多次統(tǒng)計(jì)這些項(xiàng)。
然而,有一組算法可以交換內(nèi)存以獲得精確度:在redis的實(shí)現(xiàn)中,您使用標(biāo)準(zhǔn)錯(cuò)誤小于1%的估計(jì)度量結(jié)束。這個(gè)算法的神奇在于不再需要與需要統(tǒng)計(jì)的項(xiàng)相對(duì)應(yīng)的內(nèi)存,取而代之,使用的內(nèi)存一直恒定不變。最壞的情況下只需要12k,就可以計(jì)算接近2^64個(gè)不同元素的基數(shù)。或者如果您的HyperLogLog(我們從現(xiàn)在開始簡(jiǎn)稱它為HLL)已經(jīng)看到的元素非常少,則需要的內(nèi)存要要少得多。
在redis中HLL是一個(gè)不同的數(shù)據(jù)結(jié)構(gòu),它被編碼成Redis字符串。因此可以通過調(diào)用GET命令序列化一個(gè)HLL,也可以通過調(diào)用SET命令將其反序列化到redis服務(wù)器。
HLL的API類似使用SETS數(shù)據(jù)結(jié)構(gòu)做相同的任務(wù),SETS結(jié)構(gòu)中,通過SADD命令把每一個(gè)觀察的元素添加到一個(gè)SET集合,用SCARD命令檢查SET集合中元素的數(shù)量,集合里的元素都是唯一的,已經(jīng)存在的元素不會(huì)被重復(fù)添加。
而使用HLL時(shí)并不是真正添加項(xiàng)到HLL中(這一點(diǎn)和SETS結(jié)構(gòu)差異很大),因?yàn)镠LL的數(shù)據(jù)結(jié)構(gòu)只包含一個(gè)不包含實(shí)際元素的狀態(tài),API是一樣的:
- PFADD命令用于添加一個(gè)新元素到統(tǒng)計(jì)中。
- PFCOUNT命令用于獲取到目前為止通過PFADD命令添加的唯一元素個(gè)數(shù)近似值。
- PFMERGE命令執(zhí)行多個(gè)HLL之間的聯(lián)合操作。
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數(shù)據(jù)結(jié)構(gòu)的一個(gè)使用場(chǎng)景就是計(jì)算用戶每天在搜索框中執(zhí)行的唯一查詢,即搜索頁(yè)面UV統(tǒng)計(jì)。而Bitmaps則用于判斷某個(gè)用戶是否訪問過搜索頁(yè)面。這是它們用法的不同。
GEO
Redis的GEO特性在 Redis3.2版本中推出,這個(gè)功能可以將用戶給定的地理位置(經(jīng)度和緯度)信息儲(chǔ)存起來,并對(duì)這些信息進(jìn)行操作。GEO相關(guān)命令只有6個(gè):
-
GEOADD:GEOADD key longitude latitude member [longitude latitude member ...],將指定的地理空間位置(緯度、經(jīng)度、名稱)添加到指定的key中。例如:
GEOADD city 113.501389 22.405556 shenzhen
;
經(jīng)緯度具體的限制,由EPSG:900913/EPSG:3785/OSGEO:41001規(guī)定如下:
有效的經(jīng)度從-180度到180度。
有效的緯度從-85.05112878度到85.05112878度。
當(dāng)坐標(biāo)位置超出上述指定范圍時(shí),該命令將會(huì)返回一個(gè)錯(cuò)誤。
GEOHASH:GEOHASH key member [member ...],返回一個(gè)或多個(gè)位置元素的標(biāo)準(zhǔn)Geohash值,它可以在http://geohash.org/使用。查詢例子:
http://geohash.org/sqdtr74hyu0
.(可以通過谷歌了解Geohash原理,或者戳Geohash基本原理:https://www.cnblogs.com/tgzhu/p/6204173.html)。GEOPOS:GEOPOS key member [member ...],從key里返回所有給定位置元素的位置(經(jīng)度和緯度)。
GEODIST:GEODIST key member1 member2 [unit],返回兩個(gè)給定位置之間的距離。GEODIST命令在計(jì)算距離時(shí)會(huì)假設(shè)地球?yàn)橥昝赖那蛐巍T跇O限情況下,這一假設(shè)最大會(huì)造成0.5%的誤差。
指定單位的參數(shù)unit必須是以下單位的其中一個(gè):
m 表示單位為米(默認(rèn))。
km 表示單位為千米。
mi 表示單位為英里。
ft 表示單位為英尺。
GEORADIUS:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count],以給定的經(jīng)緯度為中心, 返回鍵包含的位置元素當(dāng)中, 與中心的距離不超過給定最大距離的所有位置元素。這個(gè)命令可以查詢某城市的周邊城市群。
GEORADIUSBYMEMBER:GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count],這個(gè)命令和GEORADIUS命令一樣,都可以找出位于指定范圍內(nèi)的元素,但是GEORADIUSBYMEMBER的中心點(diǎn)是由給定的位置元素決定的,而不是像 GEORADIUS那樣,使用輸入的經(jīng)度和緯度來決定中心點(diǎn)。
指定成員的位置被用作查詢的中心。
GEO的6個(gè)命令用法示例如下:
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"