原文出自公眾號:阿飛JAVAer
原文鏈接:https://mp.weixin.qq.com/s/p30zjmN07lnO7U6KbVtarg
推薦閱讀:互聯(lián)網(wǎng)公司面試必問的redis相關(guān)高頻題庫文檔
平常我們我接觸最多的是5個(gè)入門級數(shù)據(jù)結(jié)構(gòu):String,Hash,List,Set,Sorted Set。本文介紹3個(gè)高級數(shù)據(jù)結(jié)構(gòu):Bitmaps,Hyperloglogs,GEO。
Bitmaps
bitmaps不是一個(gè)真實(shí)的數(shù)據(jù)結(jié)構(gòu)。而是String類型上的一組面向bit操作的集合。由于strings是二進(jìn)制安全的blob,并且它們的最大長度是512m,所以bitmaps能最大設(shè)置2^32個(gè)不同的bit。
bit操作被分為兩組:
- 恒定時(shí)間的單個(gè)bit操作,例如把某個(gè)bit設(shè)置為0或者1?;蛘攉@取某bit的值。
- 對一組bit的操作。例如給定范圍內(nèi)bit統(tǒng)計(jì)(例如人口統(tǒng)計(jì))。
Bitmaps的最大優(yōu)點(diǎn)就是存儲(chǔ)信息時(shí)可以節(jié)省大量的空間。例如在一個(gè)系統(tǒng)中,不同的用戶被一個(gè)增長的用戶ID表示。40億(2^32=4*1024*1024*1024≈40億)用戶只需要512M內(nèi)存就能記住某種信息,例如用戶是否登錄過。
Bits設(shè)置和獲取通過SETBIT 和GETBIT 命令,用法如下:
SETBIT key offset valueGETBIT 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ù)是位編號,第二個(gè)參數(shù)是這個(gè)位的值,只能是0或者1。如果bit地址超過當(dāng)前string長度,會(huì)自動(dòng)增大string。
GETBIT命令指示返回指定位置bit的值。超過范圍(尋址地址在目標(biāo)key的string長度以外的位)的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一般的使用場景:
- 各種實(shí)時(shí)分析.
- 存儲(chǔ)與對象ID關(guān)聯(lián)的節(jié)省空間并且高性能的布爾信息.
例如,想象一下你想知道訪問你的網(wǎng)站的用戶的最長連續(xù)時(shí)間。你開始計(jì)算從0開始的天數(shù),就是你的網(wǎng)站公開的那天,每次用戶訪問網(wǎng)站時(shí)通過SETBIT命令設(shè)置bit為1,可以簡單的用當(dāng)前時(shí)間減去初始時(shí)間并除以3600*24(結(jié)果就是你的網(wǎng)站公開的第幾天)當(dāng)做這個(gè)bit的位置。
這種方法對于每個(gè)用戶,都有存儲(chǔ)每天的訪問信息的一個(gè)很小的string字符串。通過BITCOUN就能輕易統(tǒng)計(jì)某個(gè)用戶連續(xù)訪問網(wǎng)站的天數(shù)。另外通過調(diào)用BITPOS命令,或者客戶端獲取并分析這個(gè)bitmap,就能計(jì)算出最長停留時(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)相對應(yīng)的內(nèi)存,取而代之,使用的內(nèi)存一直恒定不變。最壞的情況下只需要12k,就可以計(jì)算接近2^64個(gè)不同元素的基數(shù)?;蛘呷绻腍yperLogLog(我們從現(xià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è)使用場景就是計(jì)算用戶每天在搜索框中執(zhí)行的唯一查詢,即搜索頁面UV統(tǒng)計(jì)。而Bitmaps則用于判斷某個(gè)用戶是否訪問過搜索頁面。這是它們用法的不同。
GEO
Redis的GEO特性在 Redis3.2版本中推出,這個(gè)功能可以將用戶給定的地理位置(經(jīng)度和緯度)信息儲(chǔ)存起來,并對這些信息進(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)橥昝赖那蛐?。在極限情況下,這一假設(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"