Traversal Queries

Besides querying for objects directly using the Data Management API, the Analysis API also supports the concept defining a Network for analysis dynamically without explicitly specifying a network reference. The following is an illustration of the usage. The technical details are documented separately:

Note

A valid traversal query should correspond with one or more nodes. When no nodes are found for an analysis request with a traversal query, an error will be raised.

Usage

Traversal queries can be used to facilitate business model construction by keeping a single, total view of risk in one structure, and then performing analyses on subsets of the structure as part of a well-defined workflow. They can also be used to facilitate ad-hoc analyses because they support dynamically building views of risk based on predefined properties of business model components.

Consider the following example of a simple business model with two potential loss sources and one financial structure.

digraph G { graph [ fontname="Courier", fontsize=12, size="7,5"]; node [ shape=rect, fontname="Courier", fontcolor=blue, fontsize=10, margin=0.1]; edge [ fontname="Courier", fontcolor=blue, fontsize=10]; ledger_node1 [label="{\l \"_schema\": \"LossSet\"\l \"path\": \"s3://bucket/path/file1.parquet\"\l \"type\": \"stochastic\"\l}\l"]; ledger_node2 [label="{\l \"_schema\": \"LossSet\"\l \"path\": \"s3://bucket/path/file2.parquet\"\l \"type\": \"historical\"\l}\l"]; quota_share [label="{\l \"_schema\": \"QuotaShare\"\l \"policy_id\": \"abc123\"\l \"inception_date\": 1546300800\l \"expiration_date\": 1577836800\l \"limit_value\": 30000.0\l \"premium_value\": 3000.0\l \"brokerage\": 0.1\l \"share\": 0.2\l}\l"] ledger_node1 -> quota_share; ledger_node2 -> quota_share; }

The business model above avoids having to define separate structures for the individual loss sources such that the financial terms of the QuotaShare policy here would need to be repeated in both versions of the structure. It would be possible to reuse the QuotaShare Node in two separate Networks but that option is also avoided. Instead, the following traversal queries can be used to select each “half” of the structure for independent analysis, either exclusively or together in the same request (if both are provided as separate NetworkAnalysisRequests in the same request to the Analysis API).

Stochastic loss analysis (example)

To match only the stochastic loss set and the subset of the above struture that includes it and the QuotaShare terms, the following query can be provided to the Analysis API at analysis time (represented here as JSON).

{
    "query": {
        "source_constraint": {
            "query": "_schema = \"LossSet\" & type = \"stochastic\""
        },
        "traversals": [
            {
                "link_constraint": {
                    "query": "*"
                },
                "destination_constraint": {
                    "query": "policy_id = \"abc123\""
                }
            }
        ]
    }
}

Note

The constraint query must have a value and cannot be left empty. This applies to source_constraint, link_constraint, and destination_constraint. However, when no constraint is required, the query value can be set to “*”, resulting in the retrieval of all elements.

The following structure results from the above traversal query:

digraph G { graph [ fontname="Courier", fontsize=12, size="7,5"]; node [ shape=rect, fontname="Courier", fontcolor=blue, fontsize=10, margin=0.1]; edge [ fontname="Courier", fontcolor=blue, fontsize=10]; ledger_node1 [label="{\l \"_schema\": \"LossSet\"\l \"path\": \"s3://bucket/path/file1.parquet\"\l \"type\": \"stochastic\"\l}\l"]; quota_share [label="{\l \"_schema\": \"QuotaShare\"\l \"policy_id\": \"abc123\"\l \"inception_date\": 1546300800\l \"expiration_date\": 1577836800\l \"limit_value\": 30000.0\l \"premium_value\": 3000.0\l \"brokerage\": 0.1\l \"share\": 0.2\l}\l"] ledger_node1 -> quota_share; }

Historical loss analysis (example)

Similarly, for the historical portion of losses:

{
    "query": {
        "source_constraint": {
            "query": "_schema = \"LossSet\" & type = \"historical\""
        },
        "traversals": [
            {
                "link_constraint": {
                    "query": "*"
                },
                "destination_constraint": {
                    "query": "policy_id = \"abc123\""
                }
            }
        ]
    }
}

The following structure results from the above traversal query:

digraph G { graph [ fontname="Courier", fontsize=12, size="7,5"]; node [ shape=rect, fontname="Courier", fontcolor=blue, fontsize=10, margin=0.1]; edge [ fontname="Courier", fontcolor=blue, fontsize=10]; ledger_node2 [label="{\l \"_schema\": \"LossSet\"\l \"path\": \"s3://bucket/path/file2.parquet\"\l \"type\": \"historical\"\l}\l"]; quota_share [label="{\l \"_schema\": \"QuotaShare\"\l \"policy_id\": \"abc123\"\l \"inception_date\": 1546300800\l \"expiration_date\": 1577836800\l \"limit_value\": 30000.0\l \"premium_value\": 3000.0\l \"brokerage\": 0.1\l \"share\": 0.2\l}\l"] ledger_node2 -> quota_share; }

Traversal Queries and Revision System

There is a Revision System integrated into Graphene. Every time when a new Node, Link or Network created it gets two numbers which are an id and a revision. These two numbers can specify the element explicitly.

When a Node, Links or Network gets updated/deleted the original element stays the same in the system. Instead of modifying the original, Data Management API creates a new element with a new revision number which is higher than original’s revision number.

Revision may or may not be used to reference elements. If a revision number used in a reference we call such reference pinned, if it was not used then we call the reference unpinned.

Let’s see differences in behavior of the endpoints that use Traversal Queries and the rest of endpoints in two examples.

Pinned reference

First, we create two Nodes and a Link which references the Nodes using both id and revision. Using the revisions makes the Nodes pinned to the Link. As a result of this creation, the Nodes and the Link are discoverable for endpoint FindNodesAndLinks. Also, the Link can be found using the FindLinks endpoint.

Second, we delete the Nodes. The Nodes get newer versions (marked as deleted) with higher revisions. As a result of this deletion, the Nodes and the Link become not discoverable for endpoint FindNodesAndLinks. Nevertheless, the Link can still be found using the FindLinks endpoint.

Unpinned reference

First, we create two Nodes and a Link that references the Nodes using only id, not revision. Not using the revisions makes the Nodes unpinned to the Link. As a result of this creation, the Nodes and the Link are discoverable for endpoint FindNodesAndLinks. Also, the Link can be found using the FindLinks endpoint.

Second, we delete the Nodes. The Nodes and the Link get newer versions (marked as deleted) with higher revisions. As a result of this deletion, the Nodes and the Link become not discoverable for endpoint FindNodesAndLinks. Also, the Link can not be found using the FindLinks endpoint.

From these two examples we can see that behaviour of endpoints that use Traversal Queries (such as FindNodesAndLinks) is different from behaviour of the other endpoints (for example FindLinks).

The reason of this deference is the endpoints in the Data Management API that use Traversal Queries always look for the most recent revision of elements. Also, a Traversal Query will match Node->Link->Node sequence, not a single element. If the last version of any elements in the sequence marked as deleted then the whole sequence Node->Link->Node will be omitted from the output.