Warehouse

Neo4j Wiki から

This example will show you the basics of partitioning the graph by using relationship types. It is an extension of the Assembly example, so take a look at that one first.

Image:Warehouse.png

Now we have four relationship types with their respective semantics and colors in the graph image:

Relationship types
Type Semantics Color
VEHICLE connects the reference node to the vehicles yellow
WAREHOUSE connects the reference node to the warehouses blue
COMPOSED_BY connects parts to subparts red
STORED_IN connects vehicles/parts to warehouses green

It is easy to spot in the image that we can't simple iterate over all outgoing relationships from a part node any more. We will look into this in a moment, but first we should take a look at the relationships between warehouses and parts/vehicles.

Image:Warehouse-frame.png

The image shows the properties of the relationship from the frame part to the framestore warehouse. Our attention goes to:

  • Type: STORED_IN
  • quantity: 30

This tells us that 30 frames are stored in the framestore warehouse. A part could of course also have relationships to multiple warehouse, like the rim part in our example.


[edit] Finding the parts

In the Assembly example, the outer loop to find all vehicles looked like this:

for ( Relationship vehicleRel : graphDb.getReferenceNode().getRelationships( Direction.OUTGOING ) )
{
    Node vehicle = vehicleRel.getEndNode();

To make sure that we only iterate over vehicles and not warehouses too, the above piece of code has to be replaced by:

Traverser vehicles = graphDb.getReferenceNode().traverse(
    Traverser.Order.BREADTH_FIRST,
    StopEvaluator.DEPTH_ONE,
    ReturnableEvaluator.ALL_BUT_START_NODE, 
    WarehouseRels.VEHICLE, Direction.OUTGOING );
for ( Node vehicle : vehicles ) {

To put it in English: start traversing at the reference node, go breadth-first, go one level deep, return everything but the start node and follow VEHICLE type relationships that are directed out from the start node. As we get the nodes directly in this case, there is no need to get the node from the relationship like in the Assembly example.

OK, this was so easy so we will go on and add some extra functionality too. What about showing how many of each part are in the different warehouses?

We need to add this code:

System.out.print( " " + rel.getProperty( "quantity", 0 ) + " ( " );
Traverser warehouses = part.traverse(
    Traverser.Order.BREADTH_FIRST,
    StopEvaluator.DEPTH_ONE,
    ReturnableEvaluator.ALL_BUT_START_NODE,
    WarehouseRels.STORED_IN, Direction.OUTGOING );
for ( Node warehouse : warehouses )
{
    String name = (String) warehouse.getProperty( "name", "" );
    int quantity = (Integer) warehouses.currentPosition()
        .lastRelationshipTraversed().getProperty( "quantity", 0 );
    System.out.print( name + " " + quantity + " " );
}
System.out.println( ")" );

We just follow the STORED_IN relationship path on step out from where we are, and there we find everything we need.

The output from our new vehicle part list will now look like this:

Product: trike
  frame 1 ( framestore 30 )
    pedal 1 ( framestore 30 )
    seat 1 ( framestore 35 )
  wheel 3 ( wheelstore 200 )
    tire 1 ( wheelstore 60 )
      tube 1 ( wheelstore 50 )
      rim 1 ( framestore 60 wheelstore 100 )
    spoke 2 ( wheelstore 70 )

Please go to the references section at the end of the page for links to the full working source code.

[edit] Getting the cost

As when we were looking for the vehicles that existed above, a traverser is the simplest way to make sure that we are calculating the costs of the parts, and not of the warehouses.

The difference here is that we want to follow COMPOSED_BY relationships, and that the starting point is some incoming node.

private int getCost( Node part )
{
    int sum = (Integer) part.getProperty( "cost", 0 );
    Traverser subParts = part.traverse( 
        Traverser.Order.BREADTH_FIRST,
        StopEvaluator.DEPTH_ONE, 
        ReturnableEvaluator.ALL_BUT_START_NODE,
        WarehouseRels.COMPOSED_BY, Direction.OUTGOING );
    for ( Node subPart : subParts )
    {
        Relationship rel = subParts.currentPosition().lastRelationshipTraversed();
        int quantity = (Integer) rel.getProperty( "quantity", 1 );
        sum += getCost( subPart ) * quantity;
    }
    return sum;
}

[edit] References

Neo4j のサイト
ツールボックス