2016-12-22 2 views
0

Ich arbeite an einer Prozedur, die unter Verwendung des Dijkstra-Algorithmus den niedrigst gewichteten Pfad zwischen zwei Knoten finden soll. Die Prozedur sollte nur Pfade zurückgeben, deren alle Knoten bestimmte Kriterien erfüllen (d. H. Alle Knoten sollten Eigenschaften mit bestimmten Werten haben). Wenn mindestens ein Knoten in einem Pfad nicht mit den Kriterien übereinstimmt, wird der Pfad ungültig und der Algorithmus sollte nach dem nächstniedrigsten Pfad suchen.Wie funktioniert PathExpanderBuilder.addNodeFilter?

Um dies zu erreichen, verwende ich eine PathExpanderBuilder mit Knotenfilter, aber sie scheinen nichts zu filtern.

Hier ist mein Code:

public class Demo { 
    @Procedure 
    @Description("apoc.algo.dijkstraWithFilters(startNode, endNode, " + 
      "'distance', 10, 'prop1', 2, 'prop2', [100, 200], 'prop3') " + 
      " YIELD path, weight - run dijkstra with relationship property name as cost function" + 
      " and a default weight if the property does not exist") 
    public Stream<WeightedPathResult> dijkstraWithFilters(
      @Name("startNode") Node startNode, 
      @Name("endNode") Node endNode, 
      @Name("weightPropertyName") String weightPropertyName, 
      @Name("defaultWeight") double defaultWeight, 
      @Name("longPropName") String longPropName, 
      @Name("longPropValue") long longPropValue, 
      @Name("listPropName") String listPropName, 
      @Name("listPropValues") List<Long> listPropValues, 
      @Name("boolPropName") String boolPropName) { 

     PathFinder<WeightedPath> algo = GraphAlgoFactory.dijkstra(
       buildPathExpanderByPermissions(longPropName, longPropValue, listPropName, listPropValues, boolPropName), 
       (relationship, direction) -> convertToDouble(relationship.getProperty(weightPropertyName, defaultWeight)) 
     ); 
     return WeightedPathResult.streamWeightedPathResult(startNode, endNode, algo); 
    } 

    private double convertToDouble(Object property) { 
     if (property instanceof Double) 
      return (double) property; 
     else if (property instanceof Long) 
      return ((Long) property).doubleValue(); 
     else if (property instanceof Integer) 
      return ((Integer) property).doubleValue(); 
     return 1; 
    } 

    private PathExpander<Object> buildPathExpanderByPermissions(
      String longPropName, 
      long longPropValue, 
      String listPropName, 
      List<Long> listPropValue, 
      String boolPropName 
    ) { 
     PathExpanderBuilder builder = PathExpanderBuilder.allTypesAndDirections(); 
     builder.addNodeFilter(
       node -> !node.hasProperty(longPropName) || 
         node.getProperty(longPropName) instanceof Long && 
           (long) node.getProperty(longPropName) < longPropValue 
     ); 
     builder.addNodeFilter(
       node -> { 
        try { 
         return !node.hasProperty(listPropName) || 
           (boolean) node.getProperty(boolPropName, false) || 
           !Collections.disjoint((List<Long>) node.getProperty(listPropName), listPropValue); 
        } 
        catch (Exception e){ 
         return false; 
        } 
       } 
     ); 
     return builder.build(); 
    } 
} 

Was soll ich hier fehlt? Mache ich eine falsche Verwendung von PathExpanderBuilder?

Antwort

0

PathExpanderBuilders sind unveränderlich und so z. addNodeFilter gibt einen neuen PathExpanderBuilder mit dem hinzugefügten Filter zurück. Daher müssen Sie Ihre builder mit dieser zurückgegebenen Instanz neu zuweisen.