Location Index already initialised

When using an existing graph and then trying to setup LocationIndexTree I get the error

LocationIndexTree index = new LocationIndexTree(graph.getBaseGraph(), graph.getDirectory());
index.loadExisting();
Already initialised

index.prepareIndex();
already created

LocationIndexTree index = new LocationIndexTree(graph.getBaseGraph(), graph.getDirectory());
NullPointerException

What is the correct way I should be using an existing LocationIndexTree in V2.0?

    EncodingManager em = EncodingManager.create(FlagEncoderFactory.FOOT + "|block_private=false," + FlagEncoderFactory.CAR + "," + FlagEncoderFactory.MOTORCYCLE + "|turn_costs=true");
    FlagEncoder encoder = em.getEncoder("car");
    Weighting weighting = new FastestWeighting(encoder);
    
    //Setup Graph
    Graphhopper.setupGraphhopper();
    GraphHopperStorage graph = Graphhopper.graphHopper.getGraphHopperStorage();
    // get the CH graph
    RoutingCHGraph chGraph = graph.getRoutingCHGraph("car");
    
    graph.freeze();
    // Load location index
    LocationIndexTree index = new LocationIndexTree(graph.getBaseGraph(), graph.getDirectory());
    index.loadExisting();

    // calculate a path with location index
    Snap fromSnap = index.findClosest(-41.1171,175.069, EdgeFilter.ALL_EDGES);
    Snap toSnap = index.findClosest(-41.1187,175.078, EdgeFilter.ALL_EDGES);

Using the following works, is there any point in even using GraphHopperStorage if I already have the graph created?

    Snap fromSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(-41.1171,175.069, EdgeFilter.ALL_EDGES);
    Snap toSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(-41.1187,175.078, EdgeFilter.ALL_EDGES);

Not sure about your exact question, but you can have a look into the unit tests or the examples about the low level API: https://github.com/graphhopper/graphhopper/blob/master/example/src/main/java/com/graphhopper/example/LowLevelAPIExample.java

So first you create the graph and then the LocationIndex

Hiya, so I have been following along in those examples. I suppose the difference is that I have already setup a graph from my pbf file.
So am I correct in that I don’t need to set a GraphHopperStorage as it already exists? So all I need to do is reference my GraphHopper.loadExisting(); graph.

Also I’ve found that if I do getLocationIndex() from outside each algo call I get incorrect distance/time.
For example;
This gives me the correct distances (and is slow)

                Snap fromSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(points[i].getLat(), points[i].getLon(), EdgeFilter.ALL_EDGES);
                Snap toSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(points[y].getLat(), points[y].getLon(), EdgeFilter.ALL_EDGES);
                QueryGraph queryGraph = QueryGraph.create(graph, fromSnap, toSnap);
                BidirRoutingAlgorithm algo = new CHRoutingAlgorithmFactory(routingCHGraph, queryGraph).createAlgo(new PMap());
                Path path = algo.calcPath(fromSnap.getClosestNode(), toSnap.getClosestNode());
From To Distance Time From_Lat From_Long To_Lat To_Long
0 0 0 0 -41.2212079 174.8177583 -41.2212079 174.8177583
0 1 21.40105007 1712 -41.2212079 174.8177583 -41.22103473 174.8178714
0 2 4.284524754 342 -41.2212079 174.8177583 -41.22124144 174.8180036
0 3 79.68969271 6374 -41.2212079 174.8177583 -41.22060215 174.8181301

This gives me an incorrect result (but is faster);

for (GHPoint point : points) {
            Snap fromSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(point.getLat(), point.getLon(), EdgeFilter.ALL_EDGES);
            nodeSnap.add(fromSnap);
            nodeIndexes.add(fromSnap.getClosestNode());
}

///////////////
// Some Code //
///////////////

for(int i=0; i<nodeIndexes.size(); i++){
        for(int y=0; y<nodeIndexes.size(); y++){
            QueryGraph queryGraph = QueryGraph.create(graph, nodeSnap.get(i), nodeSnap.get(y));
            BidirRoutingAlgorithm algo = new CHRoutingAlgorithmFactory(routingCHGraph, queryGraph).createAlgo(new PMap());
            Path path = algo.calcPath(nodeIndexes.get(i), nodeIndexes.get(y));
        }
}
From To Distance Time From_Lat From_Long To_Lat To_Long
0 0 0 0 -41.2212079 174.8177583 -41.2212079 174.8177583
0 1 106.2330592 8497 -41.2212079 174.8177583 -41.22103473 174.8178714
0 2 4.284524754 342 -41.2212079 174.8177583 -41.22124144 174.8180036
0 3 106.2322318 8497 -41.2212079 174.8177583 -41.22060215 174.8181301

Why does it matter if I process all of the node indexes and snaps earlier into an array?

I don’t understand this;

From To Distance Time From_Lat From_Long To_Lat To_Long nodeIndexes.get(i) nodeIndexes.get(y) nodeSnap.get(i).getClosestNode() nodeSnap.get(y).getClosestNode()
0 0 0 0 -41.2212079 174.8177583 -41.2212079 174.8177583 16504 16504 553100 553100
0 1 106.2330592 8496 -41.2212079 174.8177583 -41.22103473 174.8178714 16504 39641 553100 553102
0 2 4.284524754 342 -41.2212079 174.8177583 -41.22124144 174.8180036 16504 16504 553100 553101
0 3 106.2330592 8496 -41.2212079 174.8177583 -41.22060215 174.8181301 16504 39641 553100 553053

if nodeSnap is this;

Snap fromSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(point.getLat(), point.getLon(), EdgeFilter.ALL_EDGES);
nodeSnap.add(fromSnap);

and nodeIndexes is this;

Snap fromSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(point.getLat(), point.getLon(), EdgeFilter.ALL_EDGES);
nodeIndexes.add(fromSnap.getClosestNode());

Why are the two outputs different? nodeIndexes.get(0) doesnt equal nodeSnap.get(0).getClosestNode() ??

I have managed to fix the issue for the most part;

My solution was to stop producing a nodeIndex at the start. Instead I only fill the array with snaps.

for (GHPoint point : points) {
    Snap fromSnap = Graphhopper.graphHopper.getLocationIndex().findClosest(point.getLat(), point.getLon(), EdgeFilter.ALL_EDGES);
    nodeSnap.add(fromSnap);
}

Then when I use the algo to calcPath I use the nodeSnap getClosestNode() instead of the nodeIndex.
Path path = algo.calcPath(nodeSnap.get(i).getClosestNode(), nodeSnap.get(y).getClosestNode());

This gives the expected results but I am still having issues with multi-thread errors even with nodeSnap being a synronizedList
List<Snap> nodeSnap = Collections.synchronizedList(new ArrayList<Snap>());

Really super unsure why it doesn’t like doing it before hand…

All in all, it is a lot faster to pre-process the Snaps outside of the algo, even with a single thread.
Is there something in algo.calcPath that isn’t thread safe? Dunno…

Also, something to note;
It is slower to use QueryGraph queryGraph = QueryGraph.create(Graph, List<Snap>snaps);
Just use QueryGraph queryGraph = QueryGraph.create(Graph, Snap, Snap); for each iteration.

I will continue to make improvements where I can, I’m sure someone can see some glaringly obvious improvements so please offer any advice you have :slight_smile:

Have a look at the low level example here:

What is important (and this is probably not very intuitive) is that QueryGraph.create() modifies the closest nodes of the snaps. And the reason it does this is that ‘creating’ the query graph means adding virtual nodes and edges to the graph. So without the query graph the virtual nodes that might be the closest do not even exist yet.

I suppose my confusion stemed from the query graph being created from the same base graph so was unsure why node indexes would change.
I was following the examples but couldn’t work out the difference between node indexes from the base graph and node indexes from the query graph.

Thanks for the explanation, it makes it a lot clearer

Powered by Discourse