Q:

How to speed up osm2po when using as java lib?

I'am trying to utilize osm2po as java lib for calculation of distances matrix between some set of points (lat/lon) and for each pair of points I call the following method that code is based on sample provided at osm2po.de web-site:
public int getDistance(GeoPoint source, GeoPoint target) {
        int res = Integer.MAX_VALUE;
        int sourceId = graph.findClosestVertexId(source.getLatitude(), source.getLongitude(), 1);
        int targetId = graph.findClosestVertexId(target.getLatitude(), target.getLongitude(), 1);

        router.traverse(graph, sourceId, targetId, Float.MAX_VALUE, params);

        if (router.isVisited(targetId)) { // Found!
            int[] path = router.makePath(targetId);
            float distKm = 0.0f;

            for (int segmentId : path) {
                RoutingResultSegment rrs = graph.lookupSegment(segmentId);
                distKm = distKm + rrs.getKm();
            }

            res = (int)(distKm * 1000);
        }

        router.reset();
        return res;

But I noticed that it takes about 2-3 seconds per one point to calculate whole distance matrix (I have 10-25 points per matrix in average) that looks not too fast (30-60secs per matrix).
Could someone advice what could be improved here - especially I am not sure in correct usage of reset() call - when actually it should be done? - it's not too much documentation on osm2po usage within java...
Also I would appreciate any performance tips to improve this code. One more guess I have is that findClosestVertexId() is expensive enough call and cashing its results for subsequent calls could improve the situation.

A:

Indeed, you can improve the performance a lot. What you are doing here in order to fetch a distance between two points is to call the entire routing batch for each pair.
Usually a routing needs three steps:

Finding the nearest Source- and TargetVertex on the network.
Calculating the shortest path between them
Reconstructing all path informations (geometries, street names,
etc.)

Assuming you have a matrix of 10x10, why are you calling findClosestVertexId() 200 times?
You are going to calcule an adjaceny/cost-matrix. This can be done with a trick.
To get a first idea of what I'm talking about read my answer/comment on this thread:
Unreachable vertex.
Finally step 3 (lookupSegment) is not needed at all.

A:

package de.cm.osm2po.test;

import java.io.File;
import java.util.Arrays;

import de.cm.osm2po.logging.Log;
import de.cm.osm2po.logging.Log2poConsoleWriter;
import de.cm.osm2po.model.LatLon;
import de.cm.osm2po.routing.Graph;
import de.cm.osm2po.routing.MultiTargetRouter;
import de.cm.osm2po.routing.PoiRouter;

public class MatrixDemo {

    // ###################### Demo Main ##############################

    public static void main(String[] args) {
        File graphFile = new File("D:/work/osm2po/hh/hh_2po.gph");

        MatrixDemo matrixDemo = new MatrixDemo(graphFile);
        int[] vertexIds = matrixDemo.findClosestVertexIds(
                new LatLon(53.5, 10.1),
                new LatLon(53.4, 10.0),
                new LatLon(53.5, 9.9));
        float[][] matrix = matrixDemo.createMatrix(vertexIds);
        matrixDemo.close();

        for (int i = 0; i < matrix.length; i++) {
            System.out.println(Arrays.toString(matrix[i]));
        }
    }

    // ##################### Intrinsic Clazz #########################

    private Graph graph;
    private MultiTargetRouter router;

    public MatrixDemo(File graphFile) {
        Log log = new Log(Log.LEVEL_DEBUG).addLogWriter(new Log2poConsoleWriter());
        graph = new Graph(graphFile, log, Graph.SUPPORT_LATLON);
        router = new PoiRouter();
    }

    public void close() {
        graph.close();
    }

    public int[] findClosestVertexIds(LatLon... latLons) {
        int[] vertexIds = new int[latLons.length];
        for (int i = 0; i < latLons.length; i++) {
            vertexIds[i] = graph.findClosestVertexId(
                    (float)latLons[i].getLat(), (float)latLons[i].getLon());
        }
        return vertexIds;
    }

    public float[][] createMatrix(int... vertexIds) {
        int n = vertexIds.length;
        int[] cpVertexIds = Arrays.copyOf(vertexIds, n);
        float[][] matrix = new float[n][n];

        for (int y = 0; y < n; y++) {

            int swap = cpVertexIds[0];
            cpVertexIds[0] = cpVertexIds[y];
            cpVertexIds[y] = swap;

            int sourceId = cpVertexIds[0];
            int[] targetIds = Arrays.copyOfRange(cpVertexIds, 1, n -1);

            router.reset();
            router.traverse(graph, sourceId, targetIds, Float.MAX_VALUE, null);

            for (int z = 0; z < n; z++) {
                int x = z + y;
                if (x >= n) x -= n;

                matrix[y][x] = Float.MAX_VALUE;
                if (router.isVisited(vertexIds[x])) {
                    matrix[y][x] = router.getCost(vertexIds[x]);  
                }
            }

        }

        return matrix;
    }

}

If you have big data but only need the matrix for a small region, you can improve the performance by setting the MaxCost-Parameter to sth. smaller than Float.MAXVALUE.
Tipp: Mostly it is sufficient to call a full traversal using MaxValue twice or thrice.
After these loops the longest path should be found and you can replace the MaxValue with the cost * <some buffer> 
router.traverse(graph, sourceId, targetIds, longestPathCost * 1.5, null);

The last parameter (null) are optional additional properties.
Properties params = new Properties();
params.setProperty("findShortestPath", "true");
router.traverse(graph, sourceId, targetIds, Float.MAX_VALUE, params);

