neo4j 在 1000 万个节点上更新属性

neo4j update properties on 10 million nodes

我用的是neo4jjava核心api,想更新1000万个节点。 我认为使用多线程会更好,但性能不是很好(设置属性需要 35 分钟)。

解释一下:每个节点"Person"与"Point"节点至少有一个关系"POINTSREL",该节点具有属性"Points"。我想总结 "Point" 节点的点并将其设置为 属性 到 "Person" 节点。

这是我的代码:

Transaction transaction = service.beginTx();
ResourceIterator<Node> iterator = service.findNodes(Labels.person);
transaction.success();
transaction.close();

ExecutorService executor = Executors.newFixedThreadPool(5);

while(iterator.hasNext()){
    executor.execute(new MyJob(iterator.next()));
}

//wait until all threads are done
executor.shutdown();

try {
    executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
    e.printStackTrace();
}

这里是可运行的 class

private class MyJob implements Runnable {

    private Node node;

    /* collect useful parameters in the constructor */
    public MyJob(Node node) {
        this.node = node;
    }

    public void run() {
        Transaction transaction = service.beginTx();
        Iterable<org.neo4j.graphdb.Relationship> rel = this.node.getRelationships(RelationType.POINTSREL, Direction.OUTGOING);

        double sum = 0;
        for(org.neo4j.graphdb.Relationship entry : rel){
            try{
                sum += (Double)entry.getEndNode().getProperty("Points");
            } catch(Exception e){
                e.printStackTrace();
            }
        }
        this.node.setProperty("Sum", sum);

        transaction.success();
        transaction.close();
    }
}

有更好(更快)的方法吗?

关于我的设置: 具有 8 个 CPU 和 32GB 内存的 AWS 实例

neo4j-wrapper.conf

# Java Heap Size: by default the Java heap size is dynamically
# calculated based on available system resources.
# Uncomment these lines to set specific initial and maximum
# heap size in MB.
wrapper.java.initmemory=16000
wrapper.java.maxmemory=16000

neo4j.properties

# The type of cache to use for nodes and relationships.
cache_type=soft
cache.memory_ratio=30.0
neostore.nodestore.db.mapped_memory=2G
neostore.relationshipstore.db.mapped_memory=7G
neostore.propertystore.db.mapped_memory=2G
neostore.propertystore.db.strings.mapped_memory=2G
neostore.propertystore.db.arrays.mapped_memory=512M

在我看来,有些地方可以改进。

题外话

如果您使用 Java 7(或更高版本),请考虑使用 try with resource 来处理事务。它将防止您出错。

性能

首先 - 批处理。目前您是:

  • 正在创建工作
  • 启动线程(其实executor中有pool)
  • 开始交易

对于每个节点。您应该考虑 批量 进行更新。这意味着您应该:

  • 收集 N 个节点(即 N=1000)
  • N 个节点创建单个作业
  • 在作业中创建单个事务
  • 更新该交易中的 N 个节点
  • 关闭交易

设置

您有 8 个 CPU。这意味着您可以创建更大的线程池。我觉得Executors.newFixedThreadPool(16)就可以了

黑客

您有 32GB 内存。我可以建议:

  • 将 java 堆大小减少到 8GB。根据我的经验,大堆大小会导致大量 GC 暂停和性能下降
  • 创建映射内存大小。只是为了确保更多的数据可以保留在缓存中。

只为你的情况。如果 所有 您的数据都可以放入 RAM,那么您可以将 cache_type 更改为 hard 以实现此更改目的。 Details.

配置

如您所说 - 您正在使用 Core API。这是 Embedded 图数据库还是服务器 extension

如果这是 Embedded 图形数据库 - 您应该验证您的数据库设置是否应用于创建的实例。

我发现 属性 "cache_type=soft" 存在问题。我将它设置为 "cache_type=none",执行时间从 30 分钟减少到 2 分钟。在一些更新之后,总是有线程被阻塞大约 30 秒 - 更改此 属性 有助于避免这些阻塞。我会搜索更详细的解释。