spring-boot-neo4j
spring-boot集成neo4j圖形數(shù)據(jù)庫芽狗,并實(shí)現(xiàn)簡單的節(jié)點(diǎn)創(chuàng)建和查詢
這個(gè)項(xiàng)目是大二時(shí)數(shù)據(jù)庫的課程項(xiàng)目 現(xiàn)在稍微寫點(diǎn)readme 發(fā)布一下
github地址 https://github.com/YULuoOo/spring-boot-neo4j
簡書博客地址 http://www.reibang.com/u/35c3b7d55046
關(guān)于neo4j
Neo4j是一個(gè)網(wǎng)絡(luò)——面向網(wǎng)絡(luò)的數(shù)據(jù)庫——也就是說硝烂,它是一個(gè)嵌入式的焦除、基于磁盤的、具備完全的事務(wù)特性的Java持久化引擎麦锯,但是它將結(jié)構(gòu)化數(shù)據(jù)存儲在網(wǎng)絡(luò)上而不是表中晒屎。網(wǎng)絡(luò)(從數(shù)學(xué)角度叫做圖)是一個(gè)靈活的數(shù)據(jù)結(jié)構(gòu),可以應(yīng)用更加敏捷和快速的開發(fā)模式镇眷。Neo4j是一個(gè)高性能的圖引擎,該引擎具有成熟和健壯的數(shù)據(jù)庫的所有特性翎嫡。程序員工作在一個(gè)面向?qū)ο蟮那范㈧`活的網(wǎng)絡(luò)結(jié)構(gòu)下而不是嚴(yán)格、靜態(tài)的表中——但是他們可以享受到具備完全的事務(wù)特性、企業(yè)級的數(shù)據(jù)庫的所有好處具伍。在該模型中翅雏,以“節(jié)點(diǎn)空間”來表達(dá)領(lǐng)域數(shù)據(jù)——相對于傳統(tǒng)的模型表、行和列來說人芽,節(jié)點(diǎn)空間是很多節(jié)點(diǎn)望几、關(guān)系和屬性(鍵值對)構(gòu)成的網(wǎng)絡(luò)。關(guān)系是第一級對象啼肩,可以由屬性來注解橄妆,而屬性則表明了節(jié)點(diǎn)交互的上下文。
本次的實(shí)現(xiàn)我們看重的是它在涉及到查詢遍歷兩節(jié)點(diǎn)關(guān)系上表現(xiàn)出的卓越的輕巧快速祈坠,首先害碾,圖的遍歷相較于兩個(gè)表的遍歷要更加有效率,其次赦拘,在試用neo4j的過程中我們可以相比mysql更加容易地修改它的屬性慌随,好符合不斷考慮修改的數(shù)據(jù)庫設(shè)計(jì)。還有躺同,它能夠容納數(shù)據(jù)的量多達(dá)幾十億個(gè)節(jié)點(diǎn)和上百億關(guān)系阁猜,能夠符合社交網(wǎng)絡(luò)的龐大用戶量和錯(cuò)綜復(fù)雜的用戶和其他節(jié)點(diǎn)關(guān)系的要求。對于之前僅接觸過mysql之類關(guān)系數(shù)據(jù)庫的我們來說也是一次新的嘗試蹋艺。
需求分析
功能需求
- 給用戶提供一個(gè)與相同愛好者交流聯(lián)系的平臺剃袍,系統(tǒng)會通過你的標(biāo)簽,對哪些更加有興趣捎谨,經(jīng)過好友推薦的算法自動(dòng)推薦更多與你興趣相投民效,志同道合的人。同時(shí)涛救,用戶可以知道你關(guān)注的人對哪些方面感興趣畏邢,以及感興趣程度,還可以看到他所關(guān)注的人检吆,進(jìn)一步擴(kuò)展社交圈子舒萎,與更多的人交流來往,了解更多的知識蹭沛,發(fā)現(xiàn)更多自己以往不了解的趣事臂寝。
實(shí)現(xiàn)功能:
- 顯示關(guān)注、被關(guān)注用戶
- 添加自定義標(biāo)簽摊灭,設(shè)定權(quán)值
- 通過自定義標(biāo)簽顯示愛好重合的同好
- 通過用戶名或者標(biāo)簽搜索用戶
- 通過標(biāo)簽和權(quán)值推薦最適合該用戶的好友
- 顯示關(guān)注咆贬、愛好、和被關(guān)注最多的用戶
- 顯示兩個(gè)用戶的共同關(guān)注
- 顯示兩個(gè)用戶之間的最短路徑
性能需求
- 測試過程中斟或,插入10w節(jié)點(diǎn)的情況下對于每個(gè)tab的關(guān)注、被關(guān)注的異步刷新(數(shù)據(jù)庫同時(shí)進(jìn)行查詢操作)響應(yīng)快集嵌,沒有出現(xiàn)體感的延遲萝挤。
- neo4j的算法遍歷加快查詢的速度
數(shù)據(jù)庫設(shè)計(jì)(非關(guān)系型)
這種社交網(wǎng)絡(luò)的系統(tǒng)御毅,用關(guān)系型數(shù)據(jù)庫實(shí)現(xiàn)起來的話,會很麻煩怜珍,而且即使成功實(shí)現(xiàn)了端蛆,性能也很差,于是想到用非關(guān)系型數(shù)據(jù)庫酥泛,其中圖數(shù)據(jù)庫最合適今豆,利用neo4j數(shù)據(jù)庫實(shí)現(xiàn)社交網(wǎng)絡(luò)的設(shè)計(jì)肖爵。以用戶作為節(jié)點(diǎn)(節(jié)點(diǎn)的屬性描述了用戶的個(gè)人信息包括用戶名惋砂、年齡、性別)另外興趣也作為節(jié)點(diǎn)存在忍抽,當(dāng)然了用戶節(jié)點(diǎn)和興趣節(jié)點(diǎn)之間有所區(qū)分捶索,關(guān)系存在于用戶之間和也存在于用戶與興趣之間插掂,用戶可以通過他們分別與興趣之間的關(guān)聯(lián)度來建立他們之間的關(guān)系,用戶之間還可以通過他們共同的好友來建立關(guān)系腥例。
技術(shù)棧
Spring Boot(Intelij)
Spring Boot(Intelij)
Thymeleaf
Avalonjs
Bootstrap辅甥、jQuery、ajax
數(shù)據(jù)庫
節(jié)點(diǎn)部分:
用戶User:{id,name,age,sex,password,address,sign}
標(biāo)簽Tag:{name}
關(guān)系部分:
關(guān)注Follow:{time}
喜歡Like:{count}
以下是只包括用戶節(jié)點(diǎn)的圖燎竖,能夠顯示出復(fù)雜的人際關(guān)系
人際關(guān)系圖
接下來是整個(gè)關(guān)系網(wǎng)的全貌
可以看出璃弄,要找到和自己共有一個(gè)tag/user的user,只需要通過自己的關(guān)系箭頭找到對應(yīng)的tag/user构回,再以對方為起點(diǎn)遍歷就可以了夏块。
以rain為標(biāo)簽的所有用戶
下圖為愛好的權(quán)值的應(yīng)用,用來做好友推薦捐凭,可以看到LIKE了相同愛好的用戶拨扶,以及LIKE關(guān)系的值,代表喜愛程度茁肠。
以rain為標(biāo)簽的所有用戶
Spring boot內(nèi)實(shí)體層患民、控制層、DAO層垦梆。
實(shí)體層中匹颤,有的是NodeEntity 有的是 relationentity,都要對應(yīng)到數(shù)據(jù)庫里的實(shí)現(xiàn)托猩。
在repository類中印蓖,寫cypher語句。
系統(tǒng)的框架邏輯:
從前端采用采用ajax訪問controller接口京腥。Controller內(nèi)部使用Respository的方法進(jìn)行數(shù)據(jù)庫交互赦肃。
用戶關(guān)系和節(jié)點(diǎn)顯示:
界面內(nèi),標(biāo)簽頁的每個(gè)tab都屬于一個(gè)獨(dú)立的mscontroller,在js文件中包含特定ms-controller的內(nèi)容物他宛,包括其id船侧,自定義屬性和自定義函數(shù),用戶的follow關(guān)系和like關(guān)系的界面顯示是通過avalonjs的ms-controller內(nèi)的變量list厅各,類似android里面的listview镜撩,這里設(shè)定為當(dāng)按下按鈕時(shí)調(diào)用ms-click里面觸發(fā)特定函數(shù)@函數(shù)名,將屬性里保存的list中該元素的NodeId取出例如{{user.nodeId}}队塘。隨后ms-controller內(nèi)函數(shù)中發(fā)出ajax請求發(fā)到controller的特定地址袁梗,通過controller中Userrepository、FollowRepository憔古、RetrieveRepository等等來進(jìn)行數(shù)據(jù)庫的信息交換和查詢遮怜,各自返回list重新存入到對應(yīng)ms-controller的屬性的list中,就做到了一次的異步刷新投放。Window-onload和每次點(diǎn)擊按鈕奈泪,或者切換標(biāo)簽的時(shí)候,都可能進(jìn)行異步刷新灸芳,這樣能有效保證不發(fā)生反應(yīng)延遲信息不對的情況涝桅。
效果如下,使用ms-for
標(biāo)簽節(jié)點(diǎn)(或者說關(guān)系)顯示
實(shí)現(xiàn)過程
過程概述
- 經(jīng)由組長(本人)提出的通過nosql neo4j來進(jìn)行社交網(wǎng)絡(luò)實(shí)現(xiàn)這一想法作為開頭烙样,選擇spring boot作為框架來進(jìn)行開發(fā)
- 配置成功neo4j數(shù)據(jù)庫以后確定項(xiàng)目的大致方向冯遂,決定首先實(shí)現(xiàn)用戶注冊存入數(shù)據(jù)庫后登錄,先實(shí)現(xiàn)用戶之間互相關(guān)注的功能谒获。
- 將基礎(chǔ)界面寫出蛤肌,寫出實(shí)體類,實(shí)現(xiàn)數(shù)據(jù)庫內(nèi)存取基礎(chǔ)的關(guān)注批狱。
- 實(shí)現(xiàn)資料的修改以及網(wǎng)頁上直接刷新資料的顯示
- 考慮大批量導(dǎo)入csv文件中的用戶數(shù)據(jù)測試數(shù)據(jù)庫的查詢性能裸准,編寫隨機(jī)生成用戶名、年齡性別的函數(shù)和關(guān)系函數(shù)赔硫,自動(dòng)循環(huán)寫入txt文件再轉(zhuǎn)成csv導(dǎo)入炒俱。
- 實(shí)現(xiàn)標(biāo)簽類的顯示和增改,以及通過標(biāo)簽類對用戶的查詢
- 考慮更進(jìn)一步的算法爪膊,比如用戶之間的最短路徑权悟、用戶的共同關(guān)注,將其顯示
- 更加完善前后端的交互
遇到的問題及解決
Springboot-neo4j框架問題推盛,花了幾周配置環(huán)境以及熟悉springboot開發(fā)框架峦阁。
Neo4j使用cypher查詢語言,需要對這個(gè)語言進(jìn)行學(xué)習(xí)耘成。
在處理圖數(shù)據(jù)庫的數(shù)據(jù)時(shí)榔昔,遇到數(shù)據(jù)類型的問題驹闰。比如一個(gè)查詢要返回既有節(jié)點(diǎn)類型的數(shù)據(jù),又有關(guān)系類型的數(shù)據(jù)撒会。我們的解決方法是疮方,包裝一個(gè)類,里面既有node類茧彤,又有relation類。
Thymeleaf中導(dǎo)入css文件沒有效果的問題疆栏,后來發(fā)現(xiàn)必須要是非常特定的格式并且在properties里面寫了特定路徑才能夠檢測到曾掂,解決;
Ajax無法發(fā)出請求問題壁顶,起初發(fā)現(xiàn)未被識別,將$改成jQuery后解決若专;
Div無法居中许蓖、寬度無法自由設(shè)定問題,發(fā)現(xiàn)是由于導(dǎo)入的css文件有沖突所致调衰,利用內(nèi)部樣式表更加優(yōu)先這一特點(diǎn)暫時(shí)解決膊爪;
無法通過controller return String類來重定向,發(fā)現(xiàn)當(dāng)時(shí)是restController并且沒有使用返回ModelandView這一方法嚎莉,修改成Controller或者返回存著地址的mav米酬,解決;
從session中存的屬性通過getAttribute獲取后趋箩,在session未過期就出現(xiàn)了nullptr獲取不到session中user實(shí)體的問題赃额,每一次取出后都進(jìn)行一次存,
無法通過jQuery獲取到th:each或者ms-for里面每一個(gè)元素叫确,而無法訪問元素的屬性nodeId跳芳,無法傳值也無法增刪改的問題,通過直接ms-click設(shè)置對應(yīng)函數(shù)即可解決竹勉;
FollowRepository中的雙向關(guān)注實(shí)現(xiàn)飞盆,發(fā)現(xiàn)使用雙箭頭<-[r]->會導(dǎo)致只要有其中一個(gè)關(guān)系滿足就會被查出來的情況,后來發(fā)現(xiàn)能夠通過(n)-[r]->(m)-[r]->(n)這個(gè)語句解決;
系統(tǒng)中的亮點(diǎn)
路徑算法
```
match p = shortestPath((a:User{name:{name3}})-[*..15]->(b:User{name:{name4}}))
RETURN p
```
共同好友搜索算法
```
match (a:User)-[:Follow]->(c)<-[:Follow]-(b:User)
where a.name={name1} and b.name={name2}
return c
```
好友推薦算法
Match(n1:User)-[r1:Like]->(t1:Tag),(n2:User)-[r2:Like]->(t1)
where n1.name='imyonzmo' with count(n2.name)
as num,sqrt(sum((toInt(r1.count)-toInt(r2.count))^2)) as aaa,n1,n2,r1,r2,t1
return n1,aaa,n2,r1,r2,t1,num order by num,aaa limit 10