将 Marklogic 8 触发器用于托管三元组
Using Marklogic 8 triggers for managed triples
我有一个用例,每次从 MarkLogic 添加或删除三元组时,我都想发送通知。通知应包含这些三元组,并说明它们是添加还是删除。
我没有在 MarkLogic triggers guide 中找到任何关于它如何与(托管)三元组一起工作的提及。有没有办法编写触发器模块,以便对于修改后的文档(包含托管三元组),将新版本与旧版本进行比较以计算出添加和删除的内容并发送包含这些更改的 HTTP 请求?
我知道 doc($trgr:uri) 会给我相关文档的最新状态 - 但是有没有办法在更改之前检索以前的版本?我对 MarkLogic 和 Xquery 还很陌生,所以非常感谢一些指导。谢谢!
我认为你只能通过一种方式实现:
- 使用
pre-commit
触发器
- 使用
xdmp:eval
和 isolation
for different-transaction
获取原始文档
类似于:
xquery version "1.0-ml";
import module namespace trgr = "http://marklogic.com/xdmp/triggers" at "/MarkLogic/triggers.xqy";
declare variable $trgr:uri as xs:string external;
xdmp:log("Triggered processing of " || $trgr:uri || ".."),
xdmp:log(xdmp:eval('doc("'||$trgr:uri||'")', (), <options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>)),
xdmp:log(doc($trgr:uri))
我 运行 一个快速测试,触发器范围为收集 'test'。然后,我在 /test.xml 处插入了一个内容为 <test>a</test>
的文档,但尚未将其添加到集合测试中。然后我用 <test>b</test>
更新了文档,并将其添加到集合测试以激活触发器。它记录了 a 和 b..
这显示了如何获取原始文档和更新后的文档。确定差异本身就是一个挑战..
HTH!
非常感谢@grtjn 提供了访问变更前文档的方法。为了确定文档之间的差异,我找到了一种受此 blog post 启发的方法。我发现有效的解决方案如下所示:
xquery version '1.0-ml';
import module namespace trgr='http://marklogic.com/xdmp/triggers' at '/MarkLogic/triggers.xqy';
declare function local:diff($seq1 as item()*, $seq2 as item()*) as item()* {
let $map1 := map:new($seq1 ! map:entry(fn:string(.), .))
let $map2 := map:new($seq2 ! map:entry(fn:string(.), .))
return map:keys($map1 - $map2) ! map:get($map1,.)
};
declare variable $trgr:uri as xs:string external;
declare variable $after := doc($trgr:uri)/sem:triples/sem:triple;
declare variable $before := xdmp:eval('doc("'||$trgr:uri||'")', (),
<options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>)/sem:triples/sem:triple;
declare variable $added_triples := local:diff($after, $before);
declare variable $added_graph := xdmp:document-get-collections($trgr:uri);
declare variable $deleted_triples := local:diff($before, $after);
declare variable $deleted_graph := xdmp:eval('xdmp:document-get-collections("'||$trgr:uri||'")', (),
<options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>);
xdmp:log(fn:concat('***** Trigger processing: ', $trgr:uri, '*****')),
xdmp:log('***** added triples *****'),
xdmp:log($added_graph),
xdmp:log($added_triples),
xdmp:log('***** deleted triples *****'),
xdmp:log($deleted_graph),
xdmp:log($deleted_triples)
我创建了 3 个 pre-commit
触发器,每个 trgr:document-content
选项一个:create
、modify
和 delete
,它们都调用了上述模块. SPARQL 更新查询将导致上述模块触发一次或多次,打印添加和删除的三元组列表。
几个观察结果:
- 一条SPARQL更新语句可以创建、修改和删除多个文档,因此会多次触发该模块。
- INSERT 语句似乎总是创建新文档,因此您永远不会在同一调用中获得添加的三元组和删除的三元组。
- 该代码假定文档只有一个集合,即托管三元组的命名图。如果每个文档有多个集合,则需要额外的工作。
我有一个用例,每次从 MarkLogic 添加或删除三元组时,我都想发送通知。通知应包含这些三元组,并说明它们是添加还是删除。
我没有在 MarkLogic triggers guide 中找到任何关于它如何与(托管)三元组一起工作的提及。有没有办法编写触发器模块,以便对于修改后的文档(包含托管三元组),将新版本与旧版本进行比较以计算出添加和删除的内容并发送包含这些更改的 HTTP 请求?
我知道 doc($trgr:uri) 会给我相关文档的最新状态 - 但是有没有办法在更改之前检索以前的版本?我对 MarkLogic 和 Xquery 还很陌生,所以非常感谢一些指导。谢谢!
我认为你只能通过一种方式实现:
- 使用
pre-commit
触发器 - 使用
xdmp:eval
和isolation
fordifferent-transaction
获取原始文档
类似于:
xquery version "1.0-ml";
import module namespace trgr = "http://marklogic.com/xdmp/triggers" at "/MarkLogic/triggers.xqy";
declare variable $trgr:uri as xs:string external;
xdmp:log("Triggered processing of " || $trgr:uri || ".."),
xdmp:log(xdmp:eval('doc("'||$trgr:uri||'")', (), <options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>)),
xdmp:log(doc($trgr:uri))
我 运行 一个快速测试,触发器范围为收集 'test'。然后,我在 /test.xml 处插入了一个内容为 <test>a</test>
的文档,但尚未将其添加到集合测试中。然后我用 <test>b</test>
更新了文档,并将其添加到集合测试以激活触发器。它记录了 a 和 b..
这显示了如何获取原始文档和更新后的文档。确定差异本身就是一个挑战..
HTH!
非常感谢@grtjn 提供了访问变更前文档的方法。为了确定文档之间的差异,我找到了一种受此 blog post 启发的方法。我发现有效的解决方案如下所示:
xquery version '1.0-ml';
import module namespace trgr='http://marklogic.com/xdmp/triggers' at '/MarkLogic/triggers.xqy';
declare function local:diff($seq1 as item()*, $seq2 as item()*) as item()* {
let $map1 := map:new($seq1 ! map:entry(fn:string(.), .))
let $map2 := map:new($seq2 ! map:entry(fn:string(.), .))
return map:keys($map1 - $map2) ! map:get($map1,.)
};
declare variable $trgr:uri as xs:string external;
declare variable $after := doc($trgr:uri)/sem:triples/sem:triple;
declare variable $before := xdmp:eval('doc("'||$trgr:uri||'")', (),
<options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>)/sem:triples/sem:triple;
declare variable $added_triples := local:diff($after, $before);
declare variable $added_graph := xdmp:document-get-collections($trgr:uri);
declare variable $deleted_triples := local:diff($before, $after);
declare variable $deleted_graph := xdmp:eval('xdmp:document-get-collections("'||$trgr:uri||'")', (),
<options xmlns="xdmp:eval"><isolation>different-transaction</isolation></options>);
xdmp:log(fn:concat('***** Trigger processing: ', $trgr:uri, '*****')),
xdmp:log('***** added triples *****'),
xdmp:log($added_graph),
xdmp:log($added_triples),
xdmp:log('***** deleted triples *****'),
xdmp:log($deleted_graph),
xdmp:log($deleted_triples)
我创建了 3 个 pre-commit
触发器,每个 trgr:document-content
选项一个:create
、modify
和 delete
,它们都调用了上述模块. SPARQL 更新查询将导致上述模块触发一次或多次,打印添加和删除的三元组列表。
几个观察结果:
- 一条SPARQL更新语句可以创建、修改和删除多个文档,因此会多次触发该模块。
- INSERT 语句似乎总是创建新文档,因此您永远不会在同一调用中获得添加的三元组和删除的三元组。
- 该代码假定文档只有一个集合,即托管三元组的命名图。如果每个文档有多个集合,则需要额外的工作。