Search code examples
triggerssemanticsmarklogic

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!


Solution

  • 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.