User Community Service Desk Downloads
If you can't find the product or version you're looking for, visit support.ataccama.com/downloads

Using Generic Traversal Master Service

genericTraversalMasterService is the most powerful native RO service. It allows retrieving multiple entities connected by relations and traversing the data in the master model. For every master view Mv, there is one service genericMvTraversal.

The basic use case of the service is retrieving one record from a master entity identified by id or a combination of origin and sourceId.

There are two advanced features:

  • Traversing: Allows changing the starting point for the entities preloaded in the model, that is, which record to return as the root element of the response.

  • Preloading: Allows preloading records connected to the current record by a relationship (simulates joins).

Data model

The following examples are done using the MDM Example Project, working with its data and model:

Master Layer Model

When traversing or preloading, use parent and child roles for relationship names instead of technical names of relationships (the Name field in the figure below), for example, <traverse relationshipName="addresses" /> or <rel name="addresses">. Parent and child roles are defined in the relationship configuration as seen in the example.

If you have no roles defined in relationships, you have to use the value in the Name attribute (<name>) or rev_<name> for relationships going from a child to a parent. For example, <traverse relationshipName="party_has_address" /> or <traverse relationshipName="rev_party_has_address" />.

Relationship Configuration in the Master Layer Model

Basic usage

The simplest usage is similar to getMasterByIdService - specify the entity name and record ID in the request (internal MDM primary key):

Request by record id
<request>
  <startWith entity="party" id="38" />
</request>

The response contains one party record:

Response
<list>
  <party>
    <metadata>
      <id>38</id>
      <active>true</active>
      <creationTid>1002</creationTid>
      <lastUpdateTid>1002</lastUpdateTid>
      <creationDate>2014-09-02T12:47:59+02:00</creationDate>
      <lastUpdateDate>2014-09-02T12:47:59+02:00</lastUpdateDate>
    </metadata>
    <attributes>
      <cmo_type>P</cmo_type>
      <cmo_first_name>Smith</cmo_first_name>
      <cmo_last_name>John</cmo_last_name>
      <cmo_gender>M</cmo_gender>
      <cmo_birth_date>1978-12-16T00:00:00+01:00</cmo_birth_date>
      <cmo_sin>095242434</cmo_sin>
    </attributes>
    <relationships/>
  </party>
</list>

The master record to retrieve is identified either by ID (as in the previous example) or by a combination of the instance record sourceId and origin:

Request by instance record source id and origin
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />

</request>

NME automatically finds the instance record and its master record. The response is the same.

Simple traversing

genericTraversalMasterService allows traversing from the starting point to other entities over relationships defined in the master model, for example, you want to retrieve addresses related to a given party:

Request with traversal
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <traversal>
    <traverse relationshipName="addresses" />
  </traversal>
</request>

The response is a list of addresses:

Response
<list>
  <address>
    <metadata>
      ...
    </metadata>
    <attributes>
      <party_master_id>38</party_master_id>
      <cmo_type>R</cmo_type>
      <cmo_street>13-3295 Sunnyside</cmo_street>
      <cmo_state>BC</cmo_state>
      <cmo_zip>V3H4Z4</cmo_zip>
    </attributes>
    <relationships/>
  </address>
  <address>
    <metadata>
      ...
    </metadata>
    <attributes>
      <party_master_id>38</party_master_id>
      <cmo_type>M</cmo_type>
      <cmo_street>80 Hemlock Dr</cmo_street>
      <cmo_city>Anmore</cmo_city>
      <cmo_state>BC</cmo_state>
      <cmo_zip>V3H4W9</cmo_zip>
    </attributes>
    <relationships/>
  </address>
</list>

Traversing with a simple filter

Traversing over relationships can be enhanced by a filter. For example, if you want to see only addresses of type M, add a filter element with the eq subelement:

Request with filtered traversal
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <traversal>
    <traverse relationshipName="addresses">
      <filter>
        <eq attribute="cmo_type" value="M" />
      </filter>
    </traverse>
  </traversal>
</request>

The response is only one address:

Response
<list>
  <address>
    <metadata>
      ...
    </metadata>
    <attributes>
      <party_master_id>38</party_master_id>
      <cmo_type>M</cmo_type>
      <cmo_street>80 Hemlock Dr</cmo_street>
      <cmo_city>Anmore</cmo_city>
      <cmo_state>BC</cmo_state>
      <cmo_zip>V3H4W9</cmo_zip>
    </attributes>
    <relationships/>
  </address>
</list>

Traversing with an advanced filter

Traversing filter can have more advanced conditions. For example, if you want only addresses that have good quality address instances:

Request with filtered traversal
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <traversal>
    <traverse relationshipName="addresses">
      <filter>
        <exists>
          <traverse relationshipName="instances">   <!-- virtual traverse to address_instance records -->
            <filter>
              <eq attribute="sco_address" value="0" />  <!-- good quality means score is 0 -->
            </filter>
          </traverse>
        </exists>
      </filter>
    </traverse>
  </traversal>
</request>

This request can be translated as:

  • Get the party record with sourceId = 1002 and origin = crm#customer#party.

  • Traverse over the addresses relationship.

    • Filter records: Allow only those for which there is a related instance address record that has sco_address equal to zero.

This example shows that a filter defined by an exists condition can be recursive: depth is not limited. However, every step of recursion decreases the performance of the service.

The filter element can contain multiple eq and exists subelements. Those are evaluated by default as AND, that is, all conditions must be met to return a record. You can change this to OR by setting up an operator attribute on the filter element:

Request with filtered traversal
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <traversal>
    <traverse relationshipName="addresses">
      <filter operator="OR">
        <eq attribute="cmo_type" value="M" />
        <eq attribute="cmo_type" value="R" />
      </filter>
    </traverse>
  </traversal>
</request>

Chained traverse

Traversing over relationships can be chained, that is, multiple traverse elements can define a long path from the starting point to the destination entity. For example, if you want to get all parties related to input party records:

Request with multiple traversals
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <traversal>
    <traverse relationshipName="relparent" />   <!-- traverse to associative entity rel_party_party -->
    <traverse relationshipName="child" />     <!-- traverse back to party -->
  </traversal>
</request>

Each traverse element can have its own complex filter as described previously.

The second advanced feature of genericTraversalMasterService is the ability to return not only records of one entity but related records as well. For example, if you want a party record with all addresses:

Request with preloaded relationships
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <preloadedRelationships>
    <rel name="addresses" />
  </preloadedRelationships>
</request>

The response is a complex hierarchical XML:

Response
<list>
  <party>
    <metadata>
      ...
    </metadata>
    <attributes>        <!-- party record attributes -->
      <cmo_type>P</cmo_type>
      <cmo_first_name>Smith</cmo_first_name>
      <cmo_last_name>John</cmo_last_name>
      <cmo_gender>M</cmo_gender>
      <cmo_birth_date>1978-12-16T00:00:00+01:00</cmo_birth_date>
      <cmo_sin>095242434</cmo_sin>
    </attributes>
    <relationships>
    <addresses>         <!-- address records -->
      <address>
        <metadata>
        ...
        </metadata>
        <attributes>
          <party_master_id>38</party_master_id>
          <cmo_type>R</cmo_type>
          <cmo_street>13-3295 Sunnyside</cmo_street>
          <cmo_state>BC</cmo_state>
          <cmo_zip>V3H4Z4</cmo_zip>
        </attributes>
        <relationships/>
      </address>
      <address>
        <metadata>
        ...
        </metadata>
        <attributes>
          <party_master_id>38</party_master_id>
          <cmo_type>M</cmo_type>
          <cmo_street>80 Hemlock Dr</cmo_street>
          <cmo_city>Anmore</cmo_city>
          <cmo_state>BC</cmo_state>
          <cmo_zip>V3H4W9</cmo_zip>
        </attributes>
        <relationships/>
        </address>
      </addresses>
    </relationships>
  </party>
</list>

When preloading related records, you can apply a filter so that only some records are returned. For example, if you want a party record with all addresses of type M:

Request with advanced preloaded relationships
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <preloadedRelationships>
    <rel name="addresses">
      <filter>
        <eq attribute="cmo_type" value="M" />
      </filter>
    </rel>
  </preloadedRelationships>
</request>

The response contains a party record with one address:

Response
<list>
  <party>
    <metadata>
    ...
    </metadata>
    <attributes>
      <cmo_type>P</cmo_type>
      <cmo_first_name>Smith</cmo_first_name>
      <cmo_last_name>John</cmo_last_name>
      <cmo_gender>M</cmo_gender>
      <cmo_birth_date>1978-12-16T00:00:00+01:00</cmo_birth_date>
      <cmo_sin>095242434</cmo_sin>
    </attributes>
    <relationships>
      <addresses>
        <address>
          <metadata>
            ...
          </metadata>
          <attributes>
            <party_master_id>38</party_master_id>
            <cmo_type>M</cmo_type>
            <cmo_street>80 Hemlock Dr</cmo_street>
            <cmo_city>Anmore</cmo_city>
            <cmo_state>BC</cmo_state>
            <cmo_zip>V3H4W9</cmo_zip>
          </attributes>
          <relationships/>
        </address>
      </addresses>
    </relationships>
  </party>
</list>

There are several more possibilities:

  • Specifying a more complex filter: Several eq and exists subelements.

  • Preloading multiple relationships: For example, a party record with all related addresses and contacts.

  • Preloading records related to related records: For example, a party record with related addresses and address instances or a party record with all related parties (jump over the associative entity rel_party_party). This scenario is described in the following section.

Let’s assume you want to retrieve a party record with all related parties:

Request with advanced preloaded relationships 2
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1002" />
  <preloadedRelationships>
    <rel name="relparent/child" />
  </preloadedRelationships>
</request>
Note the definition of preloadedRelationships: relparent/child. If you want to preload records related over several relationships, you have to concatenate relationship names with the slash '/'. This forces the service to jump over two relationships to get to records.

If you specify a filter for this preloaded relationship, it is applied to records of the last entity, that is, party in this example. If you want to specify a filter to be applied to the first entity (that is, associative entity rel_party_party in this example), you have to add that entity to preloadedRelationships:

Request with advanced preloaded relationships 3
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1018" />
  <preloadedRelationships>
    <rel name="relparent">
      <filter>      <!-- filter on associative entity rel_party_party -->
        <eq attribute="cmo_p2p_rel_type" value="FAMILY" />
      </filter>
    </rel>
    <rel name="relparent/child">
      <filter>      <!-- filter on related party entity -->
        <eq attribute="cmo_gender" value="M" />
      </filter>
    </rel>
  </preloadedRelationships>
</request>

The response is an even more complex hierarchical XML:

Response
<list>
  <party>
    <metadata>
      ...
    </metadata>
    <attributes>                <!-- party attributes -->
      <cmo_type>P</cmo_type>
      <cmo_first_name>Sandy</cmo_first_name>
      <cmo_last_name>Hettinger</cmo_last_name>
      <cmo_gender>F</cmo_gender>
      <cmo_birth_date>1965-09-21T00:00:00+01:00</cmo_birth_date>
      <cmo_sin>856527270</cmo_sin>
    </attributes>
    <relationships>
      <relparent>
        <rel_party_party>
            <metadata>
              ...
            </metadata>
              <attributes>      <!-- party2party relation attributes -->
              <parent_id>29</parent_id>
              <child_id>31</child_id>
              <cmo_p2p_rel_type>FAMILY</cmo_p2p_rel_type>
            </attributes>
          <relationships>
            <child>
              <party>
                <metadata>
                  ...
                </metadata>
                <attributes>    <!-- attributes of related party -->
                  <cmo_type>P</cmo_type>
                  <cmo_first_name>Tom</cmo_first_name>
                  <cmo_last_name>Donathan</cmo_last_name>
                  <cmo_gender>M</cmo_gender>
                  <cmo_birth_date>1966-02-04T00:00:00+01:00</cmo_birth_date>
                  <cmo_sin>961085248</cmo_sin>
                </attributes>
                <relationships/>
              </party>
            </child>
          </relationships>
        </rel_party_party>
      </relparent>
    </relationships>
  </party>
</list>

Complex example

Imagine you have party sourceId as an input, and you want to get:

  • All 'family' related party records representing males

    • But only those with good data quality email addresses

    • And only those living in the city of Anmore

  • Also return this party’s email addresses that have good data quality and their addresses.

In other words: "We want to email every man in Ohio this party is related to as family."

Advanced request
<request>
  <startWith entity="party" origin="crm#customer#party" sourceId="1018" />
  <traversal>
    <traverse relationshipName="relparent">
      <filter>
        <eq attribute="cmo_p2p_rel_type" value="FAMILY" />
      </filter>
    </traverse>
    <traverse relationshipName="child">
      <filter>
        <eq attribute="cmo_gender" value="M" />
        <exists>
          <traverse relationshipName="contacts">
            <filter>
              <eq attribute="cmo_type" value="email" />
              <exists>
                <traverse relationshipName="instances">
                  <filter>
                    <eq attribute="sco_value" value="0" />
                  </filter>
                </traverse>
              </exists>
            </filter>
          </traverse>
        </exists>
        <exists>
          <traverse relationshipName="addresses">
            <filter>
              <eq attrbitue="cmo_city" value="Anmore" />
            </filter>
          </traverse>
        </exists>
      </filter>
    </traverse>
  </traversal>
  <preloadedRelationships>
    <rel name="contacts">
      <filter>
        <eq attribute="cmo_type" value="email" />
        <exists>
          <traverse relationshipName="instances">
            <filter>
              <eq attribute="sco_value" value="0" />
            </filter>
          </traverse>
        </exists>
      </filter>
    </rel>
    <rel name="contacts/instances" />
    <rel name="addresses" />
  </preloadedRelationships>
</request>

The service does a lot of work:

  1. Get the party instance record by its sourceId and origin.

  2. Get the master record for this instance.

  3. Get all relations of this record of type FAMILY.

  4. Get all party records from those relations.

  5. Filter those party records:

    1. cmo_gender is 'M'.

    2. Get all related address records and check there is at least one with cmo_city equal to 'Anmore'.

    3. Get all related contact records and filter only those of type 'email'.

      1. Then get all related instance records and check whether sco_value equals to zero.

    4. Check that at least one contact record satisfied the previous conditions.

  6. For every party record that was not filtered out, preload related records:

    1. Get all related contact records of type 'email'.

      1. Get all related contact instance records that have sco_value equal to zero.

    2. Get all related address records.

As we can see, genericTraverseMasterService is very powerful and can create quite complex queries on master data. However, keep in mind that complex queries require corresponding HW resources for both the MDM engine and underlying database storage. This particular example will execute about 10 SQL queries just for one call.

Was this page useful?