導航:首頁 > 數據處理 > 圖片資料庫包括哪些

圖片資料庫包括哪些

發布時間:2023-04-25 20:27:36

Ⅰ 開源圖資料庫有哪些

Neo4j、JanusGraph、TigerGraph、Dgraph這些都是,其實大多數的圖資料庫都是開源的,圖資料庫、圖計算都算比較新的東西,還需要開源後大家共同去改進。這些都是國外的,其實國內大廠也開始做圖資料庫、圖計算相關的軟體了,比如阿里的GraphScope、位元組的ByteGraph。

Ⅱ 什麽是Graph database

圖形資料庫(graphic database)是利用計算機將點、線、畫霹圖形基本元素按一定數據結同灶行存儲的數據集合,將地圖與其它類型的平面圖中的圖形描述為點、線、面等基本元素,並將這些圖形元素按一定數據結構(通常為拓撲數據結構)建立起來的數據集合。包括兩個層次:第一層次為拓撲編碼的數據集合,由描述點、線大模、面等圖形元素間關系的數據文件組成,包括多邊形文件、線段文件、結點文辯襪件等。文件間通過關聯數據項相互聯系;第二層次為坐標編碼數據集合,由描述各圖形元素空間位置的坐標文件組成。圖形數據攜仿激庫仍是目前地理信息系統中對矢量結構地圖數字化數據進行組織的主要形式。

Ⅲ 哪類資料庫處理圖像類數據

image類型的資料庫、圖像資料庫處理圖像類數據。
圖像資料庫系統由數據輸入系統、數據表示與管理系統、數據檢索與操作系統和應用系早塌統組成。圖像資料庫系統處理的對象包括圖像數據、地圖、圖形數據、一般文本、圖形等,統稱為模式數據。數據輸入系統從模式數據中提取計算機可以使用的信息。一個典型的好粗例子是自動地將圖輸入系統。典型的應用系統包括:利用地圖數據的地理信息系統、利用遙感圖像的土地信息系統、利用各種繪圖數據的計算機輔助設計系統、陸襪圓計算機動畫設計系統以及其他圖像處理和圖案信息處理系統。

Ⅳ 國內圖資料庫排名前三的有哪些

DB-Engines 資料庫流行度排行榜 6 月更新已發布,排名前二十如下:總體排名和上個月相比基本一致,其中排名前三的 Oracle、MySQL 和 Microsoft SQL Server 也是分數增加最多的三個資料庫,增加的分數分別為 13.67、4.67 和 15.57,三者的總分也均已超過一千。

Ⅳ 用什麼資料庫來存儲圖片

一、圖片一般是存儲為路徑的,這樣存取速度快,也方便
二、如果非要存在資料庫中的話,可以存為二進制數據,只是存取比較麻煩,效率和性能也不高

Ⅵ 圖資料庫的應用有哪些優點

圖形資料庫每個對象是一個節點,之間的關系是一條邊。相對於關系資料庫來說,圖形資料庫善於處理大量復雜、互連接、低結構化的數據,這些數據變化迅速,需要頻繁的查詢——在關系資料庫中,由於這些查詢會導致大量的表連接,從而導致性能問題,而且在設計使用上也不方便。
圖形資料庫適合用於社交網路,推薦系統等專注於構建關系圖譜的系統。
圖資料庫的代表有Neo4J、FlockDB、InfoGrid、AllegroGraph、GraphDB等。

Ⅶ 基礎資料庫

(一)數據內容

基礎資料庫包括系統運行前所採集到的所有支撐數據,數據的具體內容在數據分類與數據源章節中已描述,概括可分為以下幾類。

(1)遙感影像數據:包括歷史圖像數據,以及按照一定監測周期更新的遙感圖像數據。

(2)數字線劃圖數據:矢量數據(現狀專題圖和歷史專題圖數據)、柵格數據、元數據等。入庫前數據以ArcInfoCoverage格式分幅或整體存儲,採用地理坐標系統。

(3)數字柵格圖數據:包括1∶5萬和1∶10萬基礎地理圖形數據的掃描柵格數據。

(4)數字高程模型數據:塔里木河幹流河道1∶1萬和「四源一干」區域1∶10萬數字高程模型。

(5)多媒體數據:考察照片、錄像、錄音和虛擬演示成果等多媒體資料。

(6)屬性數據:社會經濟與水資源數據、水利工程數據、生態環境數據等。

(二)數據存儲結構

1.柵格數據

柵格數據包括遙感影像、數字柵格圖、數字正射影像圖、數字高程模型等,這些數據的存儲結構基本類似,因此可進行統一設計。遙感圖像資料庫與普通的圖像資料庫在存儲上有些差別,遙感圖像作為感測器對地理、空間環境在不同條件下的測量結果(如光譜輻射特性、微波輻射特性),必須結合同時得到的幾個圖像才可以認為是對環境在一定的時間條件下的完整的描述,也即是說,可能需要一個圖像集合才能構成一個圖像的完整的概念,並使之與語義信息產生聯系(羅睿等,2000)。因此,遙感圖像數據存儲結構模型必須能夠描述幾個圖像(波段)之間的邏輯關系。利用ArcSDE進行數據入庫時,系統可自動建立各圖像(波段)之間的關系,並按一定規則存儲在資料庫系統中。

對柵格數據在後台將採用Oracle資料庫管理系統進行存儲。Oracle系統可直接存儲影像信息,並具有較強的數據管理能力,可以實現柵格數據信息的快速檢索和提取。數據引擎採用ArcSDE,實現各類影像數據的入庫。數據存儲的關鍵是建立圖幅索引,本系統數據的存儲按圖幅號、圖名、採集時間等內容建立索引。

柵格數據依據圖形屬性一體化的存儲思想,採用大二進制格式直接存儲數據,這種方式的存儲可實現內容的快速檢索查詢,按索引表檢索出相關項後可直接打開柵格數據,提高柵格數據的管理效率。

2.矢量數據

本系統採用圖屬一體化思想即將空間數據和屬性數據合二為一,全部存在一個記錄集中的思想存儲空間數據,是目前GIS數據非常流行的存儲方法。考慮到數據的具體情況,決定採用資料庫存儲空間數據和屬性數據,部分具有少量、定型幾何信息的地理要素如水文測站、河流、湖泊等,採用圖屬一體化思想存儲其信息,而與其有關聯關系的大量、多邊化的屬性信息如水文信息,則存儲在屬性數據表中,利用唯一標識符信息建立兩表的關聯。

針對本系統空間數據的特點,系統按照「資料庫—子庫—專題(基礎數據)—層—要素—屬性」的層次框架來構築空間資料庫,按照統一的地理坐標系統來存儲空間數據,以實現對地理實體/專題要素進行分層疊加顯示。

3.多媒體數據

Oracle系統可直接存儲圖片和視頻信息,並具有較強的數據管理能力,可以實現多媒體信息的快速檢索和提取。多媒體數據存儲的關鍵是建立索引表,本系統多媒體數據的存儲按類型、時間、內容等項目建立索引,直接存儲於Oracle資料庫中。

多媒體數據存儲時,可以將多媒體內容與索引表結構合為一體,採用大二進制格式直接存儲,這種存儲方式可實現內容的快速檢索和查詢,按索引表檢索出相關項後可直接打開多媒體內容,而且多媒體資料庫也便於維護管理。

(三)空間索引設計

1.矢量空間索引

確定合適的格網級數、單元大小是建立空間格網索引的關鍵。格網太大,在一個格網內有多個空間實體,查詢檢索的准確度就低。格網太小,則索引數據量成倍增長和冗餘,檢索的速度和效率低。每一個數據層可採用不同大小、不同級別的空間索引格網單元,但每層級數最多不能超過三級。索引方式設置遵循以下基本原則:

(1)對於簡單要素的數據層,盡可能選擇單級索引格網,減少RDBMS搜索格網單元索引的級數,縮短空間索引搜索的過程;

(2)如果數據層中的要素封裝邊界大小變化比較大,應選擇2或3級索引格網;

(3)如果用戶經常對圖層執行相同的查詢,最佳格網的大小應是平均查詢范圍的1.5倍;

(4)格網的大小不能小於要素封裝邊界的平均大小。為了減少每個格網單元有多個要素封裝邊界的可能性,格網單元的大小應取要素封裝邊界平均大小的3倍;

(5)格網單元的大小不是一個確定性的問題,需要多次嘗試和努力才會得到好的結果。有一些確定格網初始值的原則,用它們可以進一步確定最佳的格網大小。

SDE(Spatial Data Engine,即空間數據引擎),從空間管理的角度看,是一個連續的空間數據模型,可將地理特徵的空間數據和屬性數據統一集成在關系型資料庫管理系統中。關系型資料庫系統支持對海量數據的存儲,從而也可實現對空間數據的海量存儲。空間數據可通過層來進行數據的劃分,將具有共同屬性的一類要素放到一層中,每個資料庫記錄對應一層中一個實際要素,這樣避免了檢索整個數據表,減少了檢索的數據記錄數量,從而減少磁碟輸入/輸出的操作,加快了對空間數據查詢的速度。

ArcSDE採用格網索引方式,將空間區域劃分成合適大小的正方形格網,記錄每一個格網內所包含的空間實體(對象),以及每一個實體的封裝邊界范圍,即包圍空間實體的左下角和右上角坐標。當用戶進行空間查詢時,首先計算出用戶查詢對象所在格網,然後通過格網號,就可以快速檢索到所需的空間實體。因此確定合適的格網級數、單元大小是建立空間格網索引的關鍵,太大或太小均不合適,這就需要進行多次嘗試,確定合適的網格大小,以保證各單元能均勻落在網格內。利用ArcSDE的索引表創建功能,記錄每一網格單元的實體分布情況,形成圖層空間索引表。根據空間索引表,ArcSDE實現了對空間數據的快速查詢。

2.柵格數據空間索引

柵格數據的空間索引通過建立多級金字塔結構來實現。以高解析度柵格數據為底層,逐級抽取數據,建立不同解析度的數據金字塔結構,逐級形成較低解析度的柵格數據。該方法通常會增加20%左右的存儲空間,但卻可以提高柵格數據的顯示速度。在資料庫查詢檢索時,調用合適級別的柵格數據,可提高瀏覽和顯示速度。

(四)入庫數據校驗

入庫數據的質量關繫到系統評價分析結果的准確性。數據在生產中就需要嚴格進行質量控制。依據數據生產流程,將數據質量控制分成生產過程式控制制和結果控制。生產過程式控制制包括數據生產前期的質量控制、數據生產過程中的實時質量控制,結果質量控制為數據生產完成後的質量控制(裴亞波等,2003)。對入庫數據的校驗主要是進行數據生產完成後的質量控制和檢查。

1.規范化檢查

(1)代碼規范化:所有地理代碼盡量採用國家標准和行業標准,例如,行政代碼採用中華人民共和國行政區劃代碼國標。

(2)數據格式規范化:所有數據採用標准交換數據格式,例如,矢量數據採用標准輸出Coverage格式和E00格式。

(3)屬性數據和關系數據欄位規范化:所有屬性數據和關系數據提前分門別類地設計欄位的內容、長短和格式,操作過程中嚴格執行。

(4)坐標系統規范化:本系統所有與空間有關的數據採用統一的空間坐標系統,即地理坐標系統。

(5)精度規范化:所有數據按照數據精度與質量控制中所要求的精度進行採集和處理。

(6)命名規范化:所有數據按照命名要求統一命名,便於系統的查詢。

(7)元數據規范化:依照元數據標准要求,進行元數據檢查。

2.質量控制

數據質量是GIS成敗的關鍵。對於關系型資料庫設計,只要能保證表的實體完整性和參照完整性,並使之符合關系資料庫的三個範式即可。對於空間資料庫設計,則不僅要考慮數據采樣、數據處理流程、空間配准、投影變換等問題,還應對數據質量做出定量分析。

數據質量一般可以通過以下幾個方面來描述(吳芳華等,2001):

(1)准確度(Accuracy):即測量值與真值之間的接近程度,可用誤差來衡量;

(2)精度(Precision):即對現象描述得詳細程度;

(3)不確定性(Uncertainty):指某現象不能精確測得,當真值不可測或無法知道時,就無法確定誤差,因而用不確定性取代誤差;

(4)相容性(Compatibility):指兩個來源不同的數據在同一個應用中使用的難易程度;

(5)一致性(Consistency):指對同一現象或同類現象表達的一致程度;

(6)完整性(Completeness):指具有同一準確度和精度的數據在類型上和特定空間范圍內完整的程度;

(7)可得性(Accessibility):指獲取或使用數據的容易程度;

(8)現勢性(Timeliness):指數據反映客觀現象目前狀況的程度。

塔里木河流域生態環境動態監測系統的所有數據在數據質量評價後,還需要從數據格式、坐標一致性等方面進行入庫質量檢驗,只有通過質量檢驗的數據才可以入庫。

3.數據檢驗

空間數據質量檢驗包括以下步驟:

(1)數據命名是否規范,是否按設計要求命名;

(2)數據是否能夠正常打開;

(3)投影方式是否正確;

(4)坐標系統是否正確;

(5)改錯是否完成,拓撲關系是否建立;

(6)屬性數據是否正確,包括欄位設置是否依據設計進行、是否有空屬性記錄、是否有屬性錯誤記錄等。

關系數據質量檢驗包括以下步驟:

(1)數據命名是否規范,是否按設計要求命名;

(2)數據是否能夠正常打開;

(3)數據欄位是否按設計要求設置;

(4)是否有空屬性記錄;

(5)是否有屬性錯誤記錄。

屬性數據的校驗,主要採用以下三種方式:

(1)兩次錄入校驗:對一些相互之間毫無關聯的數據,進行兩次的錄入,編寫程序對兩次錄入的結果進行比較,找出兩次錄入結果不一樣的數據,查看正確值,進行改正。

(2)折線圖檢驗:對一些相互之間有關聯的序列數據,如人口統計數據,對這一類數據,編寫程序把數據以折線圖的形式顯示在顯示器上,數據的序列一般都有一定規律,如果出現較大的波動,則需對此點的數據進行檢查修改。

(3)計算校驗:對一些按一定公式計算後所得結果與其他數據有關聯的數據,如某些數據的合計等於另一數據,編寫程序對這類數據進行計算,計算結果與有關聯的數據進行比較,找出結果不一樣的數據,查看正確值,進行改正。

圖形數據的校驗,主要包括以下步驟(陳俊傑等,2005):

(1)圖層校驗:圖形要素的放置圖層是唯一的。對於入庫的Coverage數據,系統將根據圖層代碼進行檢查,確保圖形要素對層入座。

(2)代碼檢查:圖形要素的代碼是唯一的。對於入庫的Coverage數據,系統將根據入庫要素代碼與特徵表中的代碼進行比較,確保入庫數據代碼存在,杜絕非法代碼入庫。

(3)類型檢查:對入庫的數據,檢查該要素的類型與特徵表中的類型是否一致,確保圖形要素對表入座。如點要素、線要素、面要素僅能賦相應的點、線、面代碼,且該代碼必須與特徵表中的數據類型代碼相同。

(4)范圍檢查:根據入庫的數據,確定該類要素的大體范圍(如X、Y坐標等),在數據入庫前,比較入庫數據與范圍數據的大小,若入庫數據在該范圍內,則入庫,否則給出提示檢查信息。

(五)數據入庫

1.遙感影像數據

利用空間數據引擎———ArcSDE可實現遙感影像數據在Oracle資料庫中的存儲和管理,在影像數據進行入庫時,應加入相應的索引和影像描述欄位。

遙感影像入庫步驟:

(1)影像數據預處理:要將塔里木河遙感影像資料庫建成一個多解析度無縫影像資料庫系統,客觀上要求資料庫中的影像數據在幾何空間、灰度空間連續一致。因此,在數據採集階段就需要對影像數據進行預處理,包括圖像幾何校正、灰度拼接(無縫鑲嵌)、正射處理、投影變換等。

幾何校正的目的是使校正後的圖像重新定位到某種地圖投影方式,以適用於各種定位、量測、多源影像的復合及與矢量地圖、DTM等的套合顯示與處理。幾何校正多採用二次多項式演算法和圖像雙線性內插重采樣法進行圖像校正。將糾正後具有規定地理編碼的圖像按多邊形圈定需要拼接的子區,逐一鑲嵌到指定模版,同時進行必要的色彩匹配,使整體圖像色調一致,完成圖像的幾何拼接,再採用金字塔影像數據結構和「從粗到精」的分層控制策略實現逐級拼接。

數字正射影像具有統一的大地坐標系、豐富的信息量和真實的景觀表達,易於製作具有「獨立於比例尺」的多級金字塔結構影像。可以採用DTM和外方位元素經過數字微分糾正方法,獲得數字正射影像,它的基本參數包括原始影像與正射影像的比例尺、采樣解析度等(方濤等,1997)。

投影變換需根據資料庫系統定義的標准轉換到統一的投影體系下。

(2)影像數據壓縮:隨著感測器空間解析度的提高和對遙感信息需求的日益增長,獲取的影像數據量成幾何級數增大,如此龐大的數據將佔用較大的存儲空間,給影像的存儲和傳輸帶來不便(葛詠等,2000)。目前,系統處理的遙感影像數據已達數百千兆,單個文件的影像數據最大達到了2G,這樣的數據量在調用顯示時速度很慢,對影像數據進行壓縮存儲,將大大提高影像訪問效率。本系統採用ArcSDE軟體提供的無損壓縮模式對入庫影像進行壓縮。

(3)影像導入:遙感影像的入庫可通過ArcSDE或入庫程序進行導入,並填寫相關的索引信息,在入庫時對大型的遙感影像數據進行自動分割,分為若乾的塊(tiles)進行存儲。

(4)圖像金字塔構建:採用ArcSDE提供的金字塔構建工具在入庫時自動生成圖像金字塔,用戶只需要選擇相應的參數設置即可。圖像金字塔及其層級圖像按解析度分級存儲與管理。最底層的解析度最高,並且數據量最大,解析度越低,其數據量越小,這樣,不同的解析度遙感圖像形成了塔式結構。採用這種圖像金字塔結構建立的遙感影像資料庫,便於組織、存儲與管理多尺度、多數據源遙感影像數據,實現了跨解析度的索引與瀏覽,極大地提高了影像數據的瀏覽顯示速度。

2.數字線劃圖

對紙圖數字化、配准、校正、分層及拼接等處理後,生成標准分幅和拼接存儲的數字矢量圖,就可以進行圖形數據入庫。

(1)分幅矢量圖形數據、圖幅接合表:按圖形比例尺、圖幅號、製作時間、圖層等方式,通過入庫程序導入到資料庫中,同時導入與該地理信息相對應的屬性信息,建立空間信息與屬性信息的關聯。

(2)拼接矢量圖形數據:按圖形比例尺、製作時間、圖層等方式,通過入庫程序導入到資料庫中,同時導入與該地理信息相對應的屬性信息,建立空間信息與屬性信息的關聯。

3.柵格數據

對紙圖數字化、配准、校正、分層及拼接等處理後,生成標准分幅和整體存儲的數字柵格圖,然後進行圖形數據入庫。

(1)分幅柵格圖形數據、圖幅接合表:按圖形比例尺、圖幅號、製作時間等方式,通過入庫程序導入到資料庫中。

(2)整幅柵格圖形數據:按比例尺、製作時間等方式,通過入庫程序導入到資料庫中。

4.數字高程模型

(1)分幅數字高程模型數據、圖幅接合表:按圖形比例尺、圖幅號、製作時間等方式,通過入庫程序導入到資料庫中。

(2)拼接數字高程模型數據:按比例尺、製作時間等方式通過入庫程序導入到資料庫中。

5.多媒體數據

多媒體數據入庫可根據多媒體資料庫內容的需要對入庫數據進行預處理,包括音頻、視頻信息錄制剪接、文字編輯、色彩選配等。對多媒體信息的加工處理需要使用特定的工具軟體進行編輯。由於音頻信息和視頻信息數據量巨大,因此,對多媒體數據存儲時需採用數據壓縮技術,現在的許多商用軟體已能夠直接存儲或播放壓縮後的多媒體數據文件,這里主要考慮根據數據顯示質量要求選擇採用不同的存儲格式。圖4-2為各類多媒體數據的加工處理流程。

圖4-2 多媒體數據加工處理流程圖

6.屬性數據

將收集的社會經濟、水利工程、生態環境等屬性資料,進行分析整理,輸入計算機,最後經過程序的計算處理,存儲到資料庫中,具體流程如圖4-3所示。

圖4-3 屬性數據入庫流程圖

Ⅷ 資料庫 能不能 存儲 圖片有哪些資料庫可以sql server,my sql 可以嗎

關系資料庫都可以存儲圖片,不絕啟過是以困宏爛二進制數所的形式存儲的。
故:oracle、汪漏db2、sqlserver、mysql等都可以。

有問題歡迎提問,滿意請採納!

Ⅸ 什麼是圖資料庫

圖資料庫(Graph database) 並非指存儲圖片的資料庫,而是以「圖」這種數據結構存儲和查詢數據。目前比較典型的代表產品是Neo4j。

Ⅹ 如何用 Python 實現一個圖資料庫(Graph Database)

本文章是 重寫 500 Lines or Less 系列的其中一篇,目標是重寫 500 Lines or Less 系列的原有項目:Dagoba: an in-memory graph database。

Dagoba 是作者設計用來展示如何從零開始自己實現一個圖資料庫( Graph Database )。該名字似乎來源於作者喜歡的一個樂隊,另一個原因是它的前綴 DAG 也正好是有向無環圖 ( Directed Acyclic Graph ) 的縮寫。本文也沿用了該名稱。

圖是一種常見的數據結構,它將信息描述為若干獨立的節點( vertex ,為了和下文的邊更加對稱,本文中稱為 node ),以及把節點關聯起來的邊( edge )。我們熟悉的鏈表以及多種樹結構可以看作是符合特定規則的圖。圖在路徑選擇、推薦演算法以及神經網路等方面都是重要的核心數據結構。

既然圖的用途如此廣泛,一個重要的問題就是如何存儲它。如果在傳統的關系資料庫中存儲圖,很自然的做法就是為節點和邊各自創建一張表,並用外鍵把它們關聯起來。這樣的話,要查找某人所有的子女,就可以寫下類似下面的查詢:

還好,不算太復雜。但是如果要查找孫輩呢?那恐怕就要使用子查詢或者 CTE(Common Table Expression) 等特殊構造了。再往下想,曾孫輩又該怎麼查詢?孫媳婦呢?

這樣我們會意識到,SQL 作為查詢語言,它只是對二維數據表這種結構而設計的,用它去查詢圖的話非常笨拙,很快會變得極其復雜,也難以擴展。針對圖而言,我們希望有一種更為自然和直觀的查詢語法,類似這樣:

為了高效地存儲和查詢圖這種數據結構,圖資料庫( Graph Database )應運而生。因為和傳統的關系型資料庫存在極大的差異,所以它屬於新型資料庫也就是 NoSql 的一個分支(其他分支包括文檔資料庫、列資料庫等)。圖資料庫的主要代表包括 Neo4J 等。本文介紹的 Dagoba 則是具備圖資料庫核心功能、主要用於教學和演示的一個簡單的圖資料庫。

原文代碼是使用 JavaScript 編寫的,在定義調用介面時大量使用了原型( prototype )這種特有的語言構造。對於其他主流語言的用戶來說,原型的用法多少顯得有些別扭和不自然。

考慮到本系列其他資料庫示例大多是用 Python 實現的,本文也按照傳統,用 Python 重寫了原文的代碼。同樣延續之前的慣例,為了讓讀者更好地理解程序是如何逐步完善的,我們用迭代式的方法完成程序的各個組成部分。

原文在 500lines 系列的 Github 倉庫中只包含了實現代碼,並未包含測試。按照代碼注釋說明,測試程序位於作者的另一個代碼庫中,不過和 500lines 版本的實現似乎略有不同。

本文實現的代碼參考了原作者的測試內容,但跳過了北歐神話這個例子——我承認確實不熟悉這些神祇之間的親緣關系,相信中文背景的讀者們多數也未必了解,雖然作者很喜歡這個例子,想了想還是不要徒增困惑吧。因此本文在編寫測試用例時只參考了原文關於家族親屬的例子,放棄了神話相關的部分,盡管會減少一些趣味性,相信對於入門級的代碼來說這樣也夠用了。

本文實現程序位於代碼庫的 dagoba 目錄下。按照本系列程序的同意規則,要想直接執行各個已完成的步驟,讀者可以在根目錄下的 main.py 找到相應的代碼位置,取消注釋並運行即可。

本程序的所有步驟只需要 Python3 ,測試則使用內置的 unittest , 不需要額外的第三方庫。原則上 Python3.6 以上版本應該都可運行,但我只在 Python3.8.3 環境下完整測試過。

本文實現的程序從最簡單的案例開始,通過每個步驟逐步擴展,最終形成一個完整的程序。這些步驟包括:

接下來依次介紹各個步驟。

回想一下,圖資料庫就是一些點( node )和邊( edge )的集合。現在我們要做出的一個重大決策是如何對節點/邊進行建模。對於邊來說,必須指定它的關聯關系,也就是從哪個節點指向哪個節點。大多數情況下邊是有方向的——父子關系不指明方向可是要亂套的!

考慮到擴展性及通用性問題,我們可以把數據保存為字典( dict ),這樣可以方便地添加用戶需要的任何數據。某些數據是為資料庫內部管理而保留的,為了明確區分,可以這樣約定:以下劃線開頭的特殊欄位由資料庫內部維護,類似於私有成員,用戶不應該自己去修改它們。這也是 Python 社區普遍遵循的約定。

此外,節點和邊存在互相引用的關系。目前我們知道邊會引用到兩端的節點,後面還會看到,為了提高效率,節點也會引用到邊。如果僅僅在內存中維護它們的關系,那麼使用指針訪問是很直觀的,但資料庫必須考慮到序列化到磁碟的問題,這時指針就不再好用了。

為此,最好按照資料庫的一般要求,為每個節點維護一個主鍵( _id ),用主鍵來描述它們之間的關聯關系。

我們第一步要把資料庫的模型建立起來。為了測試目的,我們使用一個最簡單的資料庫模型,它只包含兩個節點和一條邊,如下所示:

按照 TDD 的原則,首先編寫測試:

與原文一樣,我們把資料庫管理介面命名為 Dagoba 。目前,能夠想到的最簡單的測試是確認節點和邊是否已經添加到資料庫中:

assert_item 是一個輔助方法,用於檢查字典是否包含預期的欄位。相信大家都能想到該如何實現,這里就不再列出了,讀者可參考 Github 上的完整源碼。

現在,測試是失敗的。用最簡單的辦法實現資料庫:

需要注意的是,不管添加節點還是查詢,程序都使用了拷貝後的數據副本,而不是直接使用原始數據。為什麼要這樣做?因為字典是可變的,用戶可以在任何時候修改其中的內容,如果資料庫不知道數據已經變化,就很容易發生難以追蹤的一致性問題,最糟糕的情況下會使得數據內容徹底混亂。

拷貝數據可以避免上述問題,代價則是需要佔用更多內存和處理時間。對於資料庫來說,通常查詢次數要遠遠多於修改,所以這個代價是可以接受的。

現在測試應該正常通過了。為了讓它更加完善,我們可以再測試一些邊緣情況,看看資料庫能否正確處理異常數據,比如:

例如,如果用戶嘗試添加重復主鍵,我們預期應拋出 ValueError 異常。因此編寫測試如下:

為了滿足以上測試,代碼需要稍作修改。特別是按照 id 查找主鍵是個常用操作,通過遍歷的方法效率太低了,最好是能夠通過主鍵直接訪問。因此在資料庫中再增加一個字典:

完整代碼請參考 Github 倉庫。

在上個步驟,我們在初始化資料庫時為節點明確指定了主鍵。按照資料庫設計的一般原則,主鍵最好是不具有業務含義的代理主鍵( Surrogate key ),用戶不應該關心它具體的值是什麼,因此讓資料庫去管理主鍵通常是更為合理的。當然,在部分場景下——比如導入外部數據——明確指定主鍵仍然是有用的。

為了同時支持這些要求,我們這樣約定:欄位 _id 表示節點的主鍵,如果用戶指定了該欄位,則使用用戶設置的值(當然,用戶有責任保證它們不會重復);否則,由資料庫自動為它分配一個主鍵。

如果主鍵是資料庫生成的,事先無法預知它的值是什麼,而邊( edge )必須指定它所指向的節點,因此必須在主鍵生成後才能添加。由於這個原因,在動態生成主鍵的情況下,資料庫的初始化會略微復雜一些。還是先寫一個測試:

為支持此功能,我們在資料庫中添加一個內部欄位 _next_id 用於生成主鍵,並讓 add_node 方法返回新生成的主鍵:

接下來,再確認一下邊是否可以正常訪問:

運行測試,一切正常。這個步驟很輕松地完成了,不過兩個測試( DbModelTest 和 PrimaryKeyTest )出現了一些重復代碼,比如 get_item 。我們可以把這些公用代碼提取出來。由於 get_item 內部調用了 TestCase.assertXXX 等方法,看起來應該使用繼承,但從 TestCase 派生基類容易引起一些潛在的問題,所以我轉而使用另一個技巧 Mixin :

實現資料庫模型之後,接下來就要考慮如何查詢它了。

在設計查詢時要考慮幾個問題。對於圖的訪問來說,幾乎總是由某個節點(或符合條件的某一類節點)開始,從與它相鄰的邊跳轉到其他節點,依次類推。所以鏈式調用對查詢來說是一種很自然的風格。舉例來說,要知道 Tom 的孫子養了幾只貓,可以使用類似這樣的查詢:

可以想像,以上每個方法都應該返回符合條件的節點集合。這種實現是很直觀的,不過存在一個潛在的問題:很多時候用戶只需要一小部分結果,如果它總是不計代價地給我們一個巨大的集合,會造成極大的浪費。比如以下查詢:

為了避免不必要的浪費,我們需要另外一種機制,也就是通常所稱的「懶式查詢」或「延遲查詢」。它的基本思想是,當我們調用查詢方法時,它只是把查詢條件記錄下來,而並不立即返回結果,直到明確調用某些方法時才真正去查詢資料庫。

如果讀者比較熟悉流行的 Python ORM,比如 SqlAlchemy 或者 Django ORM 的話,會知道它們幾乎都是懶式查詢的,要調用 list(result) 或者 result[0:10] 這樣的方法才能得到具體的查詢結果。

在 Dagoba 中把觸發查詢的方法定義為 run 。也就是說,以下查詢執行到 run 時才真正去查找數據:

和懶式查詢( Lazy Query )相對應的,直接返回結果的方法一般稱作主動查詢( Eager Query )。主動查詢和懶式查詢的內在查找邏輯基本上是相同的,區別只在於觸發機制不同。由於主動查詢實現起來更加簡單,出錯也更容易排查,因此我們先從主動查詢開始實現。

還是從測試開始。前面測試所用的簡單資料庫數據太少,難以滿足查詢要求,所以這一步先來創建一個更復雜的數據模型:

此關系的復雜之處之一在於反向關聯:如果 A 是 B 的哥哥,那麼 B 就是 A 的弟弟/妹妹,為了查詢到他們彼此之間的關系,正向關聯和反向關聯都需要存在,因此在初始化資料庫時需要定義的邊數量會很多。

當然,父子之間也存在反向關聯的問題,為了讓問題稍微簡化一些,我們目前只需要向下(子孫輩)查找,可以稍微減少一些關聯數量。

因此,我們定義數據模型如下。為了減少重復工作,我們通過 _backward 欄位定義反向關聯,而資料庫內部為了查詢方便,需要把它維護成兩條邊:

然後,測試一個最簡單的查詢,比如查找某人的所有孫輩:

這里 outcome/income 分別表示從某個節點出發、或到達它的節點集合。在原作者的代碼中把上述方法稱為 out/in 。當然這樣看起來更加簡潔,可惜的是 in 在 Python 中是個關鍵字,無法作為函數名。我也考慮過加個下劃線比如 out_.in_ 這種形式,但看起來也有點怪異,權衡之後還是使用了稍微啰嗦一點的名稱。

現在我們可以開始定義查詢介面了。在前面已經說過,我們計劃分別實現兩種查詢,包括主動查詢( Eager Query )以及延遲查詢( Lazy Query )。

它們的內在查詢邏輯是相通的,看起來似乎可以使用繼承。不過遵循 YAGNI 原則,目前先不這樣做,而是只定義兩個新類,在滿足測試的基礎上不斷擴展。以後我們會看到,與繼承相比,把共同的邏輯放到資料庫本身其實是更為合理的。

接下來實現訪問節點的方法。由於 EagerQuery 調用查詢方法會立即返回結果,我們把結果記錄在 _result 內部欄位中。雖然 node 方法只返回單個結果,但考慮到其他查詢方法幾乎都是返回集合,為統一起見,讓它也返回集合,這樣可以避免同時支持集合與單結果的分支處理,讓代碼更加簡潔、不容易出錯。此外,如果查詢對象不存在的話,我們只返回空集合,並不視為一個錯誤。

查詢輸入/輸出節點的方法實現類似這樣:

查找節點的核心邏輯在資料庫本身定義:

以上使用了內部定義的一些輔助查詢方法。用類似的邏輯再定義 income ,它們的實現都很簡單,讀者可以直接參考源碼,此處不再贅述。

在此步驟的最後,我們再實現一個優化。當多次調用查詢方法後,結果可能會返回重復的數據,很多時候這是不必要的。就像關系資料庫通常支持 unique/distinct 一樣,我們也希望 Dagoba 能夠過濾重復的數據。

假設我們要查詢某人所有孩子的祖父,顯然不管有多少孩子,他們的祖父應該是同一個人。因此編寫測試如下:

現在來實現 unique 。我們只要按照主鍵把重復數據去掉即可:

在上個步驟,初始化資料庫指定了雙向關聯,但並未測試它們。因為我們還沒有編寫代碼去支持它們,現在增加一個測試,它應該是失敗的:

運行測試,的確失敗了。我們看看要如何支持它。回想一下,當從邊查找節點時,使用的是以下方法:

這里也有一個潛在的問題:調用 self.edges 意味著遍歷所有邊,當資料庫內容較多時,這是巨大的浪費。為了提高性能,我們可以把與節點相關的邊記錄在節點本身,這樣要查找邊只要看節點本身即可。在初始化時定義出入邊的集合:

在添加邊時,我們要同時把它們對應的關系同時更新到節點,此外還要維護反向關聯。這涉及對字典內容的部分復制,先編寫一個輔助方法:

然後,將添加邊的實現修改如下:

這里的代碼同時添加正向關聯和反向關聯。有的朋友可能會注意到代碼略有重復,是的,但是重復僅出現在該函數內部,本著「三則重構」的原則,暫時不去提取代碼。

實現之後,前面的測試就可以正常通過了。

在這個步驟中,我們來實現延遲查詢( Lazy Query )。

延遲查詢的要求是,當調用查詢方法時並不立即執行,而是推遲到調用特定方法,比如 run 時才執行整個查詢,返回結果。

延遲查詢的實現要比主動查詢復雜一些。為了實現延遲查詢,查詢方法的實現不能直接返回結果,而是記錄要執行的動作以及傳入的參數,到調用 run 時再依次執行前面記錄下來的內容。

如果你去看作者的實現,會發現他是用一個數據結構記錄執行操作和參數,此外還有一部分邏輯用來分派對每種結構要執行的動作。這樣當然是可行的,但數據處理和分派部分的實現會比較復雜,也容易出錯。

本文的實現則選擇了另外一種不同的方法:使用 Python 的內部函數機制,把一連串查詢變換成一組函數,每個函數取上個函數的執行結果作為輸入,最後一個函數的輸出就是整個查詢的結果。由於內部函數同時也是閉包,盡管每個查詢的參數形式各不相同,但是它們都可以被閉包「捕獲」而成為內部變數,所以這些內部函數可以採用統一的形式,無需再針對每種查詢設計額外的數據結構,因而執行過程得到了很大程度的簡化。

首先還是來編寫測試。 LazyQueryTest 和 EagerQueryTest 測試用例幾乎是完全相同的(是的,兩種查詢只在於內部實現機制不同,它們的調用介面幾乎是完全一致的)。

因此我們可以把 EagerQueryTest 的測試原樣不變拷貝到 LazyQueryTest 中。當然拷貝粘貼不是個好注意,對於比較冗長而固定的初始化部分,我們可以把它提取出來作為兩個測試共享的公共函數。讀者可參考代碼中的 step04_lazy_query/tests/test_lazy_query.py 部分。

程序把查詢函數的串列執行稱為管道( pipeline ),用一個變數來記錄它:

然後依次實現各個調用介面。每種介面的實現都是類似的:用內部函數執行真正的查詢邏輯,再把這個函數添加到 pipeline 調用鏈中。比如 node 的實現類似下面:

其他介面的實現也與此類似。最後, run 函數負責執行所有查詢,返回最終結果;

完成上述實現後執行測試,確保我們的實現是正確的。

在前面我們說過,延遲查詢與主動查詢相比,最大的優勢是對於許多查詢可以按需要訪問,不需要每個步驟都返回完整結果,從而提高性能,節約查詢時間。比如說,對於下面的查詢:

以上查詢的意思是從孫輩中找到一個符合條件的節點即可。對該查詢而言,主動查詢會在調用 outcome('son') 時就遍歷所有節點,哪怕最後一步只需要第一個結果。而延遲查詢為了提高效率,應在找到符合條件的結果後立即停止。

目前我們尚未實現 take 方法。老規矩,先添加測試:

主動查詢的 take 實現比較簡單,我們只要從結果中返回前 n 條記錄:

延遲查詢的實現要復雜一些。為了避免不必要的查找,返回結果不應該是完整的列表( list ),而應該是個按需返回的可迭代對象,我們用內置函數 next 來依次返回前 n 個結果:

寫完後運行測試,確保它們是正確的。

從外部介面看,主動查詢和延遲查詢幾乎是完全相同的,所以用單純的數據測試很難確認後者的效率一定比前者高,用訪問時間來測試也並不可靠。為了測試效率,我們引入一個節點訪問次數的概念,如果延遲查詢效率更高的話,那麼它應該比主動查詢訪問節點的次數更少。

為此,編寫如下測試:

我們為 Dagoba 類添加一個成員來記錄總的節點訪問次數,以及兩個輔助方法,分別用於獲取和重置訪問次數:

然後瀏覽代碼,查找修改點。增加計數主要在從邊查找節點的時候,因此修改部分如下:

此外還有 income/outcome 方法,修改都很簡單,這里就不再列出。

實現後再次運行測試。測試通過,表明延遲查詢確實在效率上優於主動查詢。

不像關系資料庫的結構那樣固定,圖的形式可以千變萬化,查詢機制也必須足夠靈活。從原理上講,所有查詢無非是從某個節點出發按照特定方向搜索,因此用 node/income/outcome 這三個方法幾乎可以組合出任意所需的查詢。

但對於復雜查詢,寫出的代碼有時會顯得較為瑣碎和冗長,對於特定領域來說,往往存在更為簡潔的名稱,例如:母親的兄弟可簡稱為舅舅。對於這些場景,如果能夠類似 DSL (領域特定語言)那樣允許用戶根據專業要求自行擴展,從而簡化查詢,方便閱讀,無疑會更為友好。

如果讀者去看原作者的實現,會發現他是用一種特殊語法 addAlias 來定義自己想要的查詢,調用方法時再進行查詢以確定要執行的內容,其介面和內部實現都是相當復雜的。

而我希望有更簡單的方法來實現這一點。所幸 Python 是一種高度動態的語言,允許在運行時向類中增加新的成員,因此做到這一點可能比預想的還要簡單。

為了驗證這一點,編寫測試如下:

無需 Dagoba 的實現做任何改動,測試就可以通過了!其實我們要做的就是動態添加一個自定義的成員函數,按照 Python 對象機制的要求,成員函數的第一個成員應該是名為 self 的參數,但這里已經是在 UnitTest 的內部,為了和測試類本身的 self 相區分,新函數的參數增加了一個下劃線。

此外,函數應返回其所屬的對象,這是為了鏈式調用所要求的。我們看到,動態語言的靈活性使得添加新語法變得非常簡單。

到此,一個初具規模的圖資料庫就形成了。

和原文相比,本文還缺少一些內容,比如如何將資料庫序列化到磁碟。不過相信讀者都看到了,我們的資料庫內部結構基本上是簡單的原生數據結構(列表+字典),因此序列化無論用 pickle 或是 JSON 之類方法都應該是相當簡單的。有興趣的讀者可以自行完成它們。

我們的圖資料庫實現為了提高查詢性能,在節點內部存儲了邊的指針(或者說引用)。這樣做的好處是,無論資料庫有多大,從一個節點到相鄰節點的訪問是常數時間,因此數據訪問的效率非常高。

但一個潛在的問題是,如果資料庫規模非常大,已經無法整個放在內存中,或者出於安全性等原因要實現分布式訪問的話,那麼指針就無法使用了,必須要考慮其他機制來解決這個問題。分布式資料庫無論採用何種數據模型都是一個棘手的問題,在本文中我們沒有涉及。有興趣的讀者也可以考慮 500lines 系列中關於分布式和集群演算法的其他一些文章。

本文的實現和系列中其他資料庫類似,採用 Python 作為實現語言,而原作者使用的是 JavaScript ,這應該和作者的背景有關。我相信對於大多數開發者來說, Python 的對象機制比 JavaScript 基於原型的語法應該是更容易閱讀和理解的。

當然,原作者的版本比本文版本在實現上其實是更為完善的,靈活性也更好。如果想要更為優雅的實現,我們可以考慮使用 Python 元編程,那樣會更接近於作者的實現,但也會讓程序的復雜性大為增加。如果讀者有興趣,不妨對照著去讀讀原作者的版本。

閱讀全文

與圖片資料庫包括哪些相關的資料

熱點內容
什麼是龍骨船技術 瀏覽:245
otc機器人怎麼查看原有程序 瀏覽:947
交易貓需要投保多少 瀏覽:934
閥門的技術優勢怎麼寫 瀏覽:761
信息資源管理方式包括什麼 瀏覽:395
水果消費市場有多少 瀏覽:676
手機微信博雲學小程序怎麼登錄 瀏覽:793
口罩出口信息怎麼看 瀏覽:860
產品防偽數碼是什麼意思啊 瀏覽:161
市場營銷有哪些應用 瀏覽:318
花喜代理怎麼加盟 瀏覽:40
信息管理人員經歷了哪些階段 瀏覽:969
仁化汽車配件代理加盟如何 瀏覽:1000
之江生物產品銷量怎麼樣 瀏覽:670
宇花靈技術怎麼用 瀏覽:602
想去泉州賣菜哪個菜市場人流大 瀏覽:411
沈陽雪花酒水怎麼代理 瀏覽:125
rng秘密交易是什麼意思 瀏覽:732
重慶紅糖鍋盔怎麼代理賺錢嗎 瀏覽:383
考察投資項目關注哪些數據 瀏覽:592