創建、讀、更新和刪除(Create/Read/Update/Delete,CRUD)操作是最基本的資料庫操作,但是它們也是最重要的操作。CRUD 操作通常是使用關係資料庫系統中的結構化查詢語言(Structured Query Language,SQL)完成的。隨著 Web 變得更加具有面向數據特性,因此需要從基於 SQL 的 CRUD 操作轉移到基於語義 Web 的 CRUD 操作。了解如何使用 PHP 通過基於語義的 Web 執行 CRUD 操作。
|
在開發 Web 應用程序時,為邏輯層和 UI 層創建放置伺服器端代碼的資料庫結構是一種標準實踐。要連接到資料庫,伺服器端代碼需要執行一些基本的創建、更新、刪除和 — 最重要的 — 讀取記錄等操作。由於 Web 應用程序的後台資料庫通常都是關係資料庫,因此這些 CRUD 操作都是使用眾所周知的 SQL 語言執行的。但是,隨著 Web 開發越來越多地採用面向對象的編程(OOP),模型也隨之發生改變。
資源描述框架(Resource Description Framework,RDF)是描述對象同時保留數據含義的理想方法。簡單協議和 RDF 查詢語言(Simple Protocol and RDF Query Language,SPARQL — 發音為 “sparkle”)是通常用於針對該數據進行查詢的語言,因為它在語句構成上匹配 RDF 本身的結構。RDF 和 SPARQL 都是所謂 語義 Web 棧(semantic Web stack)中的技術。
要徹底地應用語義 Web 理念,您可以使用 SPARQL 將傳統的 Web 開發技術應用到 RDF 數據中。本文將展示如何使用簡化的模式—視圖—控制器(Model-View-Controller,MVC)設計模型、PHP 伺服器端腳本語言和 SPARQL 連接到 RDF — 與使用關係資料庫系統中的 SQL 相反。
SQL 和 SPARQL CRUD 操作
|
在使用 SQL 和 SPARQL 進行開發時,需要查看一下 CRUD 操作之間的異同。清單 1 顯示了 read 操作的 SQL 代碼。
SELECT realname, dob, location FROM UserTable WHERE realname = "John Smith"; |
將這段基於 SQL 的代碼與清單 2 中所示的基於 SPARQL 的代碼相比較。採用這兩個 read 操作的原因在於它們最易於理解、實現和說明。這對於 SQL 和 SPARQL 來說都是一樣的。
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> SELECT ?uri ?name ?dob ?location FROM <http://www.example.org/graph> WHERE { ?uri rdf:type foaf:Person ; foaf:name "John Smith" ; foaf:birthday ?dob ; foaf:location ?location . } ; |
在比較兩張清單時,您的第一個想法很可能是 SPARQL 版本明顯比 SQL 版本長很多。這是事實,但是請不要誤以為 SQL 必然更簡單而且更乾淨。根據所運行引擎的不同,SPARQL 可以全部通過稱為鏈接數據結果(linked data effect)的內容進行分發。此外,它允許擁有動態模式,因為它擁有互相鏈接的面向對象的透視圖,與嚴格的 SQL 關係透視圖形成對照。如果您想要把關係資料庫表分隔為許多數據孤島,則實際上使用的 SQL 代碼行將比 SPARQL 多很多 — 更不必說 SQL 中會出現大量令人討厭的 JOIN 描述符。
SPARQL 的前兩行是 PREFIX 聲明。根據語義 Web 理論,一切內容 — 無論是對象還是數據圖來源(也是一個對象)— 都有統一資源標識符(Uniform Resource Identifier,URI)。PREFIX 行只是將臨時標籤應用到一些 URI 中 — 在本例中為 Friend of a Friend 和 RDF 模式。其中的好處是您以後可以在查詢中使用 PREFIX 聲明而不必使用完整的 URI。
SPARQL 代碼的下一行描述了查詢請求。這條語句在本質上與 SQL 語句相同,不同之處是對 URI 的附加請求。注意問號的使用(?)是為了表示術語是變數。
FROM 語句描述了獲取數據的位置。這在 SQL 和 SPARQL 中是相同的,只是在 SPARQL 中,數據源名稱是 URI,而非表示計算機或網路中某個物理位置的字元串。
兩者的 WHERE 語句完全不同,因為使用 SPARQL,必須指定用於獲取數據的模式。同樣,如果嘗試過使用關係方法執行此操作,則需要花費的代價比普通 SQL 多得多:需要使用 PHP、Java™ 編程語言或者一些其他伺服器端語言才能執行數據源之間的檢查。SPARQL 代碼行完成的操作比較明了,這包括確保正在檢索的數據只屬於 Person 類型。SPARQL 將獲取名稱和位置,同時執行一些模式匹配以查找正確的 John Smith。
創建
SPARQL 中的 CRUD 操作通常比 read 操作更神秘。但是,可以完成這些操作。首先,create 操作將把新記錄或對象插入到表或圖表中。
INSERT INTO UserTable (realname, dob, location) VALUES ("John Smith", "1985-01-01", "Bristol, UK"); |
現在,比較清單 3 中基於 SQL 的代碼與清單 4 中基於 SPARQL 的代碼中的 create 操作。
PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> INSERT INTO GRAPH <http://www.example.com/graph> (?realname, ?dob, ?location) { <http://www.example.org/graph/johnsmith#me> rdf:Type foaf:Person ; foaf:name "John Smith" ; foaf:birthday <1985-01-01T00:00:00> ; foaf:location "Bristol, UK" } |
同樣,注意 PREFIX 行與用 SPARQL 在 read 操作中執行的操作完全相同。INSERT INTO 的工作原理類似於 SQL,但是同樣,這是基於 URI 的,而非基於字元串、基於表和基於名稱的,這允許使用 HTTP 完成操作。您必須再次指定模式。在這裡,比在 read 操作中了解起來略微簡單一些,因為您幾乎可以擁有任何屬性,只要它與模式兼容。這就是 RDF 所提供的分散式動態可擴展對象的優點。
刪除
從某一程度來說,如果要創建,那很可能需要進行刪除。例如,用戶可能想要刪除他們在您站點中的帳戶(這顯然是件遺憾的事情,他們想要離開,但是他們可能有正當的理由)。清單 5 提供了典型 delete 操作的 SQL 代碼。
DELETE FROM UserTable WHERE realname = "John Smith" |
現在,比較清單 5 中基於 SQL 的代碼與清單 6 中基於 SPARQL 的代碼。
DELETE FROM GRAPH <http://www.example.com/graph> {<http://www.example.org/graph/johnsmith#me> ?predicate ?object } |
SQL 與 SPARQL 代碼之間的基本差別是 SQL 刪除了表中的某行,然而 SPARQL 將刪除與 http://www.example.org/graph/johnsmith#me 所表示的 “John Smith” 相關的 “所有三元組”。這種差別是因為 RDF 模型是基於圖表的。
更新
許多 Web 應用程序允許用戶更新信息。UPDATE 操作是實現此功能的方法。清單 7 和 8 演示了如何在 SQL 和 SPARQL 中實現更新。
UPDATE UserTable SET location = "Weston-super-Mare, UK" WHERE realname = "Joanne Smith" |
現在比較清單 7 中基於 SQL 的代碼與清單 8 中基於 SPARQL 的代碼中的 update 操作。
PREFIX foaf: <http://xmlns.com/foaf/0.1/> MODIFY <http://www.example.org/graph> DELETE {?uri foaf:location ?location} INSERT {?uri foaf:location "Weston-super-Mare, UK"} WHERE { ?uri foaf:name "Joanne Smith" } |
SPARQL 中的 UPDATE 可能看上去非常愚蠢,但是當您知道它並不是要更新關係錶行 — 而是要更新圖表中的一個非常特定的關係時,它是完全有效的。實現更新而無需達到多個位置的最簡單方法是執行刪除和插入。MODIFY 關鍵字用於建立與正確圖表的連接。
連接到 SQL 和 SPARQL 資料庫系統
要執行上面的 SQL 和 SPARQL 語句,必須以某種方式連接到系統中。很明顯,不同的系統有不同的連接方法。一種常見方法是使用開放資料庫連接(Open Database Connectivity,ODBC)驅動程序連接到一般資料庫,這些驅動程序通常附帶於最新版本的 Mac OS X 和 Linux® 系統中,並且可以安裝到諸如 Windows® 之類的其他操作系統中。ODBC 實際上提供了一個簡單的通用 API,可以連接到所選的 SQL 資料庫。有趣的是,ODBC 還可以與諸如 OpenLink Virtuoso 之類的一些語義 Web 資料庫結合使用。但是,大多數其他語義 Web 資料庫都需要一些可以處理諸如 Seseme 和 Jena 之類系統的自定義連接過程,或者自定義通用連接系統,比如 RDF2Go(在撰寫本文時,RDF2Go 僅適用於 Java 技術)。如果數據將通過 HTTP 公開,那麼另一種備選方法是基於 HTTP 的 SPARQL 連接,這種方法使您的數據成為 “鏈接數據” 並且可以實現完全分佈。由於 SQL 和 SPARQL 的連接方法的範圍是不同的,因此不適合在本文中詳細介紹這些方法。
通過 PHP 實現 SQL 和 SPARQL
在選擇連接方法后,通常下一個步驟是在 PHP 中執行常用操作。對於自定義系統,通常需要使用 SQL 字元串,插入 PHP 變數並通過函數參數傳遞。該函數隨後將連接到資料庫中並執行此事務。此處建議對 SPARQL-RDF 連接執行與 SQL-RDBMS 連接相同的操作。
因此,看一下另一種代碼比較 — 這次使用 PHP 語言 — 從 read 開始,然後是 create、delete 和 update,同上面的代碼比較一樣。使用名為 query_execute 的虛構的查詢執行函數,該函數將獲取 SQL/SPARQL 語句的字元串表示。
讀取
首先是簡單的 read 操作。在 PHP 中可以使用字元串連接將變數插入到查詢中。
function readUserInfo($realname) { $sqlstatement = "SELECT realname, dob, location FROM UserTable WHERE realname = \"" + realname + "\";"; return query_execute($sqlstatement); } |
現在,比較清單 9 中基於 SQL 的 PHP 代碼與清單 10 中基於 SPARQL 的 PHP 代碼中的 read 操作。
function readUserInfo($realname) { $sqlstatement = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> SELECT ?uri ?name ?dob ?location FROM <http://www.example.org/graph> WHERE { ?uri rdf:type foaf:Person ; foaf:name \"" + $realname + "\" ; foaf:birthday ?dob ; foaf:location ?location . } ;"; return query_execute($sparqlstatement); } |
正如您所見,以上函數在開發時使用函數名作為參數,這意味著您可以開始直接使用 SPARQL 版本。此外,如果使用的是 ODBC 系統,您不必擔心返回類型發生變化。
創建
和上面一樣。以下 PHP 方法將把變數插入到字元串中以運行動態查詢。清單 11 顯示了如何用 create 操作完成該動態查詢。
function createUserInfo($realname, $dob, $location) { $sqlstatement = "INSERT INTO UserTable (realname, dob, location) VALUES (\"" + $realname + "\", \"" + $dob + "\", \"" + $location + "\");"; return query_execute($sqlstatement); } |
現在比較清單 11 中基於 SQL 的 PHP 代碼與清單 12 中基於 SPARQL 的 PHP 代碼中的 create 操作。
function createUserInfo($uri, $realname, $dob, $location) { $sparqlstatement = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> INSERT INTO GRAPH <http://www.example.com/graph> (?realname, ?dob, ?location) { " + $uri + " rdf:Type foaf:Person ; foaf:name \"" + $realname + "\" ; foaf:birthday <" + $dob + ">> ; foaf:location \"" + $location + "\}" return query_execute($sparqlstatement); } |
為了簡單起見,此函數的 SPARQL 版本將包括 URI 參數,但是,執行一些附加字元串連接使函數聲明與 SQL 一致將非常簡單。
刪除
在 PHP 中,通過字元串連接使用插入操作來執行 delete 操作。請注意,如上一節所示,這些不同的變數傳遞到 SQL 和 SPARQL 版本中。清單 13 顯示了 delete 操作的 SQL 代碼。
function deleteUserInfo($realname) { $sqlstatement = "DELETE FROM UserTable WHERE realname = \"" + John Smith + "\""; return query_execute($sqlstatement); } |
現在,比較清單 13 中基於 SQL 的 PHP 代碼與清單 14 中基於 SPARQL 的 PHP 代碼中的 delete 操作。
function deleteUserInfo($uri) { $sparqlstatement = "DELETE FROM GRAPH <http://www.example.com/graph> {<" + $uri + "> ?predicate ?object }"; return query_execute($sparqlstatement); } |
同樣,為了簡單起見,SPARQL 版本的函數將獲取 URI,而非實際名稱。您可以將 DELETE SPARQL 語句與 WHERE 子句結合使用以按名稱而不是按 URI 查找數據,這將擁有與 SQL 版本相同的函數頭。
更新
使用 PHP 在 SQL 和 SPARQL 中更新記錄非常簡單。不過要注意關係資料庫與 RDF 提供的是不同的結構。清單 15 顯示了 update 操作的 SQL 代碼。
function updateUserInfo($realname, $location) { $sqlstatement = "UPDATE UserTable SET location = \"" + $location + "\" WHERE realname = \"" + $realname+ "\";"; return query_execute($sqlstatement); } |
現在比較清單 15 中基於 SQL 的 PHP 代碼與清單 16 中基於 SPARQL 的 PHP 代碼中的 update 操作。
function updateUserInfo($realname, $location) { $sparqlstatement = " PREFIX foaf: <http://xmlns.com/foaf/0.1/> MODIFY <http://www.example.org/graph> DELETE {?uri foaf:location ?location} INSERT {?uri foaf:location \"" + $location + "\"} WHERE { ?uri foaf:name \"" + $realname + "\" } "; return query_execute($sparqlstatement); } |
SQL 與 SPARQL 版本中的函數聲明是相同的。因此,從 SQL 轉換到 SPARQL 十分簡單。
雖然從使用 SQL 的數據源轉移到使用 SPARQL 的數據源非常簡單,但是有兩個重要部分需要注意:抽象級別和 SQL 與 SPARQL 的異同。您應當避免產生這兩種語言實際上相同的這種錯誤的想法。因此最好在了解一種語言的限制的同時,研究該語言的功能 — 特別是,不同語言提供的各種語法優點和圖形表示。
抽象級別
本文中的示例代碼與資料庫結構緊密耦合。在理論上,在必須執行表結構重組之前,SQL 和 RDBMS 只能處理某種程度的鬆散耦合。然而,SPARQL 和 RDF 不會出現這個問題。使用 SPARQL 與數據進行耦合可能會非常抽象,因為 RDF 是分散式但又互相鏈接的。本文示例的可重用性可以通過提高抽象性來改進。但是,出於我們的目的,使用了簡單的緊密耦合函數來說明 SPARQL 與 SQL 的異同。
正如您在示例代碼中看到的,SQL 與 SPARQL 有許多相似性。不同之處在於 RDF 具有基於 Web 的、圖形化和面向對象的特性以及如何將這些特性過濾到 SPARQL 語言中。作為一項簡化的通用規則,您可以將 RDF 和 SPARQL 中的三元組結構作為基本表示,依次為行(主題)的惟一主鍵、屬性/列名(謂詞或關係)及基於行和列(對象)的單元格數據。此外,SPARQL 可以充分利用 HTTP 通信,並且因此使數據可以(但不是必須)基於內部網、外部網和更廣闊的 Internet 進行分發。
為什麼從 SQL 遷移到 SPARQL?
從 SQL 遷移到 SPARQL 有許多原因。詳細原因超出了本文的討論範圍,但是您可以受到下面的啟發:
當然,不 希望從 SQL 遷移到 SPARQL 也有許多理由,並且這些理由可能非常充分。SPARQL 是另一種查詢方法,不一定要立即替換 SQL。這同樣適用於關係數據和基於語義 Web 的數據。並不是說要替換,相反,最好結合使用新舊技術,從而生成一種混合系統,它可以處理舊的遺留系統、現行系統和未來系統,同時也可以被這些系統處理。(責任編輯:A6)
[火星人 ] 使用 PHP 構建語義 Web CRUD 操作已經有804次圍觀