Java Application Developer's Guide (PDF)

Java Application Developer's Guide — Chapter 10

« Previous chapter
Next chapter »

Alerting

The MarkLogic Java API enables you to create applications that include client-side alerting capabilities through the com.marklogic.client.alerting package. You can use the RuleDefinition and RuleManager interfaces to create and maintain alerting rules and to test documents for matches to rules.

This chapter covers the following topics:

Alerting Pre-Requisites

You should enable fast reverse searches on the content database associated with your REST API instance. Enable fast reverse searches using the Admin Interface, as described in Indexes for Reverse Queries in Search Developer's Guide, or using the XQuery function admin:database-set-fast-reverse-searches.

Creating or delete alerting rules requires the rest-writer role, or equivalent privileges. All other alerting operations require the rest-reader role, or equivalent privileges.

Alerting Concepts

An alerting application is one that takes action whenever content matches a pre-defined set of criteria. For example, send an email notification to a user whenever a document about influenza is added to the database. In this case, the criteria might be the abstract contains the word influenza, and the action is send an email.

MarkLogic Server supports server-side alerting through the XQuery API and Content Processing Framework (CPF), and client-side alerting through the REST and Java APIs.

A server-side alerting application usually uses a push model. You register alerting rules and XQuery action functions with MarkLogic Server. Whenever content matches the rules, MarkLogic Server evaluates the action functions. For details, see Creating Alerting Applications in Search Developer's Guide.

By contrast, a client-side alerting application uses a pull alerting model. You register altering rules with MarkLogic Server, as in the push model. However, your application must poll MarkLogic Server for matches to the configured rules, and the application initiates actions in response to matches. This is the model used by the REST Client API.

An alerting rule is a query used in a reverse query to determine whether or not a search using that query would match a given document. A normal search query asks What documents match these search criteria? A reverse query asks What criteria match this document? In the influenza example above, you might define a rule that is a word query for influenza, with an element constraint of <abstract/>. Alerting rules are stored in the content database associated with your REST API instance.

MarkLogic Server provides fast, scalable rule matching by storing queries in alerting rules in the database and indexing them in the reverse query index. You must explicitly enable fast reverse searches on your content database to take advantage of the reverse quer index. For details, see Indexes for Reverse Queries in Search Developer's Guide.

Use the procedures described in this chapter to create and maintain search rules and to test documents for matches to the rules installed in your REST API instance. Determining what actions to take in response to a match and initiating those actions is left to the application.

Defining Alerting Rules

An alerting rule is defined by a name, a query, and optional metadata. The core of a rule is the combined query that describes the search criteria to use in future match operations. A combined query encapsulates a string and/or structured query plus query options; for syntax details and examples, see Specifying Dynamic Query Options with Combined Query in REST Application Developer's Guide.

Choose one of the following methods to define a rule:

Note that although you can define a rule in JSON, it will be returned as XML when you read it back from the database.

Defining a Rule Using RuleDefinition

Follow this procedure to define a rule using com.marklogic.client.alerting.RuleDefinition:

  1. If you have not already done so, connect to the database, storing the connection in a com.marklogic.client.DatabaseClient object. For example, if using digest authentication:
    DatabaseClient client = DatabaseClientFactory.newClient(
        host, port, new DigestAuthContext(username, password));
  2. If you have not already done so, create a com.marklogic.client.alerting.RuleManager.
    RuleManager ruleMgr = client.newRuleManager();
  3. Create a com.marklogic.client.admin.RuleDefinition object and populate it with your rule name and data. Optionally, you can include a description and metadata.
    RuleDefinition rule = new RuleDefinition(RULE_NAME, RULE_DESC);
    
    String combinedQuery = ...; // see complete example, below
    StringHandle qHandle = new StringHandle(combinedQuery);
    rule.importQueryDefinition(qHandle);
    
    RuleMetadata metadata = rule.getMetadata();
    metadata.put(new QName("author"), "me");
  4. Save the rule to the database by calling RuleManager.writeRule().
    ruleMgr.writeRule(rule);

The following example code snippet puts all the steps together. The example rule matches documents containing the term xdmp.

// create a manager for configuring rules
RuleManager ruleMgr = client.newRuleManager();
RuleDefinition rule = new RuleDefinition(RULE_NAME, RULE_DESC);

// Configure metadata
RuleMetadata metadata = rule.getMetadata();
metadata.put(new QName("author"), "me");

// Configure the match query
String combinedQuery =
    "<search:search "+
            "xmlns:search='http://marklogic.com/appservices/search'>"+
      "<search:qtext>xdmp</search:qtext>"+
      "<search:options>"+
        "<search:term>"+
          "<search:term-option>case-sensitive</search:term-option>"+
        "</search:term>"+
      "</search:options>"+
    "</search:search>";

//Or the JSON equivalent
String combinedQueryJson = 
        "{\"search\":{" +
                "   \"qtext\": \"xdmp\"," +
                "   \"options\": {" +
                "      \"term\": {" +
                "         \"term-option\": \"case-sensitive\"" +
                "      }" +
                "   }" +
                "}" +
            "}";

StringHandle qHandle = 
    new StringHandle(combinedQuery).withFormat(Format.XML);
//JSON equvalent
    new StringHandle(combinedQueryJson).withFormat(Format.JSON);
rule.importQueryDefinition(qHandle);

// Write the rule to the database
ruleMgr.writeRule(rule);

Defining a Rule in Raw XML

Follow this procedure to define a rule directly in XML. When creating the rule, use the template in Defining an Alerting Rule in REST Application Developer's Guide.

  1. If you have not already done so, connect to the database, storing the connection in a com.marklogic.client.DatabaseClient object. For example, if using digest authentication:
    DatabaseClient client = DatabaseClientFactory.newClient(
        host, port, new DigestAuthContext(username, password));
  2. If you have not already done so, create a com.marklogic.client.alerting.RuleManager.
    RuleManager ruleMgr = client.newRuleManager();
  3. Create an XML representation of the rule, using a text editor or other tool or library.cription and metadata. The following example uses String for the raw representation.
    String rawRule =
        "<rapi:rule xmlns:rapi='http://marklogic.com/rest-api'>"+
          "<rapi:name>"+RULE_NAME+"</rapi:name>"+
          "<rapi:description>An example rule.</rapi:description>"+
          "<search:search "+
                  "xmlns:search='http://marklogic.com/appservices/search'>"+
            "<search:qtext>xdmp</search:qtext>"+
            "<search:options>"+
              "<search:term>"+
                  "<search:term-option>case-sensitive</search:term-option>"+
              "</search:term>"+
            "</search:options>"+
          "</search:search>"+
          "<rapi:rule-metadata>"+
              "<author>me</author>"+
          "</rapi:rule-metadata>"+
        "</rapi:rule>";
  4. Create a handle on your raw query, using a class that implements RuleWriteHandle. For example:
    StringHandle handle = 
        new StringHandle(rawRule).withFormat(Format.XML);
  5. Save the rule to the database by calling RuleManager.writeRule().
    ruleMgr.writeRule(RULE_NAME, handle);

The following example code snippet puts all the steps together. The example rule matches documents containing the term xdmp.

// create a manager for configuring rules
RuleManager ruleMgr = client.newRuleManager();

// Define the rule in raw XML
String rawRule =
  "<rapi:rule xmlns:rapi='http://marklogic.com/rest-api'>"+
    "<rapi:name>"+RULE_NAME+"</rapi:name>"+
    "<rapi:description>An example rule.</rapi:description>"+
    "<search:search "+
            "xmlns:search='http://marklogic.com/appservices/search'>"+
      "<search:qtext>xdmp</search:qtext>"+
      "<search:options>"+
        "<search:term>"+
          "<search:term-option>case-sensitive</search:term-option>"+
        "</search:term>"+
      "</search:options>"+
    "</search:search>"+
    "<rapi:rule-metadata>"+
        "<author>me</author>"+
    "</rapi:rule-metadata>"+
  "</rapi:rule>";

// create a handle for writing the rule
StringHandle handle = 
    new StringHandle(rawRule).withFormat(Format.XML);

// write the rule to the database
ruleMgr.writeRule(RULE_NAME, handle);

Defining a Rule in Raw JSON

Follow this procedure to define a rule directly in XML. When creating the rule, use the template in Defining an Alerting Rule in REST Application Developer's Guide.

  1. If you have not already done so, connect to the database, storing the connection in a com.marklogic.client.DatabaseClient object. For example, if using digest authentication:
    DatabaseClient client = DatabaseClientFactory.newClient(
        host, port, new DigestAuthContext(username, password));
  2. If you have not already done so, create a com.marklogic.client.alerting.RuleManager.
    RuleManager ruleMgr = client.newRuleManager();
  3. Create a JSON representation of the rule, using a text editor or other tool or library.cription and metadata. The following example uses String for the raw representation.
    String rawRule =
              "{ \"rule\": {"+
                "\"name\" : \""+RULE_NAME3+"\","+
                "\"search\" : {"+
                  "\"qtext\" : \"xdmp\","+
                  "\"options\" : {"+
                    "\"term\" : { \"term-option\" : \"case-sensitive\" }"+
                  "}"+
                "},"+
                "\"description\": \"A JSON example rule.\","+
                "\"rule-metadata\" : { \"author\" : \"me\" }"+
              "}}";
  4. Create a handle using a class that implements RuleWriteHandle and associate your raw rule with the handle. For example:
    StringHandle handle = 
        new StringHandle(rawRule).withFormat(Format.JSON);
  5. Save the rule to the database by calling RuleManager.writeRule().
    ruleMgr.writeRule(RULE_NAME, handle);

The following example code snippet puts all the steps together. The example rule matches documents containing the term xdmp.

// create a manager for configuring rules
RuleManager ruleMgr = client.newRuleManager();

// Define the rule in raw JSON
String rawRule =
  "{ \"rule\": {"+
    "\"name\" : \""+RULE_NAME3+"\","+
    "\"search\" : {"+
      "\"qtext\" : \"xdmp\","+
      "\"options\" : {"+
        "\"term\" : { \"term-option\" : \"case-sensitive\" }"+
      "}"+
    "},"+
    "\"description\": \"A JSON example rule.\","+
    "\"rule-metadata\" : { \"author\" : \"me\" }"+
  "}}";

// Create a handle for writing the rule
StringHandle qHandle = 
    new StringHandle(rawRule).withFormat(Format.JSON);

// Write the rule to the database
ruleMgr.writeRule(RULE_NAME3, qHandle);

Testing for Matches to Alerting Rules

Once you install alerting rules in your REST API instance, use RuleManager.match() to determine which rules match one or more input documents. You can select the input documents using a database query or database URIs, or by passing a transient document.

This section covers the following topics:

Basic Steps

Follow this procedure to test one or more documents to see if they match installed alerting rules. Identify the input documents using a query or URIs, or by passing in a transient input document.

  1. If you have not already done so, connect to the database, storing the connection in a com.marklogic.client.DatabaseClient object. For example, if using digest authentication:
    DatabaseClient client = DatabaseClientFactory.newClient(
        host, port, new DigestAuthContext(username, password));
  2. If you have not already done so, create a com.marklogic.client.alerting.RuleManager.
    RuleManager ruleMgr = client.newRuleManager();
  3. Find the rules that match your input documents by calling RuleManager.match(). The result is a list of RuleDefinition objects. The following example uses a query to identify the input documents.
    StringQueryDefinition querydef = ...;
    RuleDefinitionList matchedRules = 
        ruleMgr.match(querydef, new RuleDefinitionList());

The match() method returns the definition of any rules matching your input documents.

You can further customize rule matching by limiting the match results to a subset of the installed rules or applying a server-side transformation to the match results. For details, see the JavaDoc for RuleManager.

For a complete example, see com.marklogic.client.example.cookbook.RawClientAlert.

Identifying Input Documents Using a Query

You can use a string query, structured query, or combined query to select the documents in the database that you want to test for rule matches. These instructions assume you are familiar with constructing queries using the Java API; for details, see Searching.

Use the following procedure to select input documents using a query:

  1. Construct a string, structured, or combined query definition as described in Searching. The following example uses StringQueryDefinition.
    QueryManager queryMgr = client.newQueryManager();
    String criteria = "document";
    StringQueryDefinition querydef = queryMgr.newStringDefinition();
    querydef.setCriteria(criteria);
  2. If you constructed a raw XML or JSON query definition, create a handle using a class that implements StructureWriteHandle. For example, if you created an XML query using String, create a StringHandle:
    StringHandle rawHandle = 
        new StringHandle(rawXMLQuery).withFormat(Format.XML);
    //Or
        new StringHandle(rawJSONQuery).withFormat(Format.JSON);
  3. Call RuleManager.match(), passing in either a QueryDefinition or StructureWriteHandle to the document selection query.
    RuleDefinitionList matchedRules = 
        ruleMgr.match(querydef, new RuleDefinitionList());

For a complete example, see com.marklogic.client.example.cookbook.RawClientAlert.

You can limit the rules under consideration by passing an array of rule names to RuleManager.match(). You can limit the input documents to a subset of the input query results by specifying start and page length. For details, see the JavaDoc for RuleManager.

Identifying Input Documents Using URIs

You can select the documents you want to test for rule matches by specifying a list of document URIs to RuleManager.match(). Each URI must identify a document, not a database directory.

Use the following procedure to select input documents using URIs:

  1. Construct a String array of document URIs.
    String[] docIds = { "/example/doc1.xml", "/suggest/doc2.xml" };
  2. Call RuleManager.match(), passing in the list of URIs.
    RuleDefinitionList matchedRules = 
        ruleMgr.match(docIds, new RuleDefinitionList());

You can limit the rules under consideration by passing an array of rule names to RuleManager.match(). For details, see the JavaDoc for RuleManager.

Matching Against a Transient Document

You can test for rule matches against a document that is not in the database by passing the transient document to RuleManager.match().

  1. Create a handle using a class that implements StructureWriteHandle. The following example uses a String as the source document.
    String doc = "<prefix>xdmp</prefix>";
    //Or
    String doc = "{\"prefix\": \"xdmp\"}"
    
    StringHandle handle = new StringHandle(doc).withFormat(Format.XML);
    //Or
    StringHandle handle = new StringHandle(doc).withFormat(Format.JSON);
    
  2. Call RuleManager.match(), passing in a StructureWriteHandle to the document.
    RuleDefinitionList matchedRules = 
        ruleMgr.match(handle, new RuleDefinitionList());

You can limit the rules under consideration by passing an array of rule names to RuleManager.match(). For details, see the JavaDoc for RuleManager.

Filtering Match Results

By default, the result of an alert match includes all matching rules. You can limit the result to a subset of matching rules by passing a list of candiate rule names to RuleManager.match(). For example, the result of the following match includes at most the definitions of the rules named one and two, even if more rules match the input query definition:

RuleManager ruleMgr = client.newRuleManager();
StringQueryDefinition querydef = ...;
String [] candidateRules = new String[] {"one", "two"};
RuleDefinitionList matchedRules = 
    ruleMgr.match(querydef, 0L, QueryManager.DEFAULT_PAGE_LENGTH, 
        candidateRules, new RuleDefinitionList());

Transforming Alert Match Results

You can make arbitrary changes to the results from a match request by applying a server-side XQuery transformation function to the results. This section covers the following topics:

Writing a Match Result Transform

Alert match transforms use the same interface and framework as content transformations applied during document ingestion, described in Writing Transformations in the REST Application Developer's Guide.

Your transform function receives the raw XML match result data prepared by MarkLogic Server as input, such as a document with a <rapi:rules/> root element. For example:

<rapi:rules xmlns:rapi="http://marklogic.com/rest-api">
  <rapi:rule>
    <rapi:name>one</rapi:name>
    <rapi:description>Rule 1</rapi:description>
    <search:search
        xmlns:search="http://marklogic.com/appservices/search">
      <search:qtext>xdmp</search:qtext>
    </search:search>
  </rapi:rule>
</rapi/rules>

If your function produces XML output and the client application requested JSON output, MarkLogic Server will transform your output to JSON only if one of the following conditions are met.

  • Your function produces an XML document that conforms to the normal output from the search operation. For example, a document with a <rapi:rules/> root element whose contents are changed in a way that preserves the normal structure.
  • Your function produces an XML document with a root element in the namespace http://marklogic.com/xdmp/json/basic that can be transformed by json:transform-to-json.

Under all other circumstances, the output returned by your transform function is what is returned to the client application.

Using a Match Result Transform

To use a server transform function:

  1. Create a transform function according to the interface described in Writing Transformations in the REST Application Developer's Guide.
  2. Install your transform function on the REST API instance following the instructions in Installing Transforms.
  3. In your application, create a ServerTransform object to represent the installed transform, and pass it as a parameter on your call to RuleManager.match(). For example:
    RuleManager ruleMgr = client.newRuleManager();
    StringQueryDefinition querydef = ...;
    RuleDefinitionList matchedRules = 
        ruleMgr.match(querydef, 0L, QueryManager.DEFAULT_PAGE_LENGTH, 
            new String[] {}, new RuleDefinitionList(),
            new ServerTransform("your-transform-name"));

You are responsible for specifying a handle type capable of interpreting the results produced by your transform function. The RuleDefinitionList implementation provided by the Java API only understands the match results structure that MarkLogic Server produces by default.

« Previous chapter
Next chapter »
Powered by MarkLogic Server | Terms of Use | Privacy Policy