如何使用Redis存儲圖的聯(lián)通關(guān)系

問題描述

一張圖由若干節(jié)點(diǎn)和連接節(jié)點(diǎn)的組成。本文考慮如何利用Redis保存所有節(jié)點(diǎn)和邊的信息,并且支持給定任意節(jié)點(diǎn)晴玖,查詢出與其聯(lián)通的所有節(jié)點(diǎn)晶默。所謂聯(lián)通谨娜,指的是兩個節(jié)點(diǎn)之間一定有一條若干條邊組成的路徑。

如上需求可以使用專門的圖數(shù)據(jù)庫(如neo4j)進(jìn)行實(shí)現(xiàn)磺陡。但實(shí)際上趴梢,只要進(jìn)行恰當(dāng)?shù)脑O(shè)計(jì),并結(jié)合一些設(shè)定币他,使用Redis也可以實(shí)現(xiàn)如上需求坞靶。

節(jié)點(diǎn)信息存儲方法

首先,我們需要用到Redis的散列類型來存儲節(jié)點(diǎn)的信息圆丹。key為節(jié)點(diǎn)的唯一標(biāo)識id(以下稱為節(jié)點(diǎn)id)滩愁,value為散列表,保存節(jié)點(diǎn)的各種信息辫封。

如下是一個簡單的例子硝枉,假設(shè)有三個節(jié)點(diǎn),id為1倦微,2妻味,3,4欣福,5责球。代表五個人,每個人都有姓名,年齡雏逾,職業(yè)三個屬性嘉裤,則每個人的數(shù)據(jù)的存儲方式如下(以id為1的人為例):

hset person:1 name mike
hset person:1 age 23
hset person:1 profession engineer

節(jié)點(diǎn)聯(lián)通關(guān)系存儲方法

使用Redis的集合類型表示節(jié)點(diǎn)之間的聯(lián)通關(guān)系。注意栖博,這里拋棄掉了邊的信息屑宠,僅保留聯(lián)通關(guān)系。即拋棄掉了兩個節(jié)點(diǎn)聯(lián)通的具體路徑仇让。

假設(shè)存在如下的五個人有如下的朋友(聯(lián)通)關(guān)系:

1 -- 2, 2 -- 3, 4 -- 5, 5 -- 2

我們希望通過特定的算法典奉,當(dāng)這四個聯(lián)通關(guān)系依次入庫后,redis數(shù)據(jù)庫中有如下的存儲結(jié)構(gòu):

friend:1 [1, 2, 3, 4, 5]
friend:2 [1]
friend:3 [1]
friend:4 [1]
friend:5 [1]

從上面四個聯(lián)通關(guān)系可以看出丧叽,實(shí)際上1卫玖,2,3踊淳,4假瞬,5是彼此聯(lián)通的,那么就構(gòu)成了一個聯(lián)通圖嚣崭。每一個聯(lián)通圖笨触,需要按照一定原則選舉出一個代表節(jié)點(diǎn)。該節(jié)點(diǎn)的關(guān)系鍵保存完成的聯(lián)通成員信息雹舀。而其余成員節(jié)點(diǎn)的關(guān)系鍵均指向該代表性節(jié)點(diǎn)芦劣。以上面的例子為例,節(jié)點(diǎn)的選舉原則是選取聯(lián)通圖中編號最小的節(jié)點(diǎn)说榆。則1為代表性節(jié)點(diǎn)虚吟,則friend:1中保存了完整的聯(lián)通成員信息。節(jié)點(diǎn)2-5則僅保存與1聯(lián)通签财。這樣保存的目的是防止數(shù)據(jù)的冗余存儲串慰。聯(lián)通圖假設(shè)有n個成員,則需要的存儲空間為2*n-1唱蒸。

為了達(dá)到上面的存儲效果邦鲫,需要在入庫時對關(guān)系鍵進(jìn)行一些調(diào)整操作,具體步驟如下:

步驟1 獲取關(guān)聯(lián)關(guān)系的左右兩個節(jié)點(diǎn)神汹,檢查是否存在節(jié)點(diǎn)的關(guān)系鍵庆捺,若沒有則創(chuàng)建關(guān)系鍵并將自身加入關(guān)系集合

sadd friend:1 1 
sadd friend:2 2 

步驟2 針對每個節(jié)點(diǎn)的關(guān)系鍵,獲取其關(guān)聯(lián)的所有節(jié)點(diǎn)中id最小的節(jié)點(diǎn)(注意屁魏,若使用有序集合滔以,最小節(jié)點(diǎn)將更方便求解,此處以普通集合為例)氓拼。如下為偽代碼你画,混合了redis命令和java的賦值命令

set1 =  smems friend:1 //將friend:1中的集合保存在set1
set2 =  smems friend:2
std1 = min(set1)//取set1中最小的元素
std2 = min(set2)

步驟3 找出std1和std2的較小值和較大值

stdMin = std1>std2? std2:std1
stdMax = std1>std2? std1:std2

步驟4 若stdMin==stdMax則無需進(jìn)行任何操作抵碟,否則將stdMax中的所有元素都加入到stdMin中,且stdMax中的元素對應(yīng)的關(guān)系鍵全部設(shè)置成stdMin

members = smems friend:stdMax
//stdMax中的元素對應(yīng)的關(guān)系鍵全部設(shè)置成stdMin
for(String member:members){
    del friend:member
    sadd friend:member stdMin
}
//將friend:stdMin和friend:stdMax中的元素合并坏匪,并將結(jié)果放入stdMin
smerge friend:stdMin friend:stdMin friend:stdMax

每一個關(guān)聯(lián)關(guān)系的入庫都需要如上四步拟逮。如果存在多線程入庫的情況,需要將其形成一個事務(wù)處理适滓。下面以1 -- 2, 2 -- 3, 4 -- 5, 5 -- 2的入庫順序逐步進(jìn)行推演:

入庫1 -- 2

步驟1后為:

friend:1 [1]
friend:2 [2]

步驟2: 得到1中元素最小為1唱歧,2中元素最小為2
步驟3: stdMin=1,stdMax=2
步驟4:將2中元素歸到1粒竖,并設(shè)置2中元素的關(guān)系鍵內(nèi)容為1

friend:1 [1,2]
friend:2 1

入庫2 -- 3

步驟1后為(創(chuàng)建了3的關(guān)系鍵):

friend:1 [1,2]
friend:2 [1]
friend:3 [3]

步驟2: 得到2中元素最小為1,3中元素最小為3
步驟3: stdMin=1几于,stdMax=3
步驟4:將3中元素歸到1蕊苗,并設(shè)置3中元素的關(guān)系鍵內(nèi)容為1

friend:1 [1,2,3]
friend:2 [1]
friend:3 [1]

入庫4 -- 5

步驟1后為(創(chuàng)建了4和5的關(guān)系鍵):

friend:1 [1,2,3]
friend:2 [1]
friend:3 [1]
friend:4 [4]
friend:5 [5]

步驟2: 得到4中元素最小為4,5中元素最小為5
步驟3: stdMin=4沿彭,stdMax=5
步驟4:將4中元素歸到5朽砰,并設(shè)置4中元素的關(guān)系鍵內(nèi)容為5

friend:1 [1,2,3]
friend:2 [1]
friend:3 [1]
friend:4 [4,5]
friend:5 [4]

入庫5 -- 2

步驟1后為(無變化):

friend:1 [1,2,3]
friend:2 [1]
friend:3 [1]
friend:4 [4,5]
friend:5 [4]

步驟2: 得到5中元素最小為4,2中元素最小為1
步驟3: stdMin=1喉刘,stdMax=4
步驟4:將4中元素歸到1瞧柔,并設(shè)置4中元素的關(guān)系鍵內(nèi)容為1

friend:1 [1,2,3,4,5]
friend:2 [1]
friend:3 [1]
friend:4 [1]
friend:5 [1]

聯(lián)通關(guān)系的獲取方法

基于如上構(gòu)造的redis數(shù)據(jù)存儲,可以方便的給定任意一個節(jié)點(diǎn)睦裳,找出與其聯(lián)通的所有節(jié)點(diǎn)造锅。僅需要如下兩個步驟

  1. 獲取該節(jié)點(diǎn)的關(guān)系鍵,若不存在則返回空值
  2. 若關(guān)系鍵存在廉邑,則獲取其值哥蔚。若值中包含鍵id本身(如friend:1對應(yīng)的集合中包含1),則直接返回值蛛蒙。否則返回值中id對應(yīng)的關(guān)系鍵中的內(nèi)容(如friend:4的集合中沒有4糙箍,僅有1,則返回friend:1對應(yīng)的集合)牵祟。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末深夯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诺苹,更是在濱河造成了極大的恐慌咕晋,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筝尾,死亡現(xiàn)場離奇詭異捡需,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)筹淫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門站辉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呢撞,“玉大人,你說我怎么就攤上這事饰剥∈庀迹” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長际乘。 經(jīng)常有香客問我惯退,道長,這世上最難降的妖魔是什么祝钢? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮若厚,結(jié)果婚禮上拦英,老公的妹妹穿的比我還像新娘。我一直安慰自己测秸,他們只是感情好疤估,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著霎冯,像睡著了一般铃拇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沈撞,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天慷荔,我揣著相機(jī)與錄音,去河邊找鬼关串。 笑死拧廊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的晋修。 我是一名探鬼主播吧碾,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼墓卦!你這毒婦竟也來了倦春?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤落剪,失蹤者是張志新(化名)和其女友劉穎睁本,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忠怖,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呢堰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凡泣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枉疼。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡皮假,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出骂维,到底是詐尸還是另有隱情惹资,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布航闺,位于F島的核電站褪测,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏潦刃。R本人自食惡果不足惜侮措,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乖杠。 院中可真熱鬧萝毛,春花似錦、人聲如沸滑黔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽略荡。三九已至,卻和暖如春歉胶,著一層夾襖步出監(jiān)牢的瞬間汛兜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工通今, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粥谬,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓辫塌,卻偏偏與公主長得像漏策,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子臼氨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1 序 2016年6月25日夜掺喻,帝都,天下著大雨储矩,拖著行李箱和同學(xué)在校門口照了最后一張合照感耙,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,108評論 0 12
  • 1 Redis介紹1.1 什么是NoSql為了解決高并發(fā)即硼、高可擴(kuò)展、高可用屡拨、大數(shù)據(jù)存儲問題而產(chǎn)生的數(shù)據(jù)庫解決方...
    克魯?shù)吕?/span>閱讀 5,304評論 0 36
  • 我踩云踏風(fēng)只酥,奔向一縷闌珊褥实, 我捧月摘星,編織你的心田层皱。 任性的思念有苦有甜性锭, 放任的情感無垠無邊。 今天叫胖,我又回到...
    填空師閱讀 302評論 0 0
  • 文·老夫子 / 圖·360圖片 距離有遠(yuǎn)有近草冈,只是屬于你。 夢瓮增,此般高不可攀怎棱,像顆天上的星。 輕輕的念著你绷跑,名字像...
    流茵小筑工作室閱讀 425評論 0 1
  • 感恩: 昨天晚上很多義工住宿拳恋,主動詢問需不需要加毛毯,先開了空調(diào)砸捏,先把洗澡的水溫調(diào)好谬运,人家提出的要求我都盡量滿...
    實(shí)無所得閱讀 327評論 0 0