Traversal Framework: Working with ResourceIterables

So the Traversal Framework is here to stay but there are some changes. Is this the first post about it since it was announced that it was staying?

I've been upgrading some plugins I have to Neo4j 5.5 and I've hit an issue. One of the changes to the Traversal Framework is the interface for PathExpander:

public interface PathExpander<STATE> {
 
    ResourceIterable<Relationship> expand(Path path, BranchState<STATE> state);

    PathExpander<STATE> reverse();
}

For expand you must return a ResourceIterable, rather than a standard java Iterable.

The issue I have is that all the implementations I can find of ResourceIterable in the Neo4j codebase seem to either be part of the unpublished internal API, or are implemented in private classes. In my code I have previously been filtering the results from path.endNode().getRelationships() and only returning a subset from my expand() implementation I can't get this to work now, since I can't cast/convert the HashSets that I was using to ResourceIterables. Am I missing something? What is the right approach for doing this now.

Here is a simplified version of the code I'm working with:

@Override
public ResourceIterable<Relationship> expand(Path path, BranchState<TraverseState> bState)
{
	TraverseState state = state.getState();

	assert path.endNode().hasLabel(Labels.Undefined);

	var concludes = path.endNode().getRelationships(Direction.OUTGOING, RelationshipTypes.CONCLUDES);
	var expansion = new HashSet<Relationship>();

	for(Relationship rel : concludes)
	{
		if(!state.traverseOnce.contains(rel))
		{
			expansion.add(rel);
			state.traverseOnce.add(rel);
		}
	}

	if(expansion.size() > 0)
		return expansion;
	
	return Collections.emptyList();
}

For this code I get errors for both return statements because they're returning Iterables. If I try casting them, then I get runtime errors as the cast fails. Has anyone been working with this yet and have a solution?

I am still using version 4 of the API. In it I found:

org.neo4j.internal.helpers.collection.Iterables

It has a static method that looks to convert Iterable into a ResourceIterable

public static ResourceIterable asResourceIterable( final Iterable iterable )

Thanks. I had found some of these internal helpers, and this one seems to be precisely what I'm missing.

I'd rather not use the undocumented internal API, but it doesn't look like there's a nice way of avoiding that. I could create my own implementation of ResourceIterable, ResourceIterator and a few other classes, which seems heavy-handed for a simple filtering use case such as mine.

I'll probably open up an issue on GitHub for this; it's a missing feature for anyone using the updated Traversal Framework, as far as I can see.

As far as I can see this is still an issue in 5.15, so I've finally got around to opening an issue.

For anyone else who goes down this rabbit hole, here is the issue Traversal Framework: No public method for creating ResourceIterable · Issue #13396 · neo4j/neo4j · GitHub

There seems to be a disconnect with the documentation and the actual code. Here is a screenshot from the Java API 5.16 documentation. It shows an example of a custom PathExpander. Notice the return type of the expand method.

I updated a project to 5.16 to see what would be the methods to override if I created a class the implemented PathExpander. It required ResourceIterable, not Iterable as shown in the screenshot.

Thanks, I hadn't noticed that. So they're doing almost exactly what I'm trying to do....but their code would never work.

I've updated the ticket and I was also just talking to some of their team on a call about another thing and called this out.

1 Like