SQL - TRAVERSE

Retrieves connected records crossing relationships. This works with both the Document and Graph API’s, meaning that you can traverse relationships between say invoices and customers on a graph, without the need to model the domain using the Graph API.

Traverse - 图1 In many cases, you may find it more efficient to use SELECT, which can result in shorter and faster queries. For more information, see TRAVERSE versus SELECT below.

Syntax

  1. TRAVERSE <[class.]field>|*|any()|all()
  2. [FROM <target>]
  3. [MAXDEPTH <number>]
  4. WHILE <condition>
  5. [LIMIT <max-records>]
  6. [STRATEGY <strategy>]
  • <fields> Defines the fields you want to traverse.
  • <target> Defines the target you want to traverse. This can be a class, one or more clusters, a single Record ID, set of Record ID’s, or a sub-query.
  • MAXDEPTH Defines the maximum depth of the traversal. 0 indicates that you only want to traverse the root node. Negative values are invalid.
  • WHILE Defines the condition for continuing the traversal while it is true.
  • LIMIT Defines the maximum number of results the command can return.
  • STRATEGY Defines strategy for traversing the graph.

NOTE: The use of the WHERE clause has been deprecated for this command.

Examples

In a social network-like domain, a user profile is connected to friends through links. The following examples consider common operations on a user with the record ID #10:1234.

  • Traverse all fields in the root record:

    1. orientdb> TRAVERSE * FROM #10:1234
  • Specify fields and depth up to the htird level, using the BREADTH_FIRST strategy:

    1. orientdb> TRAVERSE out("Friend") FROM #10:1234 WHILE $depth <= 3
    2. STRATEGY BREADTH_FIRST
  • Execute the same command, this time filtering for a minimum depth to exclude the first target vertex:

    1. orientdb> SELECT FROM (TRAVERSE out("Friend") FROM #10:1234 WHILE $depth <= 3)
    2. WHERE $depth >= 1

    NOTE: You can also define the maximum depth in the SELECT command, but it’s much more efficient to set it at the inner TRAVERSE statement because the returning record sets are already filtered by depth.

  • Combine traversal with SELECT command to filter the result-set. Repeat the above example, filtering for users in Rome:

    1. orientdb> SELECT FROM (TRAVERSE out("Friend") FROM #10:1234 WHILE $depth <= 3)
    2. WHERE city = 'Rome'
  • Extract movies of actors that have worked, at least once, in any movie produced by J.J. Abrams:

    1. orientdb> SELECT FROM (TRAVERSE out("Actors"), out("Movies") FROM (SELECT FROM
    2. Movie WHERE producer = "J.J. Abrams") WHILE $depth <= 3) WHERE
    3. @class = 'Movie'
  • Display the current path in the traversal:

    1. orientdb> SELECT $path FROM ( TRAVERSE out() FROM V WHILE $depth <= 10 )

Supported Variables

Fields

Defines the fields that you want to traverse. If set to *, any() or all() then it traverses all fields. This can prove costly to performance and resource usage, so it is recommended that you optimize the command to only traverse the pertinent fields.

In addition tot his, you can specify the fields at a class-level. Polymorphism is supported. By specifying Person.city and the class Customer extends person, you also traverse fields in Customer.

Field names are case-sensitive, classes not.

Target

Targets for traversal can be,

  • <class> Defines the class that you want to traverse.
  • CLUSTER:<cluster> Defines the cluster you want to traverse.
  • <record-id> Individual root Record ID that you want to traverse.
  • [<record-id>,<record-id>,...] Set of Record ID’s that you want to traverse. This is useful when navigating graphs starting from the same root nodes.

Context Variables

In addition to the above, you can use the following context variables in traversals:

  • $parent Gives the parent context, if any. You may find this useful when traversing from a sub-query.
  • $current Gives the current record in the iteration. To get the upper-level record in nested queries, you can use $parent.$current.
  • $depth Gives the current depth of nesting.
  • $path Gives a string representation of the current path. For instance, #5:0#.out. You can also display it through SELECT:
    1. orientdb> SELECT $path FROM (TRAVERSE ** FROM V)
  • $stack Gives a list of operations in the stack. Use it to access the traversal history. It’s a List<OTraverseAbstractProcess<?>>, where the process implementations are:
    • OTraverseRecordSetProcess The base target of traversal, usually the first given.
    • OTraverseRecordProcess The traversed record.
    • OTraverseFieldProcess The traversal through the record’s fields.
    • OTraverseMultiValueProcess Use on fields that are multivalue, such as arrays, collections and maps.
  • $history Gives a set of records traversed as SET<ORID>.

Use Cases

TRAVERSE versus SELECT

When you already know traversal information, such as relationship names and depth-level, consider using SELECT instead of TRAVERSE as it is faster in some cases.

For example, this query traverses the follow relationship on Twitter accounts, getting the second level of friendship:

  1. orientdb> SELECT FROM (TRAVERSE out('follow') FROM TwitterAccounts WHILE
  2. $depth <= 2) WHERE $depth = 2

But, you could also express this same query using SELECT operation, in a way that is also shorter and faster:

  1. orientdb> SELECT out('follow').out('follow') FROM TwitterAccounts

TRAVERSE with the Graph Model and API

While you can use the TRAVERSE command with any domain model, it provides the greatest utility in [Graph Databases[(Graph-Database-Tinkerpop.md) model.

This model is based on the concepts of the Vertex (or Node) as the class V and the Edge (or Arc, Connection, Link, etc.) as the class E. If you want to traverse in a direction, you have to use the class name when declaring the traversing fields. The supported directions are:

  • Vertex to outgoing edges Using outE() or outE('EdgeClassName'). That is, going out from a vertex and into the outgoing edges.
  • Vertex to incoming edges Using inE() or inE('EdgeClassName'). That is, going from a vertex and into the incoming edges.
  • Vertex to all edges Using bothE() or bothE('EdgeClassName'). That is, going from a vertex and into all the connected edges.
  • Edge to Vertex (end point) Using inV() . That is, going out from an edge and into a vertex.
  • Edge to Vertex (starting point) Using outV() . That is, going back from an edge and into a vertex.
  • Edge to Vertex (both sizes) Using bothV() . That is, going from an edge and into connected vertices.
  • Vertex to Vertex (outgoing edges) Using out() or out('EdgeClassName'). This is the same as outE().inV()
  • Vertex to Vertex (incoming edges) Using in() or in('EdgeClassName'). This is the same as outE().inV()
  • Vertex to Vertex (all directions) Using both() or both('EdgeClassName').

For instance, traversing outgoing edges on the record #10:3434:

  1. orientdb> TRAVERSE out() FROM #10:3434

In a domain for emails, to find all messages sent on January 1, 2012 from the user Luca, assuming that they are stored in the vertex class User and that the messages are contained in the vertex class Message. Sent messages are stored as out connections on the edge class SentMessage:

  1. orientdb> SELECT FROM (TRAVERSE outE(), inV() FROM (SELECT FROM User WHERE
  2. name = 'Luca') WHILE $depth <= 2 AND (@class = 'Message' or
  3. (@class = 'SentMessage' AND sentOn = '01/01/2012') )) WHERE
  4. @class = 'Message'

Deprecated TRAVERSE Operator

Before the introduction of the TRAVERSE command, OrientDB featured a TRAVERSE operator, which worked in a different manner and was applied to the WHERE condition.

More recent releases deprecated this operator. It is recommended that you transition to the TRAVERSE command with SELECT queries to utilize more power.

The deprecated syntax for the TRAVERSE operator looks like this:

Traverse - 图2 WARNING: Beginning in version 2.1, OrientDB no longer supports this syntax.

Syntax

  1. SELECT FROM <target> WHERE <field> TRAVERSE[(<minDeep> [,<maxDeep> [,<fields>]])] (<conditions>)
  • <target> Defines the query target.
  • <field> Defines the field to traverse. Supported fields are,
    • out Gives outgoing edges.
    • in Gives incoming edges.
    • any() Any field, including in and out.
    • all() All fields, including in and out.
    • Any attribute of the vertex.
  • minDeep Defines the minimum depth-level to begin applying the conditions. This is usually 0 for the root vertex, or 1 for only the outgoing vertices.
  • maxDeep Defines the maximum depth-level to read. Default is -1, for infinite depth.
  • [<field>, <field>,...] Defines a list of fields to traverse. Default is any().
  • <conditions> Defines conditions to check on any traversed vertex.

For more information, see SQL syntax.

Examples

  • Find all vertices that have at least one friend, (connected through out), up to the third depth, that lives in Rome:

    1. orientdb> SELECT FROM Profile WHERE any() TRAVERSE(0,3) (city = 'Rome')
  • Alternatively, you can write the above as:

    1. orientdb> SELECT FROM Profile LET $temp = (SELECT FROM (TRAVERSE * FROM $current
    2. WHILE $depth <= 3) WHERE city = 'Rome') WHERE $temp.size() > 0
  • Consider an example using the Graph Query, with the following schema:

    1. Vertex edge Vertex
    2. User----->Friends----->User
    3. Label='f'
  • Find the first-level friends of the user with the Record ID #10:11:

    1. orientdb> SELECT DISTINCT(in.lid) AS lid,distinct(in.fid) AS fid FROM
    2. (TRAVERSE outE(), inV() FROM #10:11 WHILE $depth <=1) WHERE
    3. @class = 'Friends'
  • By changing the depth to 3, you can find the second-level friends of the user:

    1. orientdb> SELECT distinct(in.lid) AS lid, distinct(in.fid) AS fid FROM
    2. (TRAVERSE outE(), inV() FROM #10:11 WHILE $depth <=3) WHERE
    3. @class = 'Friends'

For more information, see