デザインパターン: トリプル出自のパターンとは

4月 17, 2020 データと AI, MarkLogic

MarkLogicデザインパターンは、MarkLogicアプリケーションの設計における一般的な問題に対処するための、再利用可能なソリューションです。
これらのパターンは、MarkLogicアプリケーションに固有のもの、あるいはMarkLogicを念頭に置いた各業界ごとのパターンになっています。
MarkLogicデザインパターンは、料理のレシピのように個別的・具体的なものではなく、一般に抽象度が高く、複数のシナリオに適用できます。

トリプル出自とドキュメント注釈デザインパターン

目的

セマンティックアプリケーションでは多くの場合、トリプルのレベルの出自情報を取得する必要があります。

エンベロープパターンを使って、トリプルのJSON/XMLシリアライゼーションに注釈として出自詳細を付けることができます。

背景

分散したソースのデータを使用するアプリケーションを構築する際(特にセマンティックコンテキストにおいて)、ソースや最終更新時刻などの出自情報を記録するのが一般的です。
RDFのみの場合、具体化(ステートメントに関するステートメントなど。「セマンティックWebにおける具体化」*Wiki 英語ページを参照)はテクニックとして使用できますが、多数のトリプルにおいて大幅な拡張が必要になり、SPARQLクエリが非常に複雑になってしまいます。

具体化によって複雑さを増すことなく、トリプルの出自詳細を出力できるソリューションが理想的です。
幸いにも、MarkLogicのドキュメントに保存されたトリプルでは、JSONおよびXMLシリアライゼーションを利用して、コンテキストのレベルを追加できます。これは、ドキュメント(特にトリプルオブジェクト)のメタデータを追加することにより実現されます。

適用

このパターンが該当するのは、トリプルのレベルで出自詳細を記録する必要がある場合です。This pattern requires that triples be persisted on documents, not using MarkLogic Managed Triples. このパターンは、出自詳細をSPARQLクエリの一部として直接戻す必要はないが、ドキュメント外で取得するのが望ましいような場合に適しています。

構成要素

このパターンの実装に関係する構成要素は次のとおりです。

  • トリプルに注釈付けする更新コード
  • トリプルの出自詳細を取得する取得コード

それぞれの例は、以下のサンプルコードを参照してください。

コラボレーション

取得コードは、更新コードが出自詳細をどのように永続化しているかを識別する必要があります。

結果

このパターンでは、JSONまたはXMLにシリアライズされたトリプルに注釈を保存することで、所定のトリプルに関する出自詳細の永続化を実現します。出自詳細の取得は、JavaScriptまたはXQueryを使ってドッキュメントに渡し、マッチングする対象トリプルを特定し、注釈を返すことで行います。

このパターンを利用する場合、管理トリプルは使用できません。ドキュメントの挿入/更新中または読み込みの前に、出自注釈を追加する必要があります。また、トリプルが存在するドキュメントを特定する必要があります。

特定するには、主題IRIをドキュメントのURIに関連付けるアイデンティティトリプルを使用します。

const subject = sem.iri("http://marklogic.com/resources/myEntity");
const uri = sem.iri("/content/myEntity.json");
sem.triple(subject,sem.iri("http://www.w3.org/2000/01/rdf-schema#isDefinedBy"), uri);

このパターンを使用した場合は、純粋なSPARQLを使用して出自詳細を検索することができなくなります。

実装

このパターンを実装する場合は、出自詳細を追加および取得するための、一貫したプロセスを用意することが重要です。

アプリケーションでTDE(Template Driven Extraction)を使用している場合、次のように、出自詳細に注釈を付ける要素/プロパティをラップできます。

{
    "metadata": [
        {
            "propertyWrapper": {
                "systemOwner": "Joe Smith",
                "source": "DB1",
                "updateTime": "2017-05-17T14:17:38.786Z"
            }
        },
        {
            "propertyWrapper": {
                "id": "ABC",
                "source": "DB1",
                "updateTime": "2017-05-17T14:17:38.786Z"
            }
        }
    ]
}

以下にTDEテンプレートのサンプルを示します。

{
 "template": {
 "context": "/metadata",
 "vars": [
 {
 "name": "prefix-subjects",
 "val": "'http://example.org/subjects'"
 },
 
 {
 "name": "prefix-predicates",
 "val": "'http://example.org/predicates'"
 },
 {
 "name": "doc-id",
 "val": "sem:iri($prefix-subjects || '/' || fn:root(.)/metadata/propertyWrapper/id/fn:string())"
 }
 ],
 "triples": [
 {
 "subject" : {"val" : "$doc-id"},
 "predicate" : {"val" : "sem:iri($prefix-predicates || '/id')"},
 "object" : { "val" : "propertyWrapper/id/fn:string()", "invalidValues" : "ignore"}
 },
 {
 "subject" : {"val" : "$doc-id"},
 "predicate" : {"val" : "sem:iri($prefix-predicates || '/systemOwner')"},
 "object" : { "val" : "propertyWrapper/systemOwner/fn:string()", "invalidValues" : "ignore"},
 
 }
 ]
 }
 }
サンプルコード

XMLドキュメントでは、トリプルで属性を使用することで非常に簡単に実行できます。

declare namespace prov = "http://marklogic.com/designPatterns/prov";
declare function prov:add-provenance($triple as sem:triple, $source as xs:string, $timestamp as xs:dateTime) {
  element sem:triple {
    attribute source {$source},
    attribute updatedTime {$timestamp},
    document {  $triple  }/element()/node()
  }
};
let $triple := sem:triple(sem:iri("myIri"),sem:iri("myProperty"),"a value")
return
prov:add-provenance($triple,"DB", fn:current-dateTime())

JSONにおけるサンプル手法を以下に示します。ただし、属性を使う代わりに、トリプルオブジェクトにプロパティを追加しています。

function addProvenance(triple, source, timestamp) {
 const t = xdmp.toJSON(triple).toObject();
 t.triple.source = source;
 t.triple.timestamp = timestamp;
 return t;
}
const t = sem.triple(sem.iri("JSON Annotation"), sem.iri("testProp"), "value");
addProvenance(t, "myDB", new Date().toJSON());

出自詳細の取得方法の例を以下に示します。

function getProvenance(uri, predicate, value) {
 const triple = fn.head(cts.doc(uri).xpath(`/triples/triple[predicate = '${predicate}' and object/value eq '${value}']`));
 const result = {};
 result.source = triple.source;
 result.timestamp = triple.timestamp;
 return result;
}
関連パターン

エンベロープパターンとは(ブログ)

まとめ

トリプル単体では、出自詳細を取得するのは簡単ではありません。複雑になり、トリプルの使い勝手とクエリのパフォーマンスが悪くなる恐れがあります。
MarkLogicのマルチモデルサポートを利用すれば、注釈付きのドキュメントに埋め込まれているトリプルを利用できます。コンテキストを追加し、短いJavaScriptコードまたはXQueryコードを使って簡単に取得できます。

ドキュメントに埋め込まれているトリプルを利用する他の方法について詳しくは、セマンティックガイドおよび非管理トリプル(英語)に関する章を参照してください。

Tom Ternquist