org.neo4j.kernel.Traversal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-kernel Show documentation
Show all versions of neo4j-kernel Show documentation
Neo4j kernel is a lightweight, embedded Java database designed to
store data structured as graphs rather than tables. For more
information, see http://neo4j.org.
/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.kernel;
import java.util.Iterator;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Expander;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.PathExpander;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipExpander;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.traversal.BidirectionalTraversalDescription;
import org.neo4j.graphdb.traversal.BranchCollisionDetector;
import org.neo4j.graphdb.traversal.BranchOrderingPolicy;
import org.neo4j.graphdb.traversal.Evaluators;
import org.neo4j.graphdb.traversal.InitialStateFactory;
import org.neo4j.graphdb.traversal.SideSelectorPolicy;
import org.neo4j.graphdb.traversal.TraversalBranch;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.graphdb.traversal.UniquenessFactory;
import org.neo4j.kernel.impl.traversal.BidirectionalTraversalDescriptionImpl;
import org.neo4j.kernel.impl.traversal.FinalTraversalBranch;
import org.neo4j.kernel.impl.traversal.TraversalDescriptionImpl;
/**
* A factory for objects regarding traversal of the graph. F.ex. it has a
* method {@link #traversal()} for creating a new
* {@link TraversalDescription}, methods for creating new
* {@link TraversalBranch} instances and more.
*/
public class Traversal
{
/**
* Creates a new {@link TraversalDescription} with default value for
* everything so that it's OK to call
* {@link TraversalDescription#traverse(org.neo4j.graphdb.Node)} without
* modification. But it isn't a very useful traversal, instead you should
* add rules and behaviors to it before traversing.
*
* @return a new {@link TraversalDescription} with default values.
*/
public static TraversalDescription description()
{
return new TraversalDescriptionImpl();
}
/**
* More convenient name than {@link #description()} when using static imports.
* Does the same thing.
*
* @see #description()
*/
public static TraversalDescription traversal()
{
return new TraversalDescriptionImpl();
}
public static TraversalDescription traversal( UniquenessFactory uniqueness )
{
return new TraversalDescriptionImpl().uniqueness( uniqueness );
}
public static TraversalDescription traversal( UniquenessFactory uniqueness, Object optionalUniquenessParameter )
{
return new TraversalDescriptionImpl().uniqueness( uniqueness, optionalUniquenessParameter );
}
public static BidirectionalTraversalDescription bidirectionalTraversal()
{
return new BidirectionalTraversalDescriptionImpl();
}
/**
* {@link InitialStateFactory} which always returns the supplied {@code initialState}.
* @param initialState the initial state for a traversal branch.
* @return an {@link InitialStateFactory} which always will return the supplied
* {@code initialState}.
*/
public static InitialStateFactory initialState( final STATE initialState )
{
return new InitialStateFactory()
{
@Override
public STATE initialState( Path branch )
{
return initialState;
}
};
}
/**
* Creates a new {@link RelationshipExpander} which is set to expand
* relationships with {@code type} and {@code direction}.
*
* @param type the {@link RelationshipType} to expand.
* @param dir the {@link Direction} to expand.
* @return a new {@link RelationshipExpander}.
*/
public static Expander expanderForTypes( RelationshipType type,
Direction dir )
{
return StandardExpander.create( type, dir );
}
/**
* Creates a new {@link PathExpander} which is set to expand
* relationships with {@code type} and {@code direction}.
*
* @param type the {@link RelationshipType} to expand.
* @param dir the {@link Direction} to expand.
* @return a new {@link PathExpander}.
*/
@SuppressWarnings( "unchecked" )
public static PathExpander pathExpanderForTypes( RelationshipType type, Direction dir )
{
return StandardExpander.create( type, dir );
}
/**
* Creates a new {@link RelationshipExpander} which is set to expand
* relationships with {@code type} in any direction.
*
* @param type the {@link RelationshipType} to expand.
* @return a new {@link RelationshipExpander}.
*/
public static Expander expanderForTypes( RelationshipType type )
{
return StandardExpander.create( type, Direction.BOTH );
}
/**
* Creates a new {@link PathExpander} which is set to expand
* relationships with {@code type} in any direction.
*
* @param type the {@link RelationshipType} to expand.
* @return a new {@link PathExpander}.
*/
@SuppressWarnings( "unchecked" )
public static PathExpander pathExpanderForTypes( RelationshipType type )
{
return StandardExpander.create( type, Direction.BOTH );
}
/**
* Returns an empty {@link Expander} which, if not modified, will expand
* all relationships when asked to expand a {@link Node}. Criterias
* can be added to narrow the {@link Expansion}.
* @return an empty {@link Expander} which, if not modified, will expand
* all relationship for {@link Node}s.
*/
public static Expander emptyExpander()
{
return StandardExpander.DEFAULT; // TODO: should this be a PROPER empty?
}
/**
* Returns an empty {@link PathExpander} which, if not modified, will expand
* all relationships when asked to expand a {@link Node}. Criterias
* can be added to narrow the {@link Expansion}.
* @return an empty {@link PathExpander} which, if not modified, will expand
* all relationship for {@link Path}s.
*/
@SuppressWarnings( "unchecked" )
public static PathExpander emptyPathExpander()
{
return StandardExpander.DEFAULT; // TODO: should this be a PROPER empty?
}
/**
* Creates a new {@link RelationshipExpander} which is set to expand
* relationships with two different types and directions.
*
* @param type1 a {@link RelationshipType} to expand.
* @param dir1 a {@link Direction} to expand.
* @param type2 another {@link RelationshipType} to expand.
* @param dir2 another {@link Direction} to expand.
* @return a new {@link RelationshipExpander}.
*/
public static Expander expanderForTypes( RelationshipType type1,
Direction dir1, RelationshipType type2, Direction dir2 )
{
return StandardExpander.create( type1, dir1, type2, dir2 );
}
/**
* Creates a new {@link PathExpander} which is set to expand
* relationships with two different types and directions.
*
* @param type1 a {@link RelationshipType} to expand.
* @param dir1 a {@link Direction} to expand.
* @param type2 another {@link RelationshipType} to expand.
* @param dir2 another {@link Direction} to expand.
* @return a new {@link PathExpander}.
*/
@SuppressWarnings( "unchecked" )
public static PathExpander pathExpanderForTypes( RelationshipType type1,
Direction dir1, RelationshipType type2, Direction dir2 )
{
return StandardExpander.create( type1, dir1, type2, dir2 );
}
/**
* Creates a new {@link RelationshipExpander} which is set to expand
* relationships with multiple types and directions.
*
* @param type1 a {@link RelationshipType} to expand.
* @param dir1 a {@link Direction} to expand.
* @param type2 another {@link RelationshipType} to expand.
* @param dir2 another {@link Direction} to expand.
* @param more additional pairs or type/direction to expand.
* @return a new {@link RelationshipExpander}.
*/
public static Expander expanderForTypes( RelationshipType type1,
Direction dir1, RelationshipType type2, Direction dir2,
Object... more )
{
return StandardExpander.create( type1, dir1, type2, dir2, more );
}
/**
* Creates a new {@link PathExpander} which is set to expand
* relationships with multiple types and directions.
*
* @param type1 a {@link RelationshipType} to expand.
* @param dir1 a {@link Direction} to expand.
* @param type2 another {@link RelationshipType} to expand.
* @param dir2 another {@link Direction} to expand.
* @param more additional pairs or type/direction to expand.
* @return a new {@link PathExpander}.
*/
@SuppressWarnings( "unchecked" )
public static PathExpander pathExpanderForTypes( RelationshipType type1,
Direction dir1, RelationshipType type2, Direction dir2,
Object... more )
{
return StandardExpander.create( type1, dir1, type2, dir2, more );
}
/**
* Returns a {@link RelationshipExpander} which expands relationships
* of all types and directions.
* @return a relationship expander which expands all relationships.
*/
public static Expander expanderForAllTypes()
{
return expanderForAllTypes( Direction.BOTH );
}
/**
* Returns a {@link RelationshipExpander} which expands relationships
* of all types and directions.
* @return a relationship expander which expands all relationships.
*/
public static PathExpander pathExpanderForAllTypes()
{
return pathExpanderForAllTypes( Direction.BOTH );
}
/**
* Returns a {@link RelationshipExpander} which expands relationships
* of all types in the given {@code direction}.
* @return a relationship expander which expands all relationships in
* the given {@code direction}.
*/
public static Expander expanderForAllTypes( Direction direction )
{
return StandardExpander.create( direction );
}
/**
* Returns a {@link PathExpander} which expands relationships
* of all types in the given {@code direction}.
* @return a path expander which expands all relationships in
* the given {@code direction}.
*/
@SuppressWarnings( "unchecked" )
public static PathExpander pathExpanderForAllTypes( Direction direction )
{
return StandardExpander.create( direction );
}
public static Expander expander( PathExpander expander )
{
if ( expander instanceof Expander )
{
return (Expander) expander;
}
return StandardExpander.wrap( expander );
}
/**
* Returns a {@link RelationshipExpander} wrapped as an {@link Expander}.
* @param expander {@link RelationshipExpander} to wrap.
* @return a {@link RelationshipExpander} wrapped as an {@link Expander}.
*/
public static Expander expander( RelationshipExpander expander )
{
if ( expander instanceof Expander )
{
return (Expander) expander;
}
return StandardExpander.wrap( expander );
}
/**
* Combines two {@link TraversalBranch}s with a common
* {@link TraversalBranch#endNode() head node} in order to obtain an
* {@link TraversalBranch} representing a path from the start node of the
* source
{@link TraversalBranch} to the start node of the
* target
{@link TraversalBranch}. The resulting
* {@link TraversalBranch} will not
* {@link TraversalBranch#next(PathExpander, org.neo4j.graphdb.traversal.TraversalContext)
* ) expand further}, and does not provide a
* {@link TraversalBranch#parent() parent} {@link TraversalBranch}.
*
* @param source the {@link TraversalBranch} where the resulting path starts
* @param target the {@link TraversalBranch} where the resulting path ends
* @throws IllegalArgumentException if the {@link TraversalBranch#endNode()
* head nodes} of the supplied {@link TraversalBranch}s does not
* match
* @return an {@link TraversalBranch} that represents the path from the
* start node of the source
{@link TraversalBranch} to
* the start node of the target
{@link TraversalBranch}
*/
public static TraversalBranch combineSourcePaths( TraversalBranch source,
TraversalBranch target )
{
if ( !source.endNode().equals( target.endNode() ) )
{
throw new IllegalArgumentException(
"The nodes of the head and tail must match" );
}
Path headPath = source, tailPath = target;
Relationship[] relationships = new Relationship[headPath.length()
+ tailPath.length()];
Iterator iter = headPath.relationships().iterator();
for ( int i = 0; iter.hasNext(); i++ )
{
relationships[i] = iter.next();
}
iter = tailPath.relationships().iterator();
for ( int i = relationships.length - 1; iter.hasNext(); i-- )
{
relationships[i] = iter.next();
}
return new FinalTraversalBranch( tailPath.startNode(), relationships );
}
/**
* Returns a "preorder depth first" ordering policy. A depth first selector
* always tries to select positions (from the current position) which are
* deeper than the current position.
*
* @return a {@link BranchOrderingPolicy} for a preorder depth first
* selector.
*/
public static BranchOrderingPolicy preorderDepthFirst()
{
return CommonBranchOrdering.PREORDER_DEPTH_FIRST;
}
/**
* Returns a "postorder depth first" ordering policy. A depth first selector
* always tries to select positions (from the current position) which are
* deeper than the current position. A postorder depth first selector
* selects deeper position before the shallower ones.
*
* @return a {@link BranchOrderingPolicy} for a postorder depth first
* selector.
*/
public static BranchOrderingPolicy postorderDepthFirst()
{
return CommonBranchOrdering.POSTORDER_DEPTH_FIRST;
}
/**
* Returns a "preorder breadth first" ordering policy. A breadth first
* selector always selects all positions on the current depth before
* advancing to the next depth.
*
* @return a {@link BranchOrderingPolicy} for a preorder breadth first
* selector.
*/
public static BranchOrderingPolicy preorderBreadthFirst()
{
return CommonBranchOrdering.PREORDER_BREADTH_FIRST;
}
/**
* Returns a "postorder breadth first" ordering policy. A breadth first
* selector always selects all positions on the current depth before
* advancing to the next depth. A postorder breadth first selector selects
* the levels in the reversed order, starting with the deepest.
*
* @return a {@link BranchOrderingPolicy} for a postorder breadth first
* selector.
*/
public static BranchOrderingPolicy postorderBreadthFirst()
{
return CommonBranchOrdering.POSTORDER_BREADTH_FIRST;
}
public static SideSelectorPolicy alternatingSelectorOrdering()
{
return SideSelectorPolicies.ALTERNATING;
}
public static SideSelectorPolicy levelSelectorOrdering()
{
return SideSelectorPolicies.LEVEL;
}
public static BranchCollisionDetector shortestPathsCollisionDetector( int maxDepth )
{
return new ShortestPathsBranchCollisionDetector( Evaluators.toDepth( maxDepth ) );
}
/**
* Provides hooks to help build a string representation of a {@link Path}.
* @param the type of {@link Path}.
*/
public static interface PathDescriptor
{
/**
* Returns a string representation of a {@link Node}.
* @param path the {@link Path} we're building a string representation
* from.
* @param node the {@link Node} to return a string representation of.
* @return a string representation of a {@link Node}.
*/
String nodeRepresentation( T path, Node node );
/**
* Returns a string representation of a {@link Relationship}.
* @param path the {@link Path} we're building a string representation
* from.
* @param from the previous {@link Node} in the path.
* @param relationship the {@link Relationship} to return a string
* representation of.
* @return a string representation of a {@link Relationship}.
*/
String relationshipRepresentation( T path, Node from,
Relationship relationship );
}
/**
* The default {@link PathDescriptor} used in common toString()
* representations in classes implementing {@link Path}.
* @param the type of {@link Path}.
*/
public static class DefaultPathDescriptor implements PathDescriptor
{
public String nodeRepresentation( Path path, Node node )
{
return "(" + node.getId() + ")";
}
public String relationshipRepresentation( Path path,
Node from, Relationship relationship )
{
String prefix = "--", suffix = "--";
if ( from.equals( relationship.getEndNode() ) )
{
prefix = "<--";
}
else
{
suffix = "-->";
}
return prefix + "[" + relationship.getType().name() + "," +
relationship.getId() + "]" + suffix;
}
}
/**
* Method for building a string representation of a {@link Path}, using
* the given {@code builder}.
* @param the type of {@link Path}.
* @param path the {@link Path} to build a string representation of.
* @param builder the {@link PathDescriptor} to get
* {@link Node} and {@link Relationship} representations from.
* @return a string representation of a {@link Path}.
*/
public static String pathToString( T path, PathDescriptor builder )
{
Node current = path.startNode();
StringBuilder result = new StringBuilder();
for ( Relationship rel : path.relationships() )
{
result.append( builder.nodeRepresentation( path, current ) );
result.append( builder.relationshipRepresentation( path, current, rel ) );
current = rel.getOtherNode( current );
}
result.append( builder.nodeRepresentation( path, current ) );
return result.toString();
}
/**
* Returns the default string representation of a {@link Path}. It uses
* the {@link DefaultPathDescriptor} to get representations.
* @param path the {@link Path} to build a string representation of.
* @return the default string representation of a {@link Path}.
*/
public static String defaultPathToString( Path path )
{
return pathToString( path, new DefaultPathDescriptor() );
}
/**
* Returns a quite simple string representation of a {@link Path}. It
* doesn't print relationship types or ids, just directions.
* @param path the {@link Path} to build a string representation of.
* @return a quite simple representation of a {@link Path}.
*/
public static String simplePathToString( Path path )
{
return pathToString( path, new DefaultPathDescriptor()
{
@Override
public String relationshipRepresentation( Path path, Node from,
Relationship relationship )
{
return relationship.getStartNode().equals( from ) ? "-->" : "<--";
}
} );
}
/**
* Returns a quite simple string representation of a {@link Path}. It
* doesn't print relationship types or ids, just directions. it uses the
* {@code nodePropertyKey} to try to display that property value as in the
* node representation instead of the node id. If that property doesn't
* exist, the id is used.
* @param path the {@link Path} to build a string representation of.
* @return a quite simple representation of a {@link Path}.
*/
public static String simplePathToString( Path path, final String nodePropertyKey )
{
return pathToString( path, new DefaultPathDescriptor()
{
@Override
public String nodeRepresentation( Path path, Node node )
{
return "(" + node.getProperty( nodePropertyKey, node.getId() ) + ")";
}
@Override
public String relationshipRepresentation( Path path, Node from,
Relationship relationship )
{
return relationship.getStartNode().equals( from ) ? "-->" : "<--";
}
} );
}
public static PathDescription path()
{
return new PathDescription();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy