Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Neo4j: Traversal Query Timeout

DZone's Guide to

Neo4j: Traversal Query Timeout

In this post, we take a look at a possible solution for handling long-running traversal queries in Neo4j that just plain take too long!

· Database Zone
Free Resource

Learn how to create flexible schemas in a relational database using SQL for JSON.

I’ve been spending some of my spare time over the last few weeks creating an application that generates running routes from Open Roads data — transformed and imported into Neo4j, of course!

I’ve created a user-defined procedure that combines several shortest path queries, but I wanted to exit any of these shortest path searches if they were taking too long. My code without a timeout looks like this:

StandardExpander orderedExpander = new OrderedByTypeExpander()
    .add( RelationshipType.withName( "CONNECTS" ), Direction.BOTH );

PathFinder<Path> shortestPathFinder = GraphAlgoFactory.shortestPath( expander, 250 );

...

There are several places where we could check the time elapsed, but the expand method in the Expander seemed like an obvious one to me. I wrote my own Expander class, which looks like this:

public class TimeConstrainedExpander implements PathExpander
{
    private final StandardExpander expander;
    private final long startTime;
    private final Clock clock;
    private int pathsExpanded = 0;
    private long timeLimitInMillis;

    public TimeConstrainedExpander( StandardExpander expander, Clock clock, long timeLimitInMillis )
    {
        this.expander = expander;
        this.clock = clock;
        this.startTime = clock.instant().toEpochMilli();
        this.timeLimitInMillis = timeLimitInMillis;
    }

    @Override
    public Iterable<Relationship> expand( Path path, BranchState state )
    {
        long timeSoFar = clock.instant().toEpochMilli() - startTime;
        if ( timeSoFar > timeLimitInMillis )
        {
            return Collections.emptyList();
        }

        return expander.expand( path, state );
    }

    @Override
    public PathExpander reverse()
    {
        return expander.reverse();
    }
}

The code snippet from earlier now needs to be updated to use our new class, which isn’t too tricky:

StandardExpander orderedExpander = new OrderedByTypeExpander()
    .add( RelationshipType.withName( "CONNECTS" ), Direction.BOTH );

TimeConstrainedExpander expander = new TimeConstrainedExpander(orderedExpander, 
    Clock.systemUTC(), 200);

PathFinder<Path> shortestPathFinder = GraphAlgoFactory.shortestPath( expander, 250 );
...

I’m not sure if this is the best way to achieve what I want, but after failing with several other approaches, at least this one actually works!

Create flexible schemas using dynamic columns for semi-structured data. Learn how.

Topics:
database ,tutorial ,neo4j ,traversal ,query ,timeout

Published at DZone with permission of Mark Needham, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}