Skip to content

Introduction

Gremlin Query Debugging is a functionality available as part of the Query Editor that allows inspecting the behaviour of your queries and their output in more details. There are multiple features within debugging with various degrees of complexity. This section will explain each in detail.

TIP

Gremlin Query Debugging is a concept unique to G.V() and with no standard definition in the Apache TinkerPop framework. It is compatible with all server technologies and versions that G.V() supports. However, it is a complex feature for a complex language (Gremlin), so there are instances of queries and graphs that cannot be debugged using all the functionality described in this page. Some scenarios of queries that cannot be debugged are described in this documentation but this may not cover all of them.

Definitions

  • Root Traversal: the set of steps that are not contained within any other step (i.e. steps that are not in a sub-traversal)
  • Sub traversal: a set of steps contained within another step.

Starting a Debugging Session

Requirements

Debugging cannot be run on all queries. There are few requirements:

  • The query's syntax must be valid. If there is any syntax error, debugging will not be available
  • Debugging is not available for queries that mutate the graph (e.g. queries containing addE, addV, property, mergeE, mergeV)

How to

From the Query Editor, you can start debugging by pressing "F5" or clicking on Start Debug. To stop debugging, press "F5" again or click on Stop Debug. Once debugging starts, you will be prompted to select a step to start debugging from. All steps in your code editor will become clickable. Clicking on a step will make it your current debugging step. You can navigate between steps in any direction. Additionally, you can use the following keyboard shortcuts whilst debugging is enabled:

  • Step Over (F10): Steps to the next available step in the current traversal. If there are no more steps available in the current traversal, the debugger will step to the next step in the parent traversal. If the traversal is the root traversal and there are no more next steps, debugging will end.
  • Step Back (F9): Steps back to the next available step in the current traversal. If there are no more steps available in the current traversal, the debugger will step to the parent traversal step. If the traversal is the root traversal, and there are no more previous steps, debugging will end.
  • Step Into (F11): If the current step has any sub-traversals, steps into the first step of the sub-traversal.
  • Step Out (F11): If the current step is within a sub-traversal, steps out into the parent step.

TIP

Whilst Debugging is active, the query editor will be in read only mode. You will need to stop debugging before editing your query.

What Happens When You Select A Step and Navigate Steps - A Concrete Example

Once a step is selected, G.V() will run the query up to the end of the selected step. Consider the following query:

g.V().
  hasId(lt(47)).
  outE().
  and(where(inV().id().is(lt(47))), values('dist').is(gt(4000))).
  inV().
  path()

If selecting the step hasId(lt(47)), G.V() will run the following query:

g.V().
  hasId(lt(47))

If I then Step Over (F10), G.V() will run the following query:

g.V().
  hasId(lt(47)).
  outE()

Pressing F10 again, G.V() will run the following query:

g.V().
  hasId(lt(47)).
  outE().
  and(where(inV().id().is(lt(47))), values('dist').is(gt(4000)))

At this point, the and step has a sub-traversal available, and the ability to Step Into will become available. By stepping into, the active step will become where(inV().id().is(lt(47))) and run the following query:

g.V().
  hasId(lt(47)).
  outE().
  and(where(inV().id().is(lt(47))))

The where step has its own sub-traversal, meaning we can Step Into again to inV, which will run the following query:

g.V().
  hasId(lt(47)).
  outE().
  and(where(inV()))

For a full navigation of the query using the options above, see the animation below:

Step Navigation

Traversal Simulation

Introduction

Traversal Simulation is a screen available under the Query Output that is generated based on the selected step for debugging. It performs a simple projection of the elements output at the current step to their output (if any) at the end of the query. In G.V(), this projection of individual query input to output is called a traverser. The Traversal Simulation reports on two aspects of your query at the current step:

  • Which elements coming out of the current step are yielding a result at the end of the query?
  • For elements that yield a result at the end of the query, what is the output?

Requirements

The Traversal Simulation cannot be generated for every step of the query. For instance, it does not make sense to offer a traversal simulation for the last step of the query, as the output of traversers would be the same as the input. Additionally, there are a number of steps for which this Traversal Simulation cannot be generated:

  • the by() step
  • the project() step
  • the group() step
  • the groupCount() step

Example

Consider this simple example query: g.V().hasLabel("person").where(values("name").is(eq("marko")))

For this simple graph:

Graph Sample

At the g.V() step, the output of the query will be all vertices in the graph. The traversal simulation will look as follows:

Traversal Simulation Example

On the left handside of the screen are the "traversers", which is the elements output at the selected step, g.V(). In this case, there are 6 vertices in the graph and there will therefore be 6 traversers. On the right handside of the screen at the summary tab is the output of the selected traverser, v[1] - person. v[1] - person is the vertex in the graph representing "marko" and has a property "name" with that value. It is returning a successful output indicated by a green tick as v[1] is a vertex with label "person" and a "name" property value that equals "marko", as shown in the query above. v[10] - software however displays a red cross indicating that the traverser failed to output a result at the end of the query. This is expected as v[10] - software does not have a "label" value of "person".

If I progress debugging to the next step, g.V().hasLabel("person"), the traversal simulation looks as follows:

Traversal Simulation Example 2

On the left handside of the screen are the traversers again, this time all vertices with label "person" as the query up to the selected step outputs all vertices with label "person". On the right handside of the screen is the result of the traversal for v[7] - person, which shows as failing. v[7] - person has a property "name" with value "stephen" that does not match the requirements of the query, hence the failure.

Usage

  • The Traversal Simulation lists all traversers on the left handside. To inspect a traverser, simply click on it.
  • The Traversal Simulation lists 50 traversers per page.
  • For performance reasons, the Traversal Simulation will load up to 1000 traversers by default. If there are more than 1000 Traversers available for the query, an option to load the next 1000 will be available under the pagination.
  • To hide/show failed traversals, check/uncheck the Hide Failed Traversals checkbox.

Traverser Summary

The Traverser Summary has two sections:

  • Traversal Input: The traversal input displays details for the element (vertex, edge, property, etc) being traversed and allows looking at its details more closely
  • Traversal Output: The traversal output displays the element(s) (vertex, edge, property, etc) coming out of the traverser through the query, if successful. Note: The traversal output is limited to displaying the first 1000 elements output by the traverser for performance reasons.

Traverser Inspection

The Traverser Inspection allows executing the query's steps one by one for the element to better understand how each step behaves, and where the traverser may eventually fail. The Traverser Inspection displays the query up until the selected step, followed by a list of all upcoming steps in the query. For steps that have sub-traversals, the Traverser Inspection also allows running step individually, in a manner similar to the one described at Starting a Debugging Session.

Each displayed step can be run individually by clicking Play Button. Doing so will trigger the query up to the step for the inspected element. If the query succeeds, the output will display under the step and can be navigated similar to the Traverser Summary. If it fails, the step will be flagged as "Failed Traversal". A step flagged as "Failed Traversal" indicates that the element failed to meet the criteria of the query at that point. For troubleshooting purposes you could consider this where the query "stops working" for your element.

WARNING

There are rare situations in which the traversal may fail due to a query syntax or processing error. In this case, a clear error message indicate how the query failed will be displayed. In such event, this could mean the query is not suitable to be ran at this step without its next step. Should that be the case, you should run the query up to the next step to continue the traverser inspection. A very common example of this situation is for queries using the repeat() step. If the query is run up to a repeat step without the use of the until or emit step, it may loop infinitely until it times out.

Traverser Inspection Example

In this example, we inspect the following query at the hasId(lt(47)) step:

g.V().
  hasId(lt(47)).
  outE().
  and(where(inV().id().is(lt(47))), values('dist').is(gt(4000))).
  inV().
  path()

In a literal sense, the query looks for the "routes longer than 4,000 miles between airports with an ID less than 47", then outputs the path to the target airport. In a graph sense, we are looking for edges with a "dist" property value greater than 4000 and with an in and out vertex id lower than 47. In the animation below, we use the Traverser Inspection to identify the exact step at which a given Airport, v[2], fails during this query:

Traverser Inspection

We can see that the traverser fails at step and(where(inV().id().is(lt(47))), values('dist').is(gt(4000))) Furthermore when running through the individual steps within the and step, we identify that where(inV().id().is(lt(47)) is successful, but values('dist').is(gt(4000)) fails. Running values('dist') individually works. This makes sense - and(where(inV().id().is(lt(47))), values('dist')) will be successful for any edge that has an in vertex id lower than 47 and a "dist" property. Running is(gt(4000)) however fails, and this is where the traverser fails: v[2] has no outgoing edges with an in vertex id lower than 47 and a "dist" property value greater than 4000.