hhp
hhp

Reputation: 61

Using Marklogic 8 triggers for managed triples

I have a use case where I want to send a notification every time triples are added or deleted from MarkLogic. The notification should contain those triples and should say whether they were added or deleted.

I didn't find any mention in the MarkLogic triggers guide regarding how it might work with (managed) triples. Is there a way to write a trigger module so that for a modified document (containing the managed triples), compare the new version with the old version to work out what's added and deleted and send a HTTP request containing these changes?

I understand that doc($trgr:uri) will give me the latest state of the document in question - but is there a way to retrieve the previous version, before the change? I'm fairly new to MarkLogic and Xquery so some guidance is much appreciated. Thanks!

Upvotes: 4

Views: 117

Answers (2)

hhp
hhp

Reputation: 61

Many thanks to @grtjn for providing the way to access the pre-change document. For determining the difference between documents I found a way inspired by this blog post. The solution that I found to be working looks like this:

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)

I created 3 pre-commit triggers, one for each of the trgr:document-content options: create, modify and delete, all invoking the above module. A SPARQL Update query will cause the above module to trigger one or more times, printing the lists of triples which were added and deleted.

Couple of observations:

  • A single SPARQL Update statement can create, modify and delete multiple documents, so will trigger the module multiple times.
  • INSERT statements seem to always create new documents, so you'll will never get added triples and deleted triples in the same invocation.
  • The code assumes there's only one collection for a document, which is the named graph for managed triples. It will need extra work if there are to be multiple collections per document.

Upvotes: 2

grtjn
grtjn

Reputation: 20414

I think you can only achieve this in one way:

  • use pre-commit triggers
  • use xdmp:eval with isolation for different-transaction to get the original document

Something like:

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))

I ran a quick test with a trigger scoped for collection 'test'. I then inserted a doc at /test.xml with contents <test>a</test>, and did NOT add it to collection test yet. I then updated the document with <test>b</test>, and also added it to collection test to activate the trigger. It logged a and b..

This shows how you can get both original and updated document. Determining the difference is a challenge on its own..

HTH!

Upvotes: 2

Related Questions