Neo4j Java API:最广泛的路径算法性能问题

时间:2014-06-30 00:14:19

标签: java algorithm neo4j graph-databases

我使用的是neo4j-enterprise edition 2.1.2,并且拥有一个包含229626个节点和1667834个关系的图表。图模型描述哪个人知道具有关系的给定时间戳的另一个人(包括每个人的标识符)。

我尝试使用Neo4j Java Core API(嵌入模式)的现有dijkstra实现来定义最广泛路径问题的算法。不幸的是它表现得很慢。但首先让我向您展示我当前实施的一些细节:

  1. 使用自定义CostEvaluator和PathExpander

    定义算法
    PathFinder<WeightedPath> finder = GraphAlgoFactory
    .dijkstra(new   TimestampPathExpander(RelationType.KNOWS,
    Direction.BOTH, 1401746400, depth),  new RelationshipCostEvaluator());
    

    数字“1401746400”表示时间戳。应检查每个小于或等于它的关系。我还介绍了一个深度,以最小化路径长度和搜索开销。

  2. TimestampPathExpander

      @Override public Iterable<Relationship> expand(Path path, BranchState<String> state) {
            List<Relationship> results = new ArrayList<Relationship>();
    
            if(path.length() >= depth) {
            return results;
            }
    
            for (Relationship r : path.endNode().getRelationships(relationshipType,
            direction)) {
                // Traverse only relations for the given timestamp
                long relationTime = (long) r.getProperty("timestamp");
                if (relationTime <= timestamp) {
                 results.add(r);
                }
        }
        return results;
    }
    

    扩展器非常简单。只需查看关系时间戳并将节点添加到结果列表即可。如果生成的路径已达到最大深度,则不会向其添加其他节点。

  3. 自定义CostEvaluator

    @Override
    public Double getCost(Relationship relationship, Direction direction) {
       double measure = significance.edgeStrength(relationship);
       return measure > 0 ? Double.MAX_VALUE - measure : 0;
    }
    
  4. 该度量用作容量值,并根据包括开始和结束节点的度量以及两者的关系计算。因为dijkstra无法处理负边缘权重,所以我只是从大量(Double.Max_value)中减去该度量,从而实现大值被解释为“更便宜”。返回零是不应该触及的角落情况。

    这就是我如何预热我的缓存:

        for ( Node n : GlobalGraphOperations.at(db).getAllNodes() ) {
            n.getPropertyKeys();
            for ( Relationship relationship : n.getRelationships() ) {
                Node start = relationship.getStartNode();
            }
        }
    

    我也使用软缓存和以下graph.db属性,其中包含节点标识符的索引以及关系的开始和结束:

    neostore.nodestore.db.mapped_memory=3G
    neostore.relationshipstore.db.mapped_memory=2G
    neostore.propertystore.db.mapped_memory=100M
    neostore.propertystore.db.strings.mapped_memory=500M
    neostore.propertystore.db.arrays.mapped_memory=100M
    
    neostore.propertystore.db.index.keys.mapped_memory=500M
    neostore.propertystore.db.index.mapped_memory=500M
    
    use_memory_mapped_buffers=true
    

    以下是一些始终使用预热缓存的性能指标:

    Cache warmup...    |   Cache warmup...
    1742 ms            |   30056 ms
    1106 ms            |   22696 ms
    970 ms             |   24406 ms
    849 ms             |   22842 ms
    Angela Merkel      |   Angela Merkel
    0.3                |   0.3
    CDU                |   Wladimir Putin
    

    大约3秒钟,只需一跳。那几乎就是这样。是否有一些我不知道的技巧可以改善这些结果?也许我做错了什么?希望有人可以提供帮助。

    问候。

1 个答案:

答案 0 :(得分:0)

您的系统设置是什么?

你的mmio配置看起来太高了,占用了你所有的堆,所以没有为Neo4j的算法留下任何堆?你有很多记忆吗?我认为你的图表10M表示节点,50M表示关系非常好。您的预热还应该访问时间戳/成本属性,以便加载它们。

neostore.nodestore.db.mapped_memory=10M
neostore.relationshipstore.db.mapped_memory=100M
neostore.propertystore.db.mapped_memory=200M
neostore.propertystore.db.strings.mapped_memory=100M
neostore.propertystore.db.arrays.mapped_memory=0M

# remove both
neostore.propertystore.db.index.keys.mapped_memory=500M
neostore.propertystore.db.index.mapped_memory=500M

您还可以分享此方法的代码吗? significance.edgeStrength(relationship);我想知道你的0成本是否会反过来影响算法,因为较小的成本会导致更多的路径被考虑,如果成本不变(全部+0)那么它们的权重相等......

如果您的长度小于限制,我只会构造一个ArrayList,否则只返回Collections.emptyList();