Task03:Neo4j簡介與醫療知識圖譜代碼分析

2021-02-13 格數致知
一、引言

在計算機科學中,圖形作為一種特定的數據結構,用於表達數據之間的複雜關係,如社交關係、組織架構、交通信息、網絡拓撲等等。在圖計算中,基本的數據結構表達式是:G=(V,E),V=vertex(節點),E=edge(邊)。圖形結構的數據結構一般以節點和邊來表現,也可以在節點上增加鍵值對屬性。圖資料庫是 NoSQL(非關係型資料庫)的一種,它應用圖形數據結構的特點(節點、屬性和邊)存儲數據實體和相互之間的關係信息。

Neo4j 是當前較為主流和先進的原生圖資料庫之一,提供原生的圖數據存儲、檢索和處理。它由 Neo Technology支持,從 2003 年開始開發,1.0 版本發布於 2010 年,2.0版本發布於 2013 年。經過十多年的發展,Neo4j 獲得越來越高的關注度,它已經從一個 Java 領域內的圖資料庫逐漸發展成為適應多語言多框架的圖資料庫。Neo4j 支持ACID、集群、備份和故障轉移,具有較高的可用性和穩定性;它具備非常好的直觀性,通過圖形化的界面表示節點和關係;同時它具備較高的可擴展性,能夠承載上億的節點、關係和屬性,通過 REST 接口或者面向對象的 JAVA API進行訪問。

二、Neo4j簡介2.1 基本概念

Neo4j使用圖相關的概念來描述數據模型,把數據保存為圖中的節點以及節點之間的關係。數據主要由三部分構成:

節點。節點表示對象實例,每個節點有唯一的ID區別其它節點,節點帶有屬性;關係。就是圖裡面的邊,連接兩個節點,另外這裡的關係是有向的並帶有屬性;屬性。key-value對,存在於節點和關係中,如圖1所示。

圖片.png

圖 1 節點、關係和屬性三者的關係

2.2 索引動機:Neo4j使用遍歷操作進行查詢。為了加速查詢,Neo4j會建立索引,並根據索引找到遍歷用的起始節點;介紹:默認情況下,相關的索引是由Apache Lucene提供的。但也能使用其他索引實現來提供。操作:用戶可以創建任意數量的命名索引。每個索引控制節點或者關係,而每個索引都通過key/value/object三個參數來工作。其中object要麼是一個節點,要麼是一個關係,取決於索引類型。另外,Neo4j中有關於節點(關係)的索引,系統通過索引實現從屬性到節點(關係)的映射。查找操作:系統通過設定訪問條件比如,遍歷的方向,使用深度優先或廣度優先算法等條件對圖進行遍歷,從一個節點沿著關係到其他節點;刪除操作:Neo4j可以快速的插入刪除節點和關係,並更新節點和關係中的屬性。2.3 Neo4j的優勢

那麼,如此引人入勝的 Neo4j,與其他資料庫相比,具有哪些明顯的優勢呢?這可以從以下幾個方面來分析,主要表現為查詢的高性能、設計的靈活性和開發的敏捷性等。

Neo4j是一個原生的圖資料庫引擎,它存儲了原生的圖數據,因此,可以使用圖結構的自然伸展特性來設計免索引鄰近節點遍歷的查詢算法,即圖的遍歷算法設計。圖的遍歷是圖數據結構所具有的獨特算法,即從一個節點開始,根據其連接的關係,可以快速和方便地找出它的鄰近節點。這種查找數據的方法並不受數據量的大小所影響,因為鄰近查詢查找的始終是有限的局部數據,而不會對整個資料庫進行搜索。所以,Neo4j具有非常高效的查詢性能,相比於RDBMS,它的查詢速度可以提高數倍乃至數十倍.而且查詢速度不會因數據量的增長而下降,即資料庫可以經久耐用,並且始終保持最初的活力。不像RDBMS那樣,因為不可避免地使用了一些範式設計,所以在查詢時如果需要表示一些複雜的關係,勢必會構造很多連接,從而形成很多複雜的運算。並且在查詢中更加可怕的是還會涉及大量數據,這些數據大多與結果毫無關係,有的可能僅僅是通過ID查找它的名稱而已,所以隨著數據量的增長,即使查詢一小部分數據,查詢也會變得越來越慢,性能日趨下降,以至於讓人無法忍受。

在日新月異的網際網路應用中,業務需求會隨著時間和條件的改變而發生變化,這對於以往使用結構化數據的系統來說,往往很難適應這種變化的需要。圖數據結構的自然伸展特性及其非結構化的數據格式,讓 Neo4j的資料庫設計可以具有很大的伸縮性和靈活性。因為隨著需求的變化而增加的節點、關係及其屬性並不會影響到原來數據的正常使用,所以使用Neo4j來設計資料庫,可以更接近業務需求的變化,可以更快地趕上需求發展變化的腳步。大多數使用關係型資料庫的系統,為了應對快速變化的業務需求,往往需要採取推倒重來的方法重構整個應用系統。而這樣做的成本是巨大的。使用Neo4j可以最大限度地避免這種情況發生。雖然有時候,也許是因為最初的設計考慮得太不周全,或者為了獲得更好的表現力,資料庫變更和遷移在所難免,但是使用Neo4j來做這項工作也是非常容易的,至少它沒有模式結構定義方面的苦惱。

圖資料庫設計中的數據模型,從需求的討論開始,到程序開發和實現,以及最終保存在資料庫中的樣子,直觀明了,似乎沒有什麼變化,甚至可以說本來就是一模一樣的。這說明,業務需求與系統設計之間可以拉近距離,需求和實現結果之間越來越接近。這不但降低了業務人員與設計人員之間的溝通成本,也使得開發更加容易迭代,並且非常適合使用敏捷開發方法。

Neo4j本身可伸縮的設計靈活性,以及直觀明了的數據模型設計,以及其自身簡單易用的特點等,所有這些優勢都充分說明,使用Neo4j很適合以一種測試驅動的方法應用於系統設計和開發自始至終的過程之中,通過迭代來加深對需求的理解,並通過迭代來完善數據模型設計。

在圖資料庫領域,除Neo4j外,還有其他如OrientDB、Giraph、AllegroGraph等各種圖資料庫。與所有這些圖資料庫相比,Neo4j的優勢表現在以下兩個方面。

(1)Neo4j是一個原生圖計算引擎,它存儲和使用的數據自始至終都是使用原生的圖結構數據進行處理的,不像有些圖資料庫,只是在計算處理時使用了圖資料庫,而在存儲時還將數據保存在關係型資料庫中。

(2)Neo4j是一個開源的資料庫,其開源的社區版吸引了眾多第三方的使用和推如開源項目Spring Data Neo4j就是一個做得很不錯的例子,同時也得到了更多開發者的擁躉和支持,聚集了豐富的可供交流和學習的資源與案例。這些支持、推廣和大量的使用,反過來會很好地推動Neo4j的發展。

Neo4j 查詢的高性能表現、易於使用的特性及其設計的靈活性和開發的敏捷性,以及堅如磐石般的事務管理特性,都充分說明了使用Neo4j是一個不錯的選擇。有關它的所有優點,總結起來,主要表現在以下幾個方面。

非結構化數據存儲方式,在資料庫設計上具有很大的靈活性;很容易使用,可以用嵌入式、伺服器模式、分布式模式等方式來使用資料庫;資料庫安全可靠,可以實時備份數據,很方便恢復數據;圖的數據結構直觀而形象地表現了現實世界的應用場景。三、Neo4j 數據導入3.1 數據集簡介

數據源:39健康網。包括15項信息,其中7類實體,約3.7萬實體,21萬實體關係。

知識圖譜結構

圖 5 知識圖譜結構

知識圖譜實體類型

圖 6 知識圖譜實體類型

知識圖譜實體關係類型

圖 6 知識圖譜實體關係類型

知識圖譜疾病屬性

圖 7 知識圖譜疾病屬性

基於特徵詞分類的方法來識別用戶查詢意圖

圖 8 基於特徵詞分類的方法來識別用戶查詢意圖

3.2 數據導入

參考task2:Task02:快速搭建易於醫療領域的小型知識圖譜

3.3 知識圖譜展示

運行介紹之後,打開瀏覽器進入網址:http://localhost:7474/browser/,可以看到我們導入的數據的知識圖譜,如下:

圖片.png

圖 9 知識圖譜 展示圖

3.4 主體類 MedicalGraph 介紹
class MedicalGraph:
def __init__(self):
pass

# 讀取文件,獲得實體,實體關係
def read_file(self):
psss
# 創建節點
def create_node(self, label, nodes):
pass
# 創建疾病節點的屬性
def create_diseases_nodes(self, disease_info):
pass
# 創建知識圖譜實體
def create_graphNodes(self):
pass
# 創建實體關係邊
def create_graphRels(self):
pass
# 創建實體關係邊
def create_relationship(self, start_node, end_node, edges, rel_type, rel_name):
pass

3.5 主體類 MedicalGraph 中關鍵代碼講解
    cur_dir = '/'.join(os.path.abspath(__file__).split('/')[:-1])
self.data_path = os.path.join(cur_dir, 'DATA/disease.csv')

    self.graph = Graph("http://localhost:7474", username="neo4j", password="自己設定的密碼")

這部分代碼的核心就是讀取 數據文件,並 獲取實體和實體關係信息。

disease_to_symptom  疾病與症狀關係disease_to_alias  疾病與別名關係diseases_to_part  疾病與部位關係disease_to_department  疾病與科室關係disease_to_complication  疾病與併發症關係
    def read_file(self):
"""
讀取文件,獲得實體,實體關係
:return:
"""
# cols = ["name", "alias", "part", "age", "infection", "insurance", "department", "checklist", "symptom",
# "complication", "treatment", "drug", "period", "rate", "money"]
# 實體
diseases = [] # 疾病
aliases = [] # 別名
symptoms = [] # 症狀
parts = [] # 部位
departments = [] # 科室
complications = [] # 併發症
drugs = [] # 藥品

# 疾病的屬性:age, infection, insurance, checklist, treatment, period, rate, money
diseases_infos = []
# 關係
disease_to_symptom = [] # 疾病與症狀關係
disease_to_alias = [] # 疾病與別名關係
diseases_to_part = [] # 疾病與部位關係
disease_to_department = [] # 疾病與科室關係
disease_to_complication = [] # 疾病與併發症關係
disease_to_drug = [] # 疾病與藥品關係

all_data = pd.read_csv(self.data_path, encoding='gb18030').loc[:, :].values
for data in all_data:
disease_dict = {} # 疾病信息
# 疾病
disease = str(data[0]).replace("...", " ").strip()
disease_dict["name"] = disease
# 別名
line = re.sub("[,、;,.;]", " ", str(data[1])) if str(data[1]) else "未知"
for alias in line.strip().split():
aliases.append(alias)
disease_to_alias.append([disease, alias])
# 部位
part_list = str(data[2]).strip().split() if str(data[2]) else "未知"
for part in part_list:
parts.append(part)
diseases_to_part.append([disease, part])
# 年齡
age = str(data[3]).strip()
disease_dict["age"] = age
# 傳染性
infect = str(data[4]).strip()
disease_dict["infection"] = infect
# 醫保
insurance = str(data[5]).strip()
disease_dict["insurance"] = insurance
# 科室
department_list = str(data[6]).strip().split()
for department in department_list:
departments.append(department)
disease_to_department.append([disease, department])
# 檢查項
check = str(data[7]).strip()
disease_dict["checklist"] = check
# 症狀
symptom_list = str(data[8]).replace("...", " ").strip().split()[:-1]
for symptom in symptom_list:
symptoms.append(symptom)
disease_to_symptom.append([disease, symptom])
# 併發症
complication_list = str(data[9]).strip().split()[:-1] if str(data[9]) else "未知"
for complication in complication_list:
complications.append(complication)
disease_to_complication.append([disease, complication])
# 治療方法
treat = str(data[10]).strip()[:-4]
disease_dict["treatment"] = treat
# 藥品
drug_string = str(data[11]).replace("...", " ").strip()
for drug in drug_string.split()[:-1]:
drugs.append(drug)
disease_to_drug.append([disease, drug])
# 治癒周期
period = str(data[12]).strip()
disease_dict["period"] = period
# 治癒率
rate = str(data[13]).strip()
disease_dict["rate"] = rate
# 費用
money = str(data[14]).strip() if str(data[14]) else "未知"
disease_dict["money"] = money

diseases_infos.append(disease_dict)

return set(diseases), set(symptoms), set(aliases), set(parts), set(departments), set(complications), \
set(drugs), disease_to_alias, disease_to_symptom, diseases_to_part, disease_to_department, \
disease_to_complication, disease_to_drug, diseases_infos

這部分代碼主要是為了創建不包含屬性的 節點

    def create_node(self, label, nodes):
"""
創建節點
:param label: 標籤
:param nodes: 節點
:return:
"""
count = 0
for node_name in nodes:
node = Node(label, name=node_name)
self.graph.create(node)
count += 1
print(count, len(nodes))
return

    def create_diseases_nodes(self, disease_info):
"""
創建疾病節點的屬性
:param disease_info: list(Dict)
:return:
"""
count = 0
for disease_dict in disease_info:
node = Node("Disease", name=disease_dict['name'], age=disease_dict['age'],
infection=disease_dict['infection'], insurance=disease_dict['insurance'],
treatment=disease_dict['treatment'], checklist=disease_dict['checklist'],
period=disease_dict['period'], rate=disease_dict['rate'],
money=disease_dict['money'])
self.graph.create(node)
count += 1
print(count)
return

    def create_graphNodes(self):
"""
創建知識圖譜實體
:return:
"""
disease, symptom, alias, part, department, complication, drug, rel_alias, rel_symptom, rel_part, \
rel_department, rel_complication, rel_drug, rel_infos = self.read_file()
self.create_diseases_nodes(rel_infos)
self.create_node("Symptom", symptom)
self.create_node("Alias", alias)
self.create_node("Part", part)
self.create_node("Department", department)
self.create_node("Complication", complication)
self.create_node("Drug", drug)

return

    def create_graphRels(self):
disease, symptom, alias, part, department, complication, drug, rel_alias, rel_symptom, rel_part, \
rel_department, rel_complication, rel_drug, rel_infos = self.read_file()

self.create_relationship("Disease", "Alias", rel_alias, "ALIAS_IS", "別名")
self.create_relationship("Disease", "Symptom", rel_symptom, "HAS_SYMPTOM", "症狀")
self.create_relationship("Disease", "Part", rel_part, "PART_IS", "發病部位")
self.create_relationship("Disease", "Department", rel_department, "DEPARTMENT_IS", "所屬科室")
self.create_relationship("Disease", "Complication", rel_complication, "HAS_COMPLICATION", "併發症")
self.create_relationship("Disease", "Drug", rel_drug, "HAS_DRUG", "藥品")

    def create_relationship(self, start_node, end_node, edges, rel_type, rel_name):
"""
創建實體關係邊
:param start_node:
:param end_node:
:param edges:
:param rel_type:
:param rel_name:
:return:
"""
count = 0
# 去重處理
set_edges = []
for edge in edges:
set_edges.append('###'.join(edge))
all = len(set(set_edges))
for edge in set(set_edges):
edge = edge.split('###')
p = edge[0]
q = edge[1]
query = "match(p:%s),(q:%s) where p.name='%s'and q.name='%s' create (p)-[rel:%s{name:'%s'}]->(q)" % (
start_node, end_node, p, q, rel_type, rel_name)
try:
self.graph.run(query)
count += 1
print(rel_type, count, all)
except Exception as e:
print(e)
return

四、總結

Neo4j是一個高性能的,NOSQL圖形資料庫,它將結構化數據存儲在網絡上而不是表中。Neo4j也可以被看作是一個高性能的圖引擎,該引擎具有成熟資料庫的所有特性。Neo4j是一個高度可擴展的本機圖形資料庫,旨在專門利用

相關焦點

  • 知識圖譜Task00:Neo4j安裝配置
    知識圖譜開源內容:https://github.com/datawhalechina/team-learning-nlp/tree/master/KnowledgeGraph_Basic 19學習目標熟悉Neo4j並具備基本的調用相應python庫進行操作的能力。
  • 手把手教你快速入門知識圖譜 - Neo4J教程
    前言今天,我們來聊一聊知識圖譜中的Neo4J。首先,什麼是知識圖譜?先摘一段百度百科:知識圖譜(Knowledge Graph),在圖書情報界稱為知識域可視化或知識領域映射地圖,是顯示知識發展進程與結構關係的一系列各種不同的圖形,用可視化技術描述知識資源及其載體,挖掘、分析、 構建、繪製和顯示知識及它們之間的相互聯繫。
  • 一文聊「圖」,從圖資料庫到知識圖譜
    作者 | 穆瓊責編 | 晉兆雨頭圖 | 付費下載於視覺中國隨著知識圖譜的發展,圖資料庫一詞被越來越多的提到。那麼到底什麼是圖資料庫,為什麼要用圖資料庫,如何去建設一個圖資料庫應用系統,圖資料庫與知識圖譜到底是什麼關係。今天為大家揭開神秘面紗,以Neo4j為例,淺析圖資料庫相關技術。作者介紹:穆瓊 中國農業銀行研發中心,致力於AIOps的落地。
  • 智能化探索(5)圖資料庫 Neo4j 的部署、數據導入和簡單使用
    目錄Neo4j 簡介Neo4j 的部署數據加載Cypher 查詢語言本文介紹了 Neo4j
  • 當推薦系統遇見知識圖譜
    知識圖譜是一種語義圖,其結點(node)代表實體(entity)或者概念(concept),邊(edge)代表實體/概念之間的各種語義關係(relation)。一個知識圖譜由若干個三元組(h、r、t)組成,其中h和t代表一條關係的頭結點和尾節點,r代表關係。
  • 圖形資料庫Neo4J簡介
    圖形資料庫簡介  相信您和我一樣,在使用關係型資料庫時常常會遇到一系列非常複雜的設計問題。例如一部電影中的各個演員常常有主角配角之分,還要有導演,特效等人員的參與。通常情況下這些人員常常都被抽象為Person類型,對應著同一個資料庫表。
  • KgCLUE: 大規模中文開源知識圖譜問答
    KgCLUE: 大規模中文開源知識圖譜問答
  • DGL-KE:亞馬遜開源知識圖譜嵌入庫,親測快到飛起
    DGL-KE:亞馬遜開源大規模知識圖譜嵌入訓練庫先說結論啊 這個庫的開源已經是去年(2020)的事情了,突然感覺時間好快~,當時並沒有在意,最近關注到這個庫是因為自己在訓練知識圖譜 Embedding 的時候做的一些調研,考慮到後續大規模知識圖譜的訓練,需要更快的開源庫,於是DGL-KE 重新回到我的視野!
  • 詳解預訓練模型、信息抽取、文本生成、知識圖譜、對話系統技術
    01 課程大綱課程內容上做了大幅度的更新,課程覆蓋了從預訓練模型、對話系統、信息抽取、知識圖譜、文本生成所有必要的技術應用和學術前沿。課程採用全程直播授課模式。第一章:知識圖譜與圖數據模型| 知識圖譜:搜尋引擎,數據整合,AI| 實體抽取、關係抽取、詞向量| graph embedding
  • 推薦系統結合知識圖譜簡單總結
    連結 | https://zhuanlan.zhihu.com/p/59762355筆者對近幾年推薦系統(Recommendation System)領域結合Knowledge Graph Embedding (知識圖譜表示學習)或者Network Embedding(網絡表示)的幾篇論文做了極簡介紹。首先簡單介紹推薦系統,之後整理了幾篇結合知識表示的論文。
  • Neo4j 數據分析—附薅羊毛教程
    目前這個插件除了囊括了上篇博文中介紹的路徑分析、中心度分析和社群分析三類圖算法函數,還包括了相似度計算、連結預測、數據預處理等模塊,具體算法的使用可以參考 The Neo4j Graph Algorithms User Guide v3.5。能夠感受到的是,無論是在函數的豐富程度方面還是文檔的編寫方面,Neo4j對圖算法的支持還在飛速進化中。
  • 知識圖譜的下一步:知識指導的預訓練模型和圖神經網絡
    工業界的數據集經常會暴露出更多問題,比如說同一個類型的實體很少,或者同一個 use case 下數據量不夠,比如根因分析、故障定位領域,不像網際網路的某些話題在網頁上可以找到大量數據 。怎麼針對這類真實的數據集做知識圖譜的構建,怎麼對數據進行大量的清洗工作,工業界更多在解決這些問題。
  • 論文淺嘗 | 基於知識圖譜嵌入的 Bootstrapping 實體對齊方法
    來源: IJCAI 2018連結: https://www.ijcai.org/proceedings/2018/0611.pdf 本文關注基於知識圖譜嵌入(後文全部簡稱為知識嵌入)的實體對齊工作,針對知識嵌入訓練數據有限這一情況,作者提出一種 bootstrapping 策略,迭代標註出可能的實體對齊,生成新數據加入知識嵌入模型的訓練中。
  • 一種模型驅動的關係資料庫知識圖譜構建方法
    關係資料庫是構建垂直領域知識圖譜的主要數據源之一。如何建立關係資料庫中概念與知識圖譜中相應概念之間的映射關係,是提高垂直領域知識圖譜構建效率的關鍵。針對這一問題,本文提出了一種基於模型驅動體系結構(MDA)的從關係資料庫中自動構造知識圖譜的模型驅動方法。首先,提出了一個模型驅動的框架,用標準XML模式描述關係資料庫和知識圖譜。
  • BERT meet Knowledge Graph:預訓練模型與知識圖譜相結合的研究進展
    隨著各類預訓練任務層出不窮,也有部分研究者考慮如何在BERT這一類模型中引入或者強化知識圖譜中包含的信息,進而增強BERT對背景知識或常識信息的編碼能力。本文主要關注於如何在BERT中引入知識圖譜中信息,並survey了目前已公布的若干種方法,歡迎大家批評和交流。
  • 7 Papers & Radios | Bengio等創建GNN權威基準;130頁知識圖譜綜述論文
    通過數據分析,他們得出了以下兩個觀察結果,其一是將不同的零售(商)分組後呈現出的銷售季度性,其二是將銷售狀況轉化為預測值後呈現出的 Tweedie 分布。基於觀察結果,研究者設計了兩種銷售預測機制,即季節提取(seasonality extraction)和分布轉化。
  • 知識圖譜(KG)存儲、可視化、公開數據集、圖計算、圖編程工具分享
    知識圖譜(Knowledge Graph),在圖書情報界稱為知識域可視化或知識領域映射地圖,是顯示知識發展進程與結構關係的一系列各種不同的圖形,用可視化技術描述知識資源及其載體,挖掘、分析、構建、繪製和顯示知識及它們之間的相互聯繫。
  • Neo4j 操作與 py2neo 用法
    在Neo4j中,節點以及邊都能夠包含保存值的屬性,此外:可以為節點設置零或多個標籤(例如 Author 或 Book)每個關係都對應一種類型(例如 WROTE 或 FRIEND_OF)關係總是從一個節點指向另一個節點(但可以在不考慮指向性的情況下進行查詢)具體介紹可以參考:https://www.w3cschool.cn/neo4j
  • Linux下0號進程的前世(init_task進程)今生(idle進程)
    , 負責所有內核線程的調度和管理它的任務就是管理和調度其他內核線程kernel_thread, 會循環執行一個kthread的函數,該函數的作用就是運行kthread_create_list全局鍊表中維護的kthread, 當我們調用kernel_thread創建的內核線程會被加入到此鍊表中,因此所有的內核線程都是直接或者間接的以kthreadd為父進程我們下面就詳解分析
  • bthread源碼剖析(一): 基本概念與TaskControl初始化
    因為並不是brpc server中的所有線程都是worker,因為brpc也會在沒有TG的的pthread上運行代碼。雖然前面我們說bthread並不嚴格從屬於一個pthread,但是bthread在運行的時候是必然要在一個pthread中的worker中被調用執行的。