動手構建地鐵關係網,實現最短路徑查詢

jstarseven發表於2020-08-31

一、前言

開啟手機‘北京地鐵’APP,輸入起始點:霍營,終點:北京南站,發現系統給我們推薦了兩條路線。
最短時間路線與最少換乘路線,並且分別給出了耗時與乘坐里程費。看到這裡,不禁開啟了靚仔疑問,假如給你地鐵站相關資料,如何構建這樣的關係網路呢?(儘量少寫程式碼,畢竟我這個人懶的不行,花最少的功夫,整最炫的效果,咦)

1.整理地鐵站點資料,處理成echarts圖表所需要的結構
2.整理地鐵站點資料,自己寫程式碼實現,能實現(好累啊...)
3.整理地鐵站點資料,匯入 Neo4j 中,點選檢視

分析:方案一,不僅要處理資料還要搞echarts樣式,算了吧。方案二,直接PASS,還是方案三省力,正好我的電腦上之前安裝過 Neo4j 圖資料庫,哈哈哈,開搞開搞!
軟體下載地址:http://doc.we-yun.com:1008/neo4j-chs
軟體安裝教程:https://www.cnblogs.com/jstarseven/p/9546555.html

Neo4j 地鐵關係網

二、資料準備

既然需要展示地鐵關係,那麼首先需要的就是北京所有地鐵站的資訊,以及站點之間的關係,距離,耗時。搜尋了一圈,最後在北京地鐵官方網站,發現了全部地鐵線路,站點名稱,站點與站點之間距離等資訊。但是缺少了具體站點與站點之間的乘車耗時,行吧,先將就著用吧!具體資料樣例如下:

Neo4j 地鐵關係網

資料來源地址:https://www.bjsubway.com/station/zjgls/#

站點關係

一共18條線路,一頓複製貼上和 Notepad++ 文字替換之後,我們得到了一個 Excel檔案,包含了所有站點之間的關係資料,如下:

Neo4j 地鐵關係網

獲取站點

複製所有站點進入Excel檔案的某一個sheet,選擇資料去重,得到所有站點名稱。

Neo4j 地鐵關係網

處理CSV

將站點關係與站點資料處理成CSV檔案格式,方便匯入 Neo4j 資料庫中,建立圖節點與關係。操作也就是 notepad++ 替換‘ ’為‘,’,另存為 .CSV 檔案,具體得到下列檔案。(因為方便 Neo4j 資料庫不同的路線顯示不同的顏色,我特地將站點關係資料拆解成了多個地鐵線的CSV檔案,如果不考慮顯示,可以一個CSV檔案,匯入站點關係即可)

Neo4j 地鐵關係網

備註:將所有CSV檔案,放入 Neo4j 安裝目錄下的 import 資料夾中(沒有就新建),如下:

Neo4j 地鐵關係網

檔案下載地址:https://files-cdn.cnblogs.com/files/jstarseven/subway.zip

三、建立地鐵關係網

Neo4j 支援匯入本地以及網路資源中的 CSV 檔案資料,並且可以從CSV檔案資料中,直接建立圖形節點以及節點關係。具體 cypher 語句,如下:

建立地鐵站點

LOAD CSV WITH HEADERS  FROM "file:///station.csv" AS line
MERGE (p:Station{id:line.id,name:line.name});

建立站點連線

LOAD CSV WITH HEADERS FROM "file:///line1.csv" AS line1
match (from1:Station{name:line1.sn}),(to1:Station{name:line1.en})
merge (from1)-[r1:一號線{jl:line1.jl,xl:line1.xl}]->(to1);

LOAD CSV WITH HEADERS FROM "file:///line2.csv" AS line2
match (from2:Station{name:line2.sn}),(to2:Station{name:line2.en})
merge (from2)-[r2:二號線{jl:line2.jl,xl:line2.xl}]->(to2);

LOAD CSV WITH HEADERS FROM "file:///line4.csv" AS line4
match (from4:Station{name:line4.sn}),(to4:Station{name:line4.en})
merge (from4)-[r4:四號線{jl:line4.jl,xl:line4.xl}]->(to4);

LOAD CSV WITH HEADERS FROM "file:///line5.csv" AS line5
match (from5:Station{name:line5.sn}),(to5:Station{name:line5.en})
merge (from5)-[r5:五號線{jl:line5.jl,xl:line5.xl}]->(to5);

LOAD CSV WITH HEADERS FROM "file:///line6.csv" AS line6
match (from6:Station{name:line6.sn}),(to6:Station{name:line6.en})
merge (from6)-[r6:六號線{jl:line6.jl,xl:line6.xl}]->(to6);

LOAD CSV WITH HEADERS FROM "file:///line7.csv" AS line7
match (from7:Station{name:line7.sn}),(to7:Station{name:line7.en})
merge (from7)-[r7:七號線{jl:line7.jl,xl:line7.xl}]->(to7);

LOAD CSV WITH HEADERS FROM "file:///line8.csv" AS line8
match (from8:Station{name:line8.sn}),(to8:Station{name:line8.en})
merge (from8)-[r8:八號線{jl:line8.jl,xl:line8.xl}]->(to8);

LOAD CSV WITH HEADERS FROM "file:///line9.csv" AS line9
match (from9:Station{name:line9.sn}),(to9:Station{name:line9.en})
merge (from9)-[r9:九號線{jl:line9.jl,xl:line9.xl}]->(to9);

LOAD CSV WITH HEADERS FROM "file:///line10.csv" AS line10
match (from10:Station{name:line10.sn}),(to10:Station{name:line10.en})
merge (from10)-[r10:十號線{jl:line10.jl,xl:line10.xl}]->(to10);

LOAD CSV WITH HEADERS FROM "file:///line13.csv" AS line13
match (from13:Station{name:line13.sn}),(to13:Station{name:line13.en})
merge (from13)-[r13:十三號線{jl:line13.jl,xl:line13.xl}]->(to13);

LOAD CSV WITH HEADERS FROM "file:///line14.csv" AS line14
match (from14:Station{name:line14.sn}),(to14:Station{name:line14.en})
merge (from14)-[r14:十四號線{jl:line14.jl,xl:line14.xl}]->(to14);

LOAD CSV WITH HEADERS FROM "file:///line15.csv" AS line15
match (from15:Station{name:line15.sn}),(to15:Station{name:line15.en})
merge (from15)-[r15:十五號線{jl:line15.jl,xl:line15.xl}]->(to15);

LOAD CSV WITH HEADERS FROM "file:///linebt.csv" AS linebt
match (frombt:Station{name:linebt.sn}),(tobt:Station{name:linebt.en})
merge (frombt)-[rbt:八通線{jl:linebt.jl,xl:linebt.xl}]->(tobt);

LOAD CSV WITH HEADERS FROM "file:///linecp.csv" AS linecp
match (fromcp:Station{name:linecp.sn}),(tocp:Station{name:linecp.en})
merge (fromcp)-[rcp:昌平線{jl:linecp.jl,xl:linecp.xl}]->(tocp);

LOAD CSV WITH HEADERS FROM "file:///lineyz.csv" AS lineyz
match (fromyz:Station{name:lineyz.sn}),(toyz:Station{name:lineyz.en})
merge (fromyz)-[ryz:亦莊線{jl:lineyz.jl,xl:lineyz.xl}]->(toyz);

LOAD CSV WITH HEADERS FROM "file:///linedx.csv" AS linedx
match (fromdx:Station{name:linedx.sn}),(todx:Station{name:linedx.en})
merge (fromdx)-[rdx:大興線{jl:linedx.jl,xl:linedx.xl}]->(todx);

LOAD CSV WITH HEADERS FROM "file:///linefs.csv" AS linefs
match (fromfs:Station{name:linefs.sn}),(tofs:Station{name:linefs.en})
merge (fromfs)-[rfs:房山線{jl:linefs.jl,xl:linefs.xl}]->(tofs);

LOAD CSV WITH HEADERS FROM "file:///linejc.csv" AS linejc
match (fromjc:Station{name:linejc.sn}),(tojc:Station{name:linejc.en})
merge (fromjc)-[rjc:機場線{jl:linejc.jl,xl:linejc.xl}]->(tojc);

執行效果

備註:Neo4j瀏覽器需要開啟多語句執行配置,否則會報語句執行錯誤,配置介面如下:

1.Neo4j瀏覽器配置

Neo4j 地鐵關係網

2.cypher語句執行過程

Neo4j 地鐵關係網

3.地鐵關係網效果

Neo4j 地鐵關係網

四、路徑檢索

以‘霍營’與‘北京南站’地鐵站為例,檢索具體一下路徑:

最少站點路徑

MATCH (p1:Station {name:"霍營"}),(p2:Station{name:"北京南站"}),p=shortestpath((p1)-[*]-(p2)) RETURN p

最短路程路徑

MATCH p=(b:Station{name:"霍營"})-[*..20]->(d:Station{name:"北京南站"}) WITH p,reduce(s = 0, r IN rels(p) | s + r.jl) AS dist return p ORDER BY dist DESC limit 1

最少耗時路徑

很遺憾,因為沒有找到北京地鐵每站之間具體的耗時資料,所以此處檢索不出來,行吧,我太難了。

五、總結

1)資料整理涉及節點資料,節點關係資料,可在匯入CSV時一併建立;
2)Cypher 是 借鑑了sql語句的 Neo4j 資料庫操作語句;
3)(a)-[*..20]->(b):表示路徑長度的最大值是20,起始節點是a,終止節點是b;
4)一次執行多條語句,Neo4j瀏覽器需要開啟多語句執行配置;

over

mysql全文檢索

相關文章