MarkLogic独自の更新系XQuery関数


概要

MarkLogicで実行できるXQueryの関数は、W3C標準のものに加えてMarkLogic独自の関数が用意されています。W3C標準の関数はfn:docのような検索やfn:replaceのような変換を行います。これに対してMarkLogic独自の更新系関数を取り上げます。


ドキュメント挿入クエリ

ドキュメントの挿入はxdmp:document-insertを使います。この関数は第1引数に挿入先、第2引数に挿入内容を設定します。第3引数はオプションですが、コレクションやアクセス権を設定したい場合は、後々設定するよりも挿入時のこの関数で決めておいた方がver9から第3引数の記入方法が大きく変わっていますので、ver9へのバージョンアップではくれぐれもご注意ください。

下記のサンプルは複数のパターンで同じ挿入内容を作り、別々のドキュメントURIで挿入を行うというものです。エスケープ文字への対応などあると思いますので最も適した方法を選んでいただければと思います。なおxdmp:document-insertは戻り値を返しません。クエリコンソールで試してみて下さい。

xquery version "1.0-ml";

(: 挿入先URIヘッダ :)
let $dir := "/insTest/"
(: 挿入内容 :)
let $content1 := element {"root"}{element {"a"}{"x"}}
let $content2 := <root><a>x</a></root>
let $content3 := xdmp:unquote("<root><a>x</a></root>")
let $content-seq := ($content1, $content2, $content3)
(: 挿入 :)
for $content at $cnt in $content-seq
let $uri := fn:concat($dir, $cnt, ".xml")
return xdmp:document-insert($uri, $content)

挿入されたドキュメントはこんな感じになります。

<root><a>x</a></root>


ドキュメント更新クエリ

ドキュメントの部分更新は、そのxdmp:node-replaceなどを使います。他の関数も含めて表にまとめます。経験的には一旦入れたドキュメントを更新するよりも、同じURIに上書き挿入した方が性能が良いような気がします。

関数
説明

xdmp:node-insert-before
指定した要素の前に要素を挿入する

xdmp:node-insert-after
指定した要素の後ろに要素を挿入する

xdmp:node-insert-child
指定した要素の子供として要素を挿入する

xdmp:node-replace
指定した要素を取り換える

xdmp:node-delete
指定した要素を削除する

xdmp:node-insert-beforeでサンプルを作ってみました。URI名に設定した数字を基にno要素を追加していきます。

xquery version "1.0-ml";

(: 更新対象URIヘッダ :)
let $dir := "/insTest/"
(: 更新対象の確認 :)
let $uri-seq := cts:uris((), (), cts:directory-query("/insTest/", "1"))
(: 更新 :)
for $uri in $uri-seq
let $doc := fn:doc($uri)
let $uriTokenized := fn:tokenize($uri, "/")[fn:last()]
let $cnt := fn:substring-before($uriTokenized, ".xml")
let $nodeInserted := element {"no"}{$cnt}
return xdmp:node-insert-before($doc/root/a, $nodeInserted)

更新されたドキュメントのうち/insTest/1.xmlはこんな感じになります。

<root><no>1</no><a>x</a></root>

このクエリ自体は挿入クエリ内を書き換えることで、挿入クエリに統一できますが、何らかの形で既存データの修正を求められる場合には必要になると思います。大量のデータを処理する場合は、このようなforループではなく、AP側のマルチスレッド処理かxdmp:spawn系関数でタスクサーバを使うなどの並列処理をお奨めします。


ドキュメント削除クエリ

ドキュメントの削除は、xdmp:document-deleteを使います。ここで挿入・更新してみた3つのドキュメントを削除するサンプルを作りました。cts:urisという関数を使って削除対象となるURIシーケンスを作成して、forループで1個ずつ削除しています。大量のデータを対象にする場合は、やはり並列処理を視野に入れておくべきです。

xquery version "1.0-ml";

(: 削除対象URIヘッダ :)
let $dir := "/insTest/"
(: 削除対象URI :)
let $uri-seq := cts:uris((), (), cts:directory-query($dir, "1"))
(: 削除 :)
for $uri in $uri-seq
return xdmp:document-delete($uri)


雑感

W3C標準関数を補完する形で存在するこれらの関数は、単に検索だけでなくCRUDを備えたデータベースとしての機能を整えるものです。一方で製品独自の関数というのは個別の勉強が必要となり取っ付きにくくなる要因です。ひとまずここにある関数ぐらいは記憶しておきたいですね。