學習筆記,比較混亂,介意慎點。
背景
在將UMLS或者LightRAG構造的數據庫存入neo4j之后,我開始將知識圖譜運用到實際場景的使用中、例如查詢、推理。然而,由于字符串匹配導致大量術語在檢索時出現缺失。導致檢索效果不佳。我們需要使用embedding模型,將對應的實體或者關系轉為vector,存入向量數據庫。利用向量數據庫已有的高效存儲技術和查詢方法。幫助我們快速查詢到相關實體或者關系。通過確定相似度的閾值,來保留最終查詢結果。
目標:
? ? ? ? 向量化UMLS的實體(篩選過的)
? ? ? ? embeding 千問的嵌入模型? ? ? ??
? ? ? ? 向量數據庫?在實踐中,我們推薦大家使用開源 Milvus,或它的全托管版本 Zilliz Cloud,來存儲并搜索 graph 結構中大量的 entities 和 relationships。(AI大模型:知識圖譜融入向量數據庫,帶來 RAG 效果飛升(附教程)_知識圖譜 向量數據庫-CSDN博客)
【
在這句話中,“全托管” 指的是一種軟件服務模式,具體來說,Zilliz Cloud 作為 Milvus 向量數據庫的全托管版本,意味著用戶無需自行搭建、部署、維護數據庫的底層基礎設施(如服務器、存儲、網絡等),也無需手動處理數據庫的安裝、配置、更新、備份、擴容等運維工作,這些任務全部由服務提供商(此處即 Zilliz 團隊)來負責。
用戶只需通過簡單的接口或控制臺操作,就能直接使用數據庫的核心功能(如存儲、搜索向量數據等),專注于自身業務邏輯的開發,而不必投入精力在基礎設施管理上。這種模式的優勢在于降低了技術門檻、減少了運維成本,同時能借助專業團隊的維護保障服務的穩定性和安全性,常見于云服務中的數據庫、服務器等領域。
】
【
全托管版本 Zilliz Cloud收費嗎?
Zilliz Cloud 有免費版本,也有付費版本,具體如下:
- 免費版本:Serverless cluster 是 Zilliz Cloud 的入門版本,用戶可在 GCP 上部署免費 cluster,適合入門者和想要嘗試 Zilliz Cloud 的開發人員,無需信用卡和復雜配置,即可快速體驗向量數據庫功能。
- 付費版本:包括標準版、企業版和專有部署版。標準版適合小型團隊和個人開發者,支持在 AWS 和 GCP 上部署,注冊可獲贈價值 $100 的 credit,享受 30 天免費試用。企業版適合大型組織或企業,提供高可用、數據安全和專家技術支持等。專有部署版適用于高度注重數據隱私和合規的場景,這兩種版本無免費試用,具體價格需根據用戶實際使用情況和配置確定。
】
學習過程
? ? ? ? 通過博文了解使用的具體過程為:定義數據模式,(包括知道dim = 1536 # OpenAI embedding維度),創建存放向量的集合,寫入
代碼比較簡單,如下:
# 定義數據模式
collection_name = "products"
dim = 1536 # OpenAI embedding維度
# 創建集合
collection = Collection(name=collection_name)
collection.create_field(FieldSchema("id", DataType.INT64, is_primary=True))
collection.create_field(FieldSchema("title", DataType.VARCHAR, max_length=200))
collection.create_field(FieldSchema("description", DataType.VARCHAR, max_length=2000))
collection.create_field(FieldSchema("embedding", DataType.FLOAT_VECTOR, dim=dim))
# 寫入數據
with collection:for index, row in df.iterrows():embedding = get_embedding(row.title + " " + row.description)collection.insert([[index], [row.title], [row.description], [embedding]])
向量數據庫可能會返回那些字符表面相似,但是語義不相似的內容,這會造成“上下文污染”,使得大語言模型生成的推薦不夠精確。
這里的解決是把一個概念的所有特征用知識圖譜檢索出來,把特征和原有的描述一起向量化檢索。
再用知識圖譜對向量化檢索結果進一步處理,例如:# 篩選出真正具備防水和跑步功能的產品
query = """ SELECT ?product ?title ?description WHERE { ?product hasFeature ?feature1. ?product hasFeature ?feature2. ?product name ?title. ?product description ?description. FILTER (?product IN (%s) && ?feature1 IN (%s) && ?feature2 IN (%s)) } """
(等我回來好好品一下這個查詢
我懂了,核心就是各種同時滿足已知條件。如select product,如何滿足一堆feature
? )
上面我們已經大概有個印象了。接下來開始對比開源 Milvus,或它的全托管版本 Zilliz Cloud,我們選哪個,由于我非常趕時間,需要決策一個技術選型并且快速收集情報進行了解,再部署。
學習[深入了解Zilliz Cloud與Milvus:從安裝到應用的全方位指南]_milvus安裝-CSDN博客
高效向量搜索與管理:使用Zilliz Cloud和Milvus_milvus zilliz-CSDN博客
一文帶你入門向量數據庫milvus:含docker安裝、milvus安裝使用、attu 可視化,完整指南啟動 Milvus 進行了向量相似度搜索-CSDN博客
Milvus 向量數據庫介紹及使用-CSDN博客
決定了,其實對我來說都差不多,我決定安裝Milvus,作為一個開源的軟件,學習它對我來說未來的可用性更強。邊學邊做吧。
?概念學習
最火向量數據庫Milvus安裝使用一條龍!_milvus安裝腳本-CSDN博客從該博客學了不少的概念和了解,我的理念是要學就要盡量了解自己在用的是什么,為甚要用它。
向量數據庫是大模型應用開發必備組件之一,因為它在知識庫、語義搜索、檢索增強生成(RAG)等人工智能應用中發揮著舉足輕重的作用。但向量數據有很多,為什么要使用 Milvus 呢?
常見的向量數據庫有以下這些:
Chroma
Elasticsearch
Milvus
Neo4j
OpenSearch
Redis
PGVector
然而目前市面上使用最多的向量數據庫還是 Milvus,為什么呢?
Milvus 設計之初就是為 AI 而生的一個高效的向量數據庫系統,在大多數情況下,Milvus 的性能是其他向量數據庫的 2-5 倍,它能實現萬億級向量的毫秒級相似性搜索,而且 Milvus 還是開源的向量數據庫。
PS:也就說 Milvus 既開源(可以免費使用+支持二次開發)又具備高性能,這樣的數據庫誰不愛呢?
為什么 Milvus 這么快?
Milvus 運行比較快的原因有以下幾個:
硬件感知優化:為了讓 Milvus 適應各種硬件環境,我們專門針對多種硬件架構和平臺優化了其性能,包括 AVX512、SIMD、GPU 和 NVMe SSD。
高級搜索算法:Milvus 支持多種內存和磁盤索引/搜索算法,包括 IVF、HNSW、DiskANN 等,所有這些算法都經過了深度優化。與 FAISS 和 HNSWLib 等流行實現相比,Milvus 的性能提高了 30%-70%。
C++ 搜索引擎:向量數據庫性能的 80% 以上取決于其搜索引擎。由于 C++ 語言的高性能、底層優化和高效資源管理,Milvus 將 C++ 用于這一關鍵組件。最重要的是,Milvus 集成了大量硬件感知代碼優化,從匯編級向量到多線程并行化和調度,以充分利用硬件能力。
面向列:Milvus 是面向列的向量數據庫系統。其主要優勢來自數據訪問模式。在執行查詢時,面向列的數據庫只讀取查詢中涉及的特定字段,而不是整行,這大大減少了訪問的數據量。此外,對基于列的數據的操作可以很容易地進行向量化,從而可以一次性在整個列中應用操作,進一步提高性能。
Milvus 支持的搜索類型
Milvus 支持各種類型的搜索功能,以滿足不同用例的需求:
ANN 搜索:查找最接近查詢向量的前 K 個向量。
過濾搜索:在指定的過濾條件下執行 ANN 搜索。
范圍搜索:查找查詢向量指定半徑范圍內的向量。
混合搜索:基于多個向量場進行 ANN 搜索。
全文搜索:基于 BM25 的全文搜索。
Rerankers:根據附加標準或輔助算法調整搜索結果順序,完善初始 ANN 搜索結果。
根據主鍵檢索數據。
查詢使用特定表達式檢索數據。
Milvus 安裝
Milvus 有三種部署方式:
Milvus Lite:Milvus Lite 是一個 Python 庫,可導入到您的應用程序中。作為 Milvus 的輕量級版本,它非常適合在 Jupyter 筆記本或資源有限的智能設備上運行快速原型。Milvus Lite 支持與 Milvus 其他部署相同的 API。與 Milvus Lite 交互的客戶端代碼也能與其他部署模式下的 Milvus 實例協同工作。
Milvus Standalone:Milvus Standalone 是單機服務器部署。Milvus Standalone 的所有組件都打包到一個 Docker 鏡像中,部署起來非常方便。
Milvus Distributed:Milvus Distributed 可部署在 Kubernetes 集群上。這種部署采用云原生架構,攝取負載和搜索查詢分別由獨立節點處理,允許關鍵組件冗余。它具有最高的可擴展性和可用性,并能靈活定制每個組件中分配的資源。Milvus Distributed 是在生產中運行大規模向量搜索系統的企業用戶的首選。
PS:當然中小型公司生產環境也可以直接購買 XXX 云的 Milvus 實例直接使用。
我們這里使用 Milvus Standalone 單機版部署方式。
硬件要求
如何確定自己的電腦性能:
有幾核:按 Win + R 輸入 “cmd” 后按回車,打開命令提示符。輸入命令 “wmic CPU get NumberOfCores,NumberOfLogicalProcessors” 并回車,輸出會顯示核心數(NumberOfCores)和邏輯處理器數。
CPU型號:任務管理器:右鍵點擊任務欄,選擇 “任務管理器”,或使用快捷鍵 Ctrl + Shift + Esc 直接打開。在任務管理器中,點擊 “性能” 標簽,選擇 “CPU”
安裝
0.如何確定自己有沒有安裝docker desktop、wsl
????????Docker Desktop:在 Windows、macOS 或 Linux 系統中,打開命令提示符、PowerShell 或終端,輸入 “docker --version” 或 “docker version” 命令。若顯示 Docker 的版本信息,則說明已安裝。還可輸入 “docker info” 命令,若能獲取到 Docker 系統的詳細信息,如鏡像數量、容器數量等,也表明已安裝且服務正常運行。
【pps,我突然想到,自己安裝只能安裝在windows,而未來公司用多半是服務器或者linux系統。我裝在學校服務器的話,容易遇到服務器維護,沒卡啥的,還是調接口吧,或者直接調用之前的neo4j。于是以下廢棄,歡迎大家調到下一個一級標題】
1.安裝wsl
2從安裝到測試安裝完成【Windows系統】向量數據庫Milvus安裝教程-CSDN博客
【
一些我的小疑問
????????Docker 是一種開源的容器化技術,通過 “容器” 封裝應用程序及其所有依賴的底層系統環境(如操作系統庫、配置文件、系統工具等),實現 “一次構建,到處運行”。
容器與宿主機系統隔離,確保應用在不同操作系統(如 Windows、Linux、macOS)或服務器上的運行環境完全一致,解決 “在我這能跑,在你那跑不了” 的問題。
???????? 容器類似輕量級虛擬機,包含應用運行所需的代碼、庫、環境變量等,但共享主機操作系統內核,啟動快、資源占用低。 通過 Docker,開發者可在一致環境中開發、測試和部署應用,也便于規模化管理和分發應用。
? ? ? ? ?Docker Compose 是 Docker 官方提供的用于定義和運行多容器 Docker 應用程序的工具,通過 YAML 文件配置應用所需的所有服務,再用一條命令即可創建并啟動所有服務。
? ? ? ? ? 在該場景中,安裝 Milvus 服務需使用其提供的 docker - compose.yml 文件,而 Docker Compose 正是解析和執行該文件的必備工具,只有安裝它,才能通過 “docker - compose up -d” 命令啟動 Milvus 相關的容器服務。
? ? ? ??
Docker Desktop 是一款適用于 Windows 和 macOS 系統的桌面應用程序,是 Docker 官方提供的集成工具。
它的主要功能包括:
- 提供圖形化界面,方便用戶管理 Docker 容器、鏡像、網絡等資源,無需完全依賴命令行操作。
- 內置了 Docker Engine,可在本地構建、運行和測試 Docker 容器。
- 集成了 Docker Compose 工具,支持通過配置文件定義和運行多容器應用。
- 對于 Windows 系統,通常需要配合 WSL(Windows 子系統 for Linux)使用,以提供更高效的容器運行環境。
簡單來說,它是簡化本地 Docker 環境搭建和使用的工具,讓開發者能更便捷地進行容器化應用的開發、測試等工作。
】
neo4j
Neo4j 的向量搜索(Neo4jVector)和常見的向量數據庫(比如 Milvus、Qdrant)之間的區別與聯系_neo4j向量化-CSDN博客
根據上文,感覺neo4j更適合我的研究,開源現由特定節點出發,再沿著圖結構查詢
“Neo4j 向量搜索擅長將“結構化圖信息”與“語義相似度”結合起來;而 Milvus、Qdrant 等專用向量數據庫更適合做超大規模、高性能的純向量相似度檢索。”
存入向量數據庫
【neo4j】win/linux安裝和使用+cypher+langchian+向量索引_neo4j desktop linux-CSDN博客
通過上文對條件再做個了解
向量索引內容
neo4j版本5以上,部分函數要求5.18以上
官網介紹Vector indexes - Cypher Manual
csdn給出的安裝方法Neo4j安裝apoc插件的詳細教程-CSDN博客
根據上文完成了安裝apoc
原因如下:
neo4j有兩種索引方式,一種是索引文本(整個三元組full-text,即Relationship),一種是向量化Node或者Relation。
full-text向量化Full-text indexes - Cypher Manual
貌似不能向量化整個三元組?
官網向量化例子
同理,添加關系的embedding函數是db.create.setRelationshipVectorProperty
官網代碼1Cypher Cheat Sheet - Neo4j Documentation Cheat Sheet
官網代碼2Find movies given a search prompt - Embeddings & Vector Indexes Tutorial
def add_vectors():model = BertEmb() # 自定義的 model.embed_query(str) 返回一個list 裝的是embedding# step1: get embeddingscode = "MATCH (e) RETURN e.id as id, e.name as name"entity_names = driver.execute_query(code)entity_list = []print(f'Begin generate embeddings ...')for idx, record in enumerate(tqdm(entity_names.records)):id = record.get('id')name = record.get('name')curr_emb = {'id': id,'name': name,'embedding': model.embed_query(name)} entity_list.append(curr_emb)# step2: set NodeVectorPropertyprint(f'Begin adding embeddings as property...')batch = 100total_num = len(entity_names.records)pbar = tqdm(total=total_num)for step in range(0, total_num, batch):range_start = steprange_end = min(total_num, range_start+batch)batch_entities = entity_list[range_start:range_end]create_embeddings_code = """UNWIND $entities as entityMATCH (e:Entity {id:entity.id})CALL db.create.setNodeVectorProperty(e, 'embedding', entity.embedding)"""driver.execute_query(create_embeddings_code, entities=batch_entities) pbar.update(range_end-range_start) pbar.close()# step3: add indexprint(f'Begin adding index...')create_index_code = """CREATE VECTOR INDEX entity_embeddings IF NOT EXISTSFOR (e:Entity)ON e.embeddingOPTIONS {indexConfig: {`vector.dimensions`: 768,`vector.similarity_function`: 'cosine'}}"""driver.execute_query(create_index_code)
具體操作
在 Neo4j 中實現向量化存儲:從文本到高效語義搜索_neo4j 向量化-CSDN博客
neo4j圖數據庫基本概念和向量使用_neo4j_辛一一-DeepSeek技術社區
1.數據填充
假設你有一些文本數據(例如一個文本文件 dune.txt),需要將這些文本數據處理后存儲到 Neo4j 中。這通常需要以下步驟:
讀取文本數據:從文件中讀取文本內容。
分段處理:將文本分割成較小的段落或句子。
生成向量:使用某種嵌入模型(如 OpenAI 的 text-embedding-ada-002 或 Hugging Face 的 sentence-transformers)將文本轉換為向量。
存儲到 Neo4j:將文本和對應的向量存儲到 Neo4j 數據庫中。
以下是一個簡單的 Python 示例代碼,展示如何完成這些步驟:
import os
import neo4j
from transformers import AutoModel, AutoTokenizer
import torch# 1.連接到 Neo4j 數據庫
uri = os.getenv("NEO4J_URI")
username = os.getenv("NEO4J_USERNAME")
password = os.getenv("NEO4J_PASSWORD")
driver = neo4j.GraphDatabase.driver(uri, auth=(username, password))# 2.加載文本嵌入模型
model_name = "sentence-transformers/all-MiniLM-L6-v2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)# 3.讀取文本文件
with open("dune.txt", "r") as file:text = file.read()# 4.分段處理文本
paragraphs = text.split("\n\n") # 假設每兩行是一個段落# 5.將文本和向量存儲到 Neo4j
def store_paragraphs(paragraphs):with driver.session() as session:for i, paragraph in enumerate(paragraphs):# 生成向量inputs = tokenizer(paragraph, return_tensors="pt", padding=True, truncation=True)outputs = model(**inputs)vector = outputs.last_hidden_state.mean(dim=1).detach().numpy().tolist()[0]# 存儲到 Neo4jsession.run("""CREATE (p:Paragraph {id: $id, text: $text, embedding: $embedding})""",id=i,text=paragraph,embedding=vector)store_paragraphs(paragraphs)
下面是我根據上面代碼進行的一些定制化修改
1. 鏈接的信息從一開始安裝neo4j時候的來,等號右邊換成字符串就行。
2.嵌入用的是Qwen/Qwen3-Embedding-8B,從硅基流動用戶系統,統一登錄 SSO調用,需要付費,但不用部署。教程如下:創建嵌入請求 - SiliconFlow
import requestsurl = "https://api.siliconflow.cn/v1/embeddings"payload = {"model": "BAAI/bge-large-zh-v1.5","input": "Silicon flow embedding online: fast, affordable, and high-quality embedding services. come try it out!"
}
headers = {"Authorization": "Bearer <token>","Content-Type": "application/json"
}response = requests.request("POST", url, json=payload, headers=headers)print(response.text)
3.我要文本化的內容是neo4j中已有Concept節點的name屬性,type屬性的值,并將向量后的內容加入知識圖譜Concept節點中的兩個向量屬性,concept節點示例如下:
{"identity": 8,"labels": ["Concept"],"properties": {"CUI": "C0187921","name": "Radical resection for tumor of fibula","type": ["Therapeutic or Preventive Procedure" ]},"elementId": "4:6cab5d42-4d85-48d7-be0d-9c5b8f464282:8" }
4.我要在neo4jConcept節點中新添的兩個屬性中增加向量索引
5.完成需要的查詢語句
? ? ? ? 給出一個名詞,查出0.8閾值以上的top3節點
6.關系的RELA也變成向量,如果關系能被抽取的化,后續開源單獨匹配(但是太麻煩了不想考慮,之后再說吧)
2:創建向量索引
????????
在 Neo4j 中,為了高效地查詢向量數據,需要創建向量索引。向量索引可以幫助快速計算向量之間的相似性。
以下是一個創建向量索引的 Cypher 查詢示例:
CREATE VECTOR INDEX `paragraph-embeddings`
FOR (p:Paragraph) ON (p.embedding)
OPTIONS {indexConfig: {`vector.dimensions`: 384, // 假設向量維度是 384`vector.similarity_function`: 'cosine' // 使用余弦相似性
}}
vector.dimensions
:向量的維度,取決于你使用的嵌入模型。vector.similarity_function
:用于計算相似性的函數,常見的有余弦相似性(cosine
)和歐幾里得距離(euclidean
)。
3.查詢向量索引
創建索引后,可以通過向量查詢來找到與給定向量最相似的節點。以下是一個查詢示例:
CALL db.index.vector.queryNodes('paragraph-embeddings', 10, $queryVector)
YIELD node AS paragraph, score
RETURN paragraph.text AS text, score
ORDER BY score DESC
paragraph-embeddings
:向量索引的名稱。10
:返回最相似的 10 個結果。$queryVector
:查詢向量,你需要提前生成這個向量。
例如,如果你想查詢與某個文本最相似的段落,可以先將文本轉換為向量,然后作為?$queryVector
?傳入查詢。
存進去了這么查找
使用Neo4j Vector Index進行向量相似性搜索的實戰指南_neo4jvector 使用-CSDN博客
4.
另外一種方法,在節點中設置向量屬性
如果需要為節點或關系設置向量屬性,可以使用以下 Cypher 查詢:
MATCH (n:Paragraph {id: $id})
CALL db.create.setNodeVectorProperty(n, 'embedding', $vector)
RETURN n
n:Paragraph
:目標節點。embedding
:向量屬性的名稱。$vector
:要設置的向量值。
節點向量存儲和檢索
1.節點需要添加向量數組
可以選擇一開添加節點的時候加一個向量屬性
create (n:GroupProductA {name:'保高空',description: "保險產品可以保高空作業",embedding: [向量的具體值]}) return n
或者后續添加
MATCH (a:GroupProductA {name:'保高空' })
SET a+= { embedding: [向量具體數值] }
RETURN b;
2.給節點增加向量索引
CREATE VECTOR INDEX 索引名稱 IF NOT EXISTS
FOR (具體的節點標簽)
ON n.embedding
OPTIONS { indexConfig: {
?`vector.dimensions`: 向量維度數值,
?`vector.similarity_function`: 向量計算方法
}}
例如:
CREATE VECTOR INDEX HighDutyIdx IF NOT EXISTS
FOR (n:HighDuty)
ON n.embedding
OPTIONS { indexConfig: {
?`vector.dimensions`: 1536,
?`vector.similarity_function`: 'cosine'
}}
3.計算向量余弦相似度
MATCH (a:GroupProductA)
WHERE a.embedding IS NOT NULL
WITH n,
???? // 計算向量余弦相似度或歐氏距離
???? vector.similarity.cosine(n.embedding, [0.1, 0.2, ...]) AS similarity
RETURN n.name, similarity
ORDER BY similarity DESC
LIMIT 10;
4.查詢兩個節點的向量相似度
MATCH (a:GroupProductA {name: '保高空'})
MATCH (b:GroupProductA {name:'團意'})
RETURN vector.similarity.cosine(a.embedding, b.embedding)
5.查詢所有向量索引
SHOW VECTOR INDEXES
6.刪除指定向量索引
DROP INDEX moviePlots
三.全文索引檢索
1.要檢索前首先要創建全文索引.
CREATE FULLTEXT INDEX 索引名稱 FOR (n:標簽) ON EACH [n.節點屬性]
OPTIONS {
? indexConfig: {
??? `fulltext.analyzer`: 'cjk',
??? `fulltext.eventually_consistent`: true
? }
}
fulltext.analyzer是選用的分詞器
fulltext.eventually_consistent設置為true
,索引將處于最終一致性更新模式。這意味著更新將“盡快”在后臺線程中應用,而不是像其他索引那樣在事務提交期間應用
2.查看neo4j支持哪些分詞器
call?db.index.fulltext.listAvailableAnalyzers()
3.查詢所有全文索引
SHOW FULLTEXT INDEXES
4.全文索引查詢語句
CALL db.index.fulltext.queryNodes(索引名稱, 查詢的文本) YIELD node, score
RETURN node.節點屬性, score
三.RAG向量檢索最佳實踐
1.先查詢出所有符合的向量節點,有個閾值,比如大于0.8的查詢出所有符合的節點
2.然后再通過這些符合的節點,根據節點之間的關系,找到想要查詢出來的節點屬性
3.根據查詢出來的節點屬性和用戶問題,給大模型總結
4.可以考慮用全文索引和向量索引做混合搜索的RAG
其它
【
LangChain 是一個用于構建基于大語言模型(LLM)的應用程序的框架。它的核心作用是將語言模型與其他工具、數據來源等進行連接和協調,讓開發者能更便捷地搭建復雜的 LLM 應用,比如問答系統、聊天機器人、智能檢索等。
從網頁內容關聯來看,LangChain 可以與 Neo4j 結合使用,實現基于知識圖譜的增強型應用。例如,借助 LangChain 調用 Neo4j 時,需要安裝 APOC 插件,并在配置文件中進行相應設置(如添加?dbms.security.procedures.unrestricted=apoc.*,algo.*
),從而利用知識圖譜中的結構化數據提升 LLM 應用的準確性和邏輯性。
】
【
在這段關于Neo4j數據庫的描述中,**全文索引檢索**是一種針對節點屬性的文本內容進行高效搜索的技術,核心是通過預先創建“全文索引”,實現對節點屬性中關鍵詞、短語的快速匹配和檢索。以下是具體解析: ### 1. 核心作用 全文索引檢索的目的是解決“對節點屬性的文本內容進行靈活搜索”的需求。例如,若節點(如“電影”標簽的節點)有“簡介”屬性(包含長文本描述),通過全文索引可以快速找到包含“科幻”“導演XXX”等關鍵詞的所有節點,而無需逐行掃描所有節點的屬性,大幅提升檢索效率。 ### 2. 關鍵特點 - **依賴預創建的全文索引**:必須先通過`CREATE FULLTEXT INDEX`語句創建索引,明確要索引的節點標簽(`n:標簽`)和具體屬性(`n.節點屬性`),否則無法進行全文檢索。 - **支持分詞器配置**:通過`fulltext.analyzer`指定分詞規則(如示例中的`cjk`,適用于中文、日文、韓文等東亞語言的分詞),將文本拆分為有意義的“詞”,確保搜索時能準確匹配關鍵詞(例如中文“人工智能”會被正確拆分為“人工”“智能”,而非單個字符)。 - **索引更新模式**:`fulltext.eventually_consistent: true`表示索引采用“最終一致性”更新,即節點屬性變化后,索引不會立即更新,而是在后臺異步處理,適合對實時性要求不高但追求寫入性能的場景;若設為`false`,則索引在事務提交時同步更新,實時性高但可能影響寫入速度。 ### 3. 操作流程 - **創建索引**:通過`CREATE FULLTEXT INDEX`語句定義索引規則(關聯的節點標簽、屬性、分詞器等)。 - **查詢索引**:使用`CALL db.index.fulltext.queryNodes(索引名稱, 查詢文本)`執行檢索,返回匹配的節點(`node`)和匹配得分(`score`,得分越高表示匹配度越高)。 - **輔助操作**:可通過`call db.index.fulltext.listAvailableAnalyzers()`查看支持的分詞器,通過`SHOW FULLTEXT INDEXES`查看已創建的全文索引。 ### 4. 與RAG向量檢索的關系 文中提到“全文索引和向量索引做混合搜索的RAG”,說明兩者是互補的檢索方式: - 全文索引依賴關鍵詞匹配,適合精確查找包含特定詞匯的內容; - 向量檢索(如RAG中常用的)則通過文本語義向量的相似度匹配,適合理解“語義相關性”(例如“如何入門機器學習”和“機器學習新手教程”雖關鍵詞不同,但語義相近)。 混合使用可結合兩者優勢,提升檢索的準確性和全面性。 總結來說,全文索引檢索是Neo4j中針對文本內容的高效關鍵詞檢索方案,通過預定義索引和分詞規則,實現對節點屬性的快速文本匹配,是處理結構化圖形數據庫中文本搜索需求的重要工具。
】
最終我的代碼如下:
# 導入所需模塊
import os # 用于讀取環境變量(如Neo4j連接參數和API token)
import requests # 用于調用嵌入向量API
import json # 用于處理JSON數據
from neo4j import GraphDatabase # 用于連接Neo4j圖數據庫
from tqdm import tqdm # 用于添加處理進度條
import numpy as np # 用于處理數值型數據(雖然此處未直接使用)# ---------- 配置Neo4j連接 ----------
uri = os.getenv("NEO4J_URI", "bolt://localhost:7687") # 支持默認本地連接
username = os.getenv("NEO4J_USERNAME", "neo4j") # 默認用戶名
password = os.getenv("NEO4J_PASSWORD", "xxxx") # 默認密碼
driver = GraphDatabase.driver(uri, auth=(username, password)) # 創建Neo4j驅動器# ---------- 配置Qwen嵌入接口 ----------
API_URL = "https://api.siliconflow.cn/v1/embeddings" # 嵌入API URL
API_MODEL = "Qwen/Qwen3-Embedding-8B" # 嵌入模型名
API_TOKEN = "sk-jy
xxxxx" # 嵌入服務Token(默認示例)
HEADERS = {"Authorization": f"Bearer {API_TOKEN}", # Bearer鑒權頭"Content-Type": "application/json" # 數據格式為JSON
}# ---------- 獲取向量函數 ----------
def get_embedding(text):payload = {"model": API_MODEL,"input": text}response = requests.post(API_URL, headers=HEADERS, json=payload) # 發送POST請求if response.status_code == 200:return response.json()["data"][0]["embedding"] # 返回嵌入向量else:print("Embedding API error:", response.text) # 打印錯誤信息return None# ---------- 正式批量更新Concept節點向量 ----------
def update_concepts_with_embeddings():with driver.session() as session:result = session.run("MATCH (c:Concept) RETURN elementId(c) AS eid, c.name AS name, c.type AS type")for record in tqdm(result):node_eid = record["eid"]name = record["name"]type_list = record["type"]type_str = ", ".join(type_list) if isinstance(type_list, list) else str(type_list)name_vec = get_embedding(name)type_vec = get_embedding(type_str)if name_vec:session.run("MATCH (c:Concept) WHERE elementId(c) = $eid CALL db.create.setNodeVectorProperty(c, 'name_vector', $vec) RETURN c", eid=node_eid, vec=name_vec)if type_vec:session.run("MATCH (c:Concept) WHERE elementId(c) = $eid CALL db.create.setNodeVectorProperty(c, 'type_vector', $vec) RETURN c", eid=node_eid, vec=type_vec)# ---------- 小規模測試:僅更新前N個Concept節點 ----------
def test_update_concepts_with_embeddings(sample_size=5):print(f"🔍 測試開始:選取前 {sample_size} 個 Concept 節點進行嵌入更新")with driver.session() as session:result = session.run("""MATCH (c:Concept)RETURN elementId(c) AS eid, c.name AS name, c.type AS typeLIMIT $limit""",limit=sample_size)for record in result:node_eid = record["eid"]name = record["name"]type_list = record["type"]type_str = ", ".join(type_list) if isinstance(type_list, list) else str(type_list)print(f"\n🧠 節點ID: {node_eid}")print(f"📌 名稱: {name}")print(f"📎 類型: {type_str}")name_vec = get_embedding(name)type_vec = get_embedding(type_str)if name_vec:print(f"? name_vector 維度: {len(name_vec)}")session.run("MATCH (c:Concept) WHERE elementId(c) = $eid CALL db.create.setNodeVectorProperty(c, 'name_vector', $vec) RETURN c", eid=node_eid, vec=name_vec)else:print("? 獲取 name_vector 失敗")if type_vec:print(f"? type_vector 維度: {len(type_vec)}")session.run("MATCH (c:Concept) WHERE elementId(c) = $eid CALL db.create.setNodeVectorProperty(c, 'type_vector', $vec) RETURN c", eid=node_eid, vec=type_vec)else:print("? 獲取 type_vector 失敗")print("? 測試完成,請前往 Neo4j Studio 檢查節點屬性是否正確更新。")# ---------- 創建向量索引(Neo4j 5+) ----------
def create_vector_index():vector_dim = 4096 # Qwen 模型返回向量維度為 4096with driver.session() as session:session.run(f"""CREATE VECTOR INDEX concept_name_vector_indexFOR (c:Concept) ON (c.name_vector)OPTIONS {{indexConfig: {{`vector.dimensions`: {vector_dim}, `vector.similarity_function`: 'cosine'}}}}""")session.run(f"""CREATE VECTOR INDEX concept_type_vector_indexFOR (c:Concept) ON (c.type_vector)OPTIONS {{indexConfig: {{`vector.dimensions`: {vector_dim}, `vector.similarity_function`: 'cosine'}}}}""")# ---------- 相似節點查詢函數 ----------
def query_similar_concepts(input_term):query_vec = get_embedding(input_term)if not query_vec:return []with driver.session() as session:try:result = session.run("""CALL db.index.vector.queryNodes('concept_name_vector_index', 3, $embedding)YIELD node, scoreWHERE score >= 0.8RETURN node.CUI AS cui, node.name AS name, scoreORDER BY score DESC""",embedding=query_vec)return result.data()except Exception as e:print("? 查詢失敗,請確認索引是否創建:", str(e))return []# ---------- 主程序入口 ----------
if __name__ == "__main__":# ? 創建索引(若首次運行)create_vector_index()# ? 測試模式:小批量處理# test_update_concepts_with_embeddings(sample_size=5)# ?? 正式運行時請取消注釋以下行# update_concepts_with_embeddings()# ? 查詢測試concept_results = query_similar_concepts("Retired procedure")for item in concept_results:print(f"CUI: {item['cui']}, 名稱: {item['name']}, 相似度: {item['score']:.4f}")
?
測試效果如下:
neo4j中向量也放上去了?