Graph Developer's Guide for RDF Graph, Release 23
このドキュメントのPart IIにRDF Graph Serverが紹介されています。しかし、RDF Graph Serverのダウンロード・ページとして以下が示されていますが、RDF GraphについてはEclipse RDF4Jのアダプタのみがダウンロード可能で、RDF Graph Serverは含まれていません。
RDF Graph Serverはどうなったのか不明だったのですが、ユーザー・インターフェース(Query UI)を除いた機能は、Oracle REST Data Servicesに実装されていました。
Oracle REST Data Services 23.4からOracle REST Data Services APIにRDF Graphが追加されています。
https://docs.oracle.com/en/database/oracle/oracle-rest-data-services/25.1/orrst/api-rdf-graph.htmlOracle APEXを実行するにあたってOracle REST Data Servicesは必須のコンポーネントなので、APEXの環境があればSPARQLも実行できます。SPARQLからSQLへの変換はORDSで実施しているようで、オラクル・データベースでJavaVMを有効にしなくても(Autonomous DatabaseではJavaVMはデフォルトで無効です)、SPARQLを実行できます。ただし、APEXからSPARQLを実行するには、データベースからHTTPリクエストを発行してORDSを呼び出す必要があります。
今回はOracle REST Data ServicesのRDF Graph APIを呼び出すAPEXアプリケーションを作成し、SPARQLクエリを実行します。
このAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sparql-operations.zip
アプリケーションはページ・アイテムに設定した値を引数として、ボタンのクリックでREST APIを呼び出す簡単な作りになっています。
このAPEXアプリケーションをインポートすると、Web資格証明としてRDF Graph Cred、リモート・サーバーとしてRDF Graph ORDS Endpointが作成されます。このアプリケーション内でRDF Graph APIを呼び出す際に使用するWeb資格証明およびエンドポイントになります。
アプリケーションのインストール後にワークスペース・ユーティリティのリモート・サーバーおよびWeb資格証明を開いて、これらの設定値を更新する必要があります。
リモート・サーバーRDF Graph ORDS Endpointの更新は、ワークスペース・ユーティリティのリモート・サーバーから行います。
一般のエンドポイントURLを更新します。今回はAutonomous Databaseを対象にRDFグラフの保存とSPARQLの実行を行うため、エンドポイントURLは以下のようになります。
https://[Webアクセス(ORDS)パブリックURL]/[ORDS別名]/_/db-api/stable
Webアクセス(ORDS)パブリックURLは、OCIコンソールのAutonomous Databaseのツール構成から確認できます。
続けてワークスペース・ユーティリティのWeb資格証明を開きます。
Web資格証明RDF Graph Credを開きます。
REST APIは、RDFグラフを保存しているスキーマ名とそのパスワードを与えることによって認証します。Autonomous DatabaseでAPEXを使用している場合は、一般にワークスペース名をAPEXDEVとした場合、ORDS別名=ワークスペース名でapexdevとなります。そのワークスペースのデフォルト・パーシング・スキーマはWKSP_APEXDEVになります。これがデータベースのユーザー名になり、このユーザー名およびパスワードをWeb資格証明に設定します。
このAPEXアプリケーションを使って、RDFグラフの作成とSPARQLの実行を行います。
最初にRDFネットワークを作成します。呼び出すREST APIは以下です。
Create RDF network
SEM_APIS.CREATE_RDF_NETWORKの呼び出しに対応します。
https://docs.oracle.com/en/database/oracle/oracle-database/23/rdfrm/sem_apis-create_rdf_network.html
Network Nameは任意の値です。今回はNET1としています。Network Ownerは接続先のデータベース・ユーザー名(スキーマ名)を指定します。Tablespace Nameは、そのデータベース・ユーザーのデフォルト表領域を指定します。Autonomous Databaseでは表領域DATAを指定します。
ボタンCreate RDF networkをクリックすると、以下のPL/SQLコードが実行されます。REST APIの仕様にそって、API呼び出しを実施しています。レスポンスは特に加工せず、JSONのままページ・アイテムP1_RESPONSEに表示しています。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_base_url apex_workspace_remote_servers.base_url%type; | |
l_operation_url varchar2(400); | |
l_request clob; | |
l_request_json json_object_t; | |
l_response clob; | |
e_call_api_failed exception; | |
l_status_code number; | |
begin | |
select base_url into l_base_url from apex_workspace_remote_servers | |
where remote_server_static_id = :G_REMOTE_SERVER; | |
l_operation_url := | |
apex_string.format(l_base_url || '/database/rdf/networks/%s,%s', | |
:P1_NETWORK_OWNER, :P1_NETWORK_NAME); | |
apex_debug.info('operation_url = %s', l_operation_url); | |
l_request_json := json_object_t(); | |
l_request_json.put('tablespace_name', :P1_TABLESPACE_NAME); | |
l_request := l_request_json.to_clob(); | |
apex_web_service.set_request_headers('Content-Type', 'application/json'); | |
l_response := apex_web_service.make_rest_request( | |
p_url => l_operation_url | |
,p_http_method => 'PUT' | |
,p_body => l_request | |
,p_credential_static_id => :G_CREDENTIAL | |
); | |
l_status_code := apex_web_service.g_status_code; | |
apex_debug.info('status_code = %s', l_status_code); | |
if not l_status_code between 200 and 300 then | |
raise e_call_api_failed; | |
end if; | |
:P1_RESPONSE := l_response; | |
end; |
次に、作成したネットワークにモデルを作成します。Model Nameはbotchanとします。
ボタンCreate RDF modelをクリックすると以下のコードを実行します。呼び出すREST APIは以下になります。
Create RDF model
SEM_APIS.CREATE_RDF_GRAPHの呼び出しに対応します。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_base_url apex_workspace_remote_servers.base_url%type; | |
l_operation_url varchar2(400); | |
l_request clob; | |
l_request_json json_object_t; | |
l_response clob; | |
e_call_api_failed exception; | |
l_status_code number; | |
begin | |
select base_url into l_base_url from apex_workspace_remote_servers | |
where remote_server_static_id = :G_REMOTE_SERVER; | |
l_operation_url := | |
apex_string.format(l_base_url || '/database/rdf/networks/%s,%s/models/%s', | |
:P1_NETWORK_OWNER, :P1_NETWORK_NAME, :P1_MODEL_NAME); | |
apex_debug.info('operation_url = %s', l_operation_url); | |
l_request_json := json_object_t(); | |
l_request_json.put('tablespace_name', :P1_TABLESPACE_NAME); | |
l_request := l_request_json.to_clob(); | |
apex_web_service.set_request_headers('Content-Type', 'application/json'); | |
l_response := apex_web_service.make_rest_request( | |
p_url => l_operation_url | |
,p_http_method => 'PUT' | |
,p_body => l_request | |
,p_credential_static_id => :G_CREDENTIAL | |
); | |
l_status_code := apex_web_service.g_status_code; | |
apex_debug.info('status_code = %s', l_status_code); | |
if not l_status_code between 200 and 300 then | |
raise e_call_api_failed; | |
end if; | |
:P1_RESPONSE := l_response; | |
end; |
RDFネットワークとモデル(グラフ)が作成できました。SPARQLのINSERT文を実行します。
小説「坊ちゃん」の登場人物の関係データを投入します。以下のコードはClaude Sonnet 4に生成してもらいました。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 「坊ちゃん」登場人物関係データのSPARQL INSERT文 | |
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> | |
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | |
PREFIX botchan: <http://example.org/botchan/> | |
PREFIX vocab: <http://example.org/vocabulary/> | |
# 人物の基本情報を挿入 | |
INSERT DATA { | |
botchan:坊ちゃん rdf:type vocab:人物 ; | |
rdfs:label "坊ちゃん" ; | |
vocab:職業 "数学教師" ; | |
vocab:出身地 "東京" . | |
botchan:赤シャツ rdf:type vocab:人物 ; | |
rdfs:label "赤シャツ" ; | |
vocab:職業 "教頭" . | |
botchan:山嵐 rdf:type vocab:人物 ; | |
rdfs:label "山嵐" ; | |
vocab:職業 "英語教師" . | |
botchan:うらなり rdf:type vocab:人物 ; | |
rdfs:label "うらなり" ; | |
vocab:職業 "英語教師" . | |
botchan:野だいこ rdf:type vocab:人物 ; | |
rdfs:label "野だいこ" ; | |
vocab:職業 "画学教師" . | |
botchan:マドンナ rdf:type vocab:人物 ; | |
rdfs:label "マドンナ" ; | |
vocab:職業 "女性" . | |
botchan:清 rdf:type vocab:人物 ; | |
rdfs:label "清" ; | |
vocab:職業 "女中" . | |
botchan:校長 rdf:type vocab:人物 ; | |
rdfs:label "校長" ; | |
vocab:職業 "校長" . | |
} ; | |
# 職場関係を挿入 | |
INSERT DATA { | |
botchan:坊ちゃん vocab:勤務先 botchan:中学校 . | |
botchan:赤シャツ vocab:勤務先 botchan:中学校 . | |
botchan:山嵐 vocab:勤務先 botchan:中学校 . | |
botchan:うらなり vocab:勤務先 botchan:中学校 . | |
botchan:野だいこ vocab:勤務先 botchan:中学校 . | |
botchan:校長 vocab:勤務先 botchan:中学校 . | |
botchan:赤シャツ vocab:職位 "教頭" . | |
botchan:校長 vocab:職位 "校長" . | |
} ; | |
# 人間関係を挿入 | |
INSERT DATA { | |
botchan:坊ちゃん vocab:世話になった人 botchan:清 . | |
botchan:清 vocab:世話した人 botchan:坊ちゃん . | |
botchan:坊ちゃん vocab:対立関係 botchan:赤シャツ . | |
botchan:赤シャツ vocab:対立関係 botchan:坊ちゃん . | |
botchan:坊ちゃん vocab:対立関係 botchan:野だいこ . | |
botchan:野だいこ vocab:対立関係 botchan:坊ちゃん . | |
botchan:山嵐 vocab:味方関係 botchan:坊ちゃん . | |
botchan:坊ちゃん vocab:味方関係 botchan:山嵐 . | |
botchan:赤シャツ vocab:同盟関係 botchan:野だいこ . | |
botchan:野だいこ vocab:同盟関係 botchan:赤シャツ . | |
botchan:うらなり vocab:恋愛関係 botchan:マドンナ . | |
botchan:マドンナ vocab:恋愛関係 botchan:うらなり . | |
botchan:赤シャツ vocab:横恋慕 botchan:マドンナ . | |
} ; | |
# 性格・特徴を挿入 | |
INSERT DATA { | |
botchan:坊ちゃん vocab:性格 "正直" ; | |
vocab:性格 "短気" ; | |
vocab:性格 "江戸っ子気質" . | |
botchan:赤シャツ vocab:性格 "狡猾" ; | |
vocab:性格 "陰険" . | |
botchan:山嵐 vocab:性格 "豪快" ; | |
vocab:性格 "正義感が強い" . | |
botchan:うらなり vocab:性格 "温厚" ; | |
vocab:性格 "弱気" . | |
botchan:野だいこ vocab:性格 "軽薄" ; | |
vocab:性格 "調子がいい" . | |
botchan:清 vocab:性格 "献身的" ; | |
vocab:性格 "母性的" . | |
} ; | |
# 事件・出来事を挿入 | |
INSERT DATA { | |
botchan:坊ちゃん vocab:経験した出来事 "いたずら事件" ; | |
vocab:経験した出来事 "温泉事件" ; | |
vocab:経験した出来事 "辞職" . | |
botchan:赤シャツ vocab:関与した出来事 "うらなり左遷工作" . | |
botchan:野だいこ vocab:関与した出来事 "うらなり左遷工作" . | |
botchan:山嵐 vocab:行動 "坊ちゃんと協力して制裁" . | |
botchan:坊ちゃん vocab:行動 "山嵐と協力して制裁" . | |
} ; | |
# 追加のメタデータ | |
INSERT DATA { | |
botchan:中学校 rdf:type vocab:教育機関 ; | |
rdfs:label "中学校" ; | |
vocab:所在地 "四国" . | |
# 作品情報 | |
botchan:作品 rdf:type vocab:小説 ; | |
rdfs:label "坊ちゃん" ; | |
vocab:作者 "夏目漱石" ; | |
vocab:出版年 "1906" . | |
} |
ボタンExecute SPARQL Updateをクリックすると、以下のコードが実行されます。呼び出すREST APIは以下になります。
Execute a SPARQL query or update
ORDS上でSQLに変換されデータベースではSQLが実行されるため、対応するデータベースのAPIはありません。REST API呼び出し時のContent-Typeとして、application/sparql-updateを指定します。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_base_url apex_workspace_remote_servers.base_url%type; | |
l_operation_url varchar2(400); | |
l_request clob; | |
l_response clob; | |
e_call_api_failed exception; | |
l_status_code number; | |
begin | |
select base_url into l_base_url from apex_workspace_remote_servers | |
where remote_server_static_id = :G_REMOTE_SERVER; | |
l_operation_url := | |
apex_string.format(l_base_url || '/database/rdf/networks/%s,%s/models/%s/sparql/1.1', | |
:P1_NETWORK_OWNER, :P1_NETWORK_NAME, :P1_MODEL_NAME); | |
apex_debug.info('operation_url = %s', l_operation_url); | |
l_request := :P1_SPARQL_QUERY; | |
apex_web_service.set_request_headers('Content-Type', 'application/sparql-query', 'Accept', 'application/sparql-results+json'); | |
l_response := apex_web_service.make_rest_request( | |
p_url => l_operation_url | |
,p_http_method => 'POST' | |
,p_body => l_request | |
,p_credential_static_id => :G_CREDENTIAL | |
); | |
l_status_code := apex_web_service.g_status_code; | |
apex_debug.info('status_code = %s', l_status_code); | |
if not l_status_code between 200 and 300 then | |
raise e_call_api_failed; | |
end if; | |
:P1_RESPONSE := l_response; | |
end; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 「坊ちゃん」RDFグラフ検索クエリ集 | |
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> | |
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | |
PREFIX botchan: <http://example.org/botchan/> | |
PREFIX vocab: <http://example.org/vocabulary/> | |
# ===================================== | |
# 1. 基本的な人物情報検索 | |
# ===================================== | |
# 全人物の一覧表示 | |
SELECT ?person ?name ?job ?workplace | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:職業 ?job . | |
OPTIONAL { ?person vocab:勤務先 ?workplace } | |
} | |
ORDER BY ?name | |
# 特定の職業の人物を検索 | |
SELECT ?person ?name | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:職業 "英語教師" . | |
} | |
# 坊ちゃんの基本情報 | |
SELECT ?property ?value | |
WHERE { | |
botchan:坊ちゃん ?property ?value . | |
} | |
# ===================================== | |
# 2. 職場・階層関係の検索 | |
# ===================================== | |
# 中学校に勤務する全教職員 | |
SELECT ?person ?name ?job ?position | |
WHERE { | |
?person vocab:勤務先 botchan:中学校 ; | |
rdfs:label ?name ; | |
vocab:職業 ?job . | |
OPTIONAL { ?person vocab:職位 ?position } | |
} | |
ORDER BY ?position ?job | |
# 管理職の一覧 | |
SELECT ?person ?name ?position | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:職位 ?position . | |
} | |
# 教師のみの一覧 | |
SELECT ?person ?name ?subject | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:職業 ?subject . | |
FILTER(CONTAINS(?subject, "教師")) | |
} | |
# ===================================== | |
# 3. 人間関係の検索 | |
# ===================================== | |
# 坊ちゃんの人間関係マップ | |
SELECT ?relationship ?related_person ?related_name | |
WHERE { | |
{ | |
botchan:坊ちゃん ?relationship ?related_person . | |
?related_person rdf:type vocab:人物 ; | |
rdfs:label ?related_name . | |
} | |
UNION | |
{ | |
?related_person ?relationship botchan:坊ちゃん . | |
?related_person rdf:type vocab:人物 ; | |
rdfs:label ?related_name . | |
FILTER(?relationship != rdf:type && ?relationship != rdfs:label) | |
} | |
} | |
# 対立関係の一覧 | |
SELECT ?person1 ?name1 ?person2 ?name2 | |
WHERE { | |
?person1 vocab:対立関係 ?person2 ; | |
rdfs:label ?name1 . | |
?person2 rdfs:label ?name2 . | |
} | |
# 味方関係の一覧 | |
SELECT ?person1 ?name1 ?person2 ?name2 | |
WHERE { | |
?person1 vocab:味方関係 ?person2 ; | |
rdfs:label ?name1 . | |
?person2 rdfs:label ?name2 . | |
} | |
# 恋愛関係の一覧 | |
SELECT ?person1 ?name1 ?person2 ?name2 | |
WHERE { | |
?person1 vocab:恋愛関係 ?person2 ; | |
rdfs:label ?name1 . | |
?person2 rdfs:label ?name2 . | |
} | |
# 同盟関係の一覧 | |
SELECT ?person1 ?name1 ?person2 ?name2 | |
WHERE { | |
?person1 vocab:同盟関係 ?person2 ; | |
rdfs:label ?name1 . | |
?person2 rdfs:label ?name2 . | |
} | |
# ===================================== | |
# 4. 性格特性の検索 | |
# ===================================== | |
# 全人物の性格一覧 | |
SELECT ?person ?name ?trait | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:性格 ?trait . | |
} | |
ORDER BY ?name | |
# 特定の性格を持つ人物検索 | |
SELECT ?person ?name | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:性格 "正義感が強い" . | |
} | |
# 性格特性をグループ化して表示 | |
SELECT ?person ?name (GROUP_CONCAT(?trait; separator=", ") as ?traits) | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:性格 ?trait . | |
} | |
GROUP BY ?person ?name | |
ORDER BY ?name | |
# ネガティブな性格の人物 | |
SELECT ?person ?name ?trait | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:性格 ?trait . | |
FILTER(?trait IN ("狡猾", "陰険", "軽薄")) | |
} | |
# ===================================== | |
# 5. 事件・出来事の検索 | |
# ===================================== | |
# 坊ちゃんが経験した出来事 | |
SELECT ?event | |
WHERE { | |
botchan:坊ちゃん vocab:経験した出来事 ?event . | |
} | |
# 誰がどの出来事に関与したか | |
SELECT ?person ?name ?event_type ?event | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name . | |
{ | |
?person vocab:経験した出来事 ?event . | |
BIND("経験" as ?event_type) | |
} | |
UNION | |
{ | |
?person vocab:関与した出来事 ?event . | |
BIND("関与" as ?event_type) | |
} | |
} | |
# 特定の出来事に関わった人物 | |
SELECT ?person ?name ?involvement | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name . | |
{ | |
?person vocab:経験した出来事 "温泉事件" . | |
BIND("経験者" as ?involvement) | |
} | |
UNION | |
{ | |
?person vocab:関与した出来事 "うらなり左遷工作" . | |
BIND("関与者" as ?involvement) | |
} | |
} | |
# 行動を起こした人物 | |
SELECT ?person ?name ?action | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:行動 ?action . | |
} | |
# ===================================== | |
# 6. 複合条件検索 | |
# ===================================== | |
# 坊ちゃんの敵対者の詳細情報 | |
SELECT ?enemy ?name ?job ?traits ?alliance | |
WHERE { | |
botchan:坊ちゃん vocab:対立関係 ?enemy . | |
?enemy rdfs:label ?name ; | |
vocab:職業 ?job . | |
# 性格特性を集約 | |
OPTIONAL { | |
SELECT ?enemy (GROUP_CONCAT(?trait; separator=", ") as ?traits) | |
WHERE { | |
?enemy vocab:性格 ?trait . | |
} | |
GROUP BY ?enemy | |
} | |
# 同盟関係を確認 | |
OPTIONAL { | |
?enemy vocab:同盟関係 ?ally . | |
?ally rdfs:label ?ally_name . | |
BIND(?ally_name as ?alliance) | |
} | |
} | |
# 中学校の人間関係ネットワーク | |
SELECT ?person1 ?name1 ?relationship ?person2 ?name2 | |
WHERE { | |
?person1 vocab:勤務先 botchan:中学校 ; | |
rdfs:label ?name1 . | |
?person1 ?relationship ?person2 . | |
?person2 vocab:勤務先 botchan:中学校 ; | |
rdfs:label ?name2 . | |
FILTER(?relationship IN (vocab:対立関係, vocab:味方関係, vocab:同盟関係)) | |
} | |
# 性格と職業の相関 | |
SELECT ?job ?trait (COUNT(?person) as ?count) | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
vocab:職業 ?job ; | |
vocab:性格 ?trait . | |
} | |
GROUP BY ?job ?trait | |
ORDER BY ?job ?count DESC | |
# ===================================== | |
# 7. 特定人物の詳細プロファイル | |
# ===================================== | |
# 赤シャツの完全プロファイル | |
SELECT ?property ?value | |
WHERE { | |
botchan:赤シャツ ?property ?value . | |
FILTER(?property != rdf:type) | |
} | |
# 山嵐の関係性分析 | |
SELECT ?relationship_type ?related_person ?related_name | |
WHERE { | |
{ | |
botchan:山嵐 ?relationship_type ?related_person . | |
?related_person rdf:type vocab:人物 ; | |
rdfs:label ?related_name . | |
} | |
UNION | |
{ | |
?related_person ?relationship_type botchan:山嵐 . | |
?related_person rdf:type vocab:人物 ; | |
rdfs:label ?related_name . | |
} | |
FILTER(?relationship_type != rdf:type && ?relationship_type != rdfs:label) | |
} | |
# ===================================== | |
# 8. メタデータと作品情報の検索 | |
# ===================================== | |
# 作品の基本情報 | |
SELECT ?property ?value | |
WHERE { | |
botchan:作品 ?property ?value . | |
} | |
# 学校の情報 | |
SELECT ?property ?value | |
WHERE { | |
botchan:中学校 ?property ?value . | |
} | |
# データセット全体のサマリー | |
SELECT ?type (COUNT(?resource) as ?count) | |
WHERE { | |
?resource rdf:type ?type . | |
} | |
GROUP BY ?type | |
# ===================================== | |
# 9. 条件分析クエリ | |
# ===================================== | |
# 孤立している人物(特別な関係がない人物) | |
SELECT ?person ?name ?job | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name ; | |
vocab:職業 ?job . | |
FILTER NOT EXISTS { | |
?person vocab:対立関係|vocab:味方関係|vocab:同盟関係|vocab:恋愛関係 ?other . | |
} | |
FILTER NOT EXISTS { | |
?other vocab:対立関係|vocab:味方関係|vocab:同盟関係|vocab:恋愛関係 ?person . | |
} | |
} | |
# 最も多くの関係を持つ人物 | |
SELECT ?person ?name (COUNT(?relationship) as ?relationship_count) | |
WHERE { | |
?person rdf:type vocab:人物 ; | |
rdfs:label ?name . | |
{ | |
?person ?relationship ?other . | |
?other rdf:type vocab:人物 . | |
} | |
UNION | |
{ | |
?other ?relationship ?person . | |
?other rdf:type vocab:人物 . | |
} | |
FILTER(?relationship IN (vocab:対立関係, vocab:味方関係, vocab:同盟関係, vocab:恋愛関係, vocab:世話になった人, vocab:世話した人)) | |
} | |
GROUP BY ?person ?name | |
ORDER BY DESC(?relationship_count) | |
# ===================================== | |
# 10. 推論的検索 | |
# ===================================== | |
# 間接的な敵関係(敵の同盟者) | |
SELECT ?person ?name ?indirect_enemy ?enemy_name | |
WHERE { | |
botchan:坊ちゃん vocab:対立関係 ?direct_enemy . | |
?direct_enemy vocab:同盟関係 ?indirect_enemy . | |
?person rdfs:label ?name . | |
?indirect_enemy rdfs:label ?enemy_name . | |
FILTER(?indirect_enemy != botchan:坊ちゃん) | |
} | |
# 潜在的な味方関係(味方の味方) | |
SELECT ?person ?name ?potential_ally ?ally_name | |
WHERE { | |
botchan:坊ちゃん vocab:味方関係 ?direct_ally . | |
?direct_ally vocab:味方関係 ?potential_ally . | |
?person rdfs:label ?name . | |
?potential_ally rdfs:label ?ally_name . | |
FILTER(?potential_ally != botchan:坊ちゃん) | |
} |
この中の同盟関係の一覧を問い合わせてみます。
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX botchan: <http://example.org/botchan/>
PREFIX vocab: <http://example.org/vocabulary/>
# 同盟関係の一覧
SELECT ?person1 ?name1 ?person2 ?name2
WHERE {
?person1 vocab:同盟関係 ?person2 ;
rdfs:label ?name1 .
?person2 rdfs:label ?name2 .
}
ボタンExecute SPARQL Queryをクリックすると、以下のコードが実行されます。REST APIのエンドポイントはUpdateと同じですが、Content-Typeとしてapplication/sparql-queryを指定しています。また、Acceptにapplication/sparql-results+jsonを指定することで、レスポンスをJSON形式で受け取っています。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_base_url apex_workspace_remote_servers.base_url%type; | |
l_operation_url varchar2(400); | |
l_request clob; | |
l_response clob; | |
e_call_api_failed exception; | |
l_status_code number; | |
begin | |
select base_url into l_base_url from apex_workspace_remote_servers | |
where remote_server_static_id = :G_REMOTE_SERVER; | |
l_operation_url := | |
apex_string.format(l_base_url || '/database/rdf/networks/%s,%s/models/%s/sparql/1.1', | |
:P1_NETWORK_OWNER, :P1_NETWORK_NAME, :P1_MODEL_NAME); | |
apex_debug.info('operation_url = %s', l_operation_url); | |
l_request := :P1_SPARQL_QUERY; | |
apex_web_service.set_request_headers('Content-Type', 'application/sparql-query', 'Accept', 'application/sparql-results+json'); | |
l_response := apex_web_service.make_rest_request( | |
p_url => l_operation_url | |
,p_http_method => 'POST' | |
,p_body => l_request | |
,p_credential_static_id => :G_CREDENTIAL | |
); | |
l_status_code := apex_web_service.g_status_code; | |
apex_debug.info('status_code = %s', l_status_code); | |
if not l_status_code between 200 and 300 then | |
raise e_call_api_failed; | |
end if; | |
:P1_RESPONSE := l_response; | |
end; |
野だいこと赤シャツが同盟関係にあるとのことです。
以上で、ORDSのRDF Graph APIを呼び出すことにより、RDFグラフの作成および検索ができることを確認できました。
今回の記事は以上になります。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完