2

我的学士论文的一部分是将.nt文件(乌龟格式)加载到neo4j数据库中,在阅读并寻找可能的实现之后,我发现OpenRDF的SailRepositoryConnection实现应该像我需要的那样工作,但我遇到了严重的 OOM/GC 问题。我使用的库: - Blueprints 2.5 - OpenRDF Sesame 2.7.8 - Neo4j 2.0.3

我使用的系统: - Fedora 19 64bit - 4 Gb Ram - Java 版本 1.7.0_51

我的代码如下:

public void loadFile() throws SailException {
        //load file
        Neo4j2Graph neo4jGraph = new Neo4j2Graph(this.DB_DIRECTORY);
        BatchGraph<TransactionalGraph> neo = new BatchGraph<TransactionalGraph>(neo4jGraph, VertexIDType.NUMBER, 1);

    GraphSail sail = new GraphSail( neo4jGraph );
    sail.initialize();

    SailRepositoryConnection connection;
    try { 
        connection = new SailRepository( sail ).getConnection();

        URL url = f.toURI().toURL(); // getClass().getResource( this.f.getCanonicalPath() );
        // System.out.println( "Loading " + url + ": " );

        connection.add(url, null , RDFFormat.NTRIPLES);

        connection.commit();
        connection.close();
    } catch ( Exception e ) {
        e.printStackTrace(System.out);
    }

    // System.out.print( "Done." );

    sail.shutDown();
    neo4jGraph.shutdown();
    neo.shutdown();
}

对于非常小的 .nt 文件(如 4800 三倍),它工作得很好。但是尝试加载包含 180 万个三倍的 .nt 文件时会发生以下错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at org.apache.lucene.search.TermQuery$TermWeight.<init>(TermQuery.java:53)
    at org.apache.lucene.search.TermQuery.createWeight(TermQuery.java:199)
    at org.apache.lucene.search.Searcher.createNormalizedWeight(Searcher.java:168)
    at org.apache.lucene.search.IndexSearcher.createNormalizedWeight(IndexSearcher.java:664)
    at org.apache.lucene.search.Query.weight(Query.java:103)
    at org.neo4j.index.impl.lucene.Hits.<init>(Hits.java:101)
    at org.neo4j.index.impl.lucene.LuceneIndex.search(LuceneIndex.java:427)
    at org.neo4j.index.impl.lucene.LuceneIndex.query(LuceneIndex.java:314)
    at org.neo4j.index.impl.lucene.LuceneIndex.get(LuceneIndex.java:229)
    at org.neo4j.kernel.impl.coreapi.AbstractAutoIndexerImpl$IndexWrapper.get(AbstractAutoIndexerImpl.java:176)
    at com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Graph.getVertices(Neo4j2Graph.java:369)
    at com.tinkerpop.blueprints.oupls.sail.GraphSail$DataStore.findVertex(GraphSail.java:297)
    at com.tinkerpop.blueprints.oupls.sail.GraphSailConnection.getOrCreateVertex(GraphSailConnection.java:241)
    at com.tinkerpop.blueprints.oupls.sail.GraphSailConnection.addStatementInternal(GraphSailConnection.java:208)
    at com.tinkerpop.blueprints.oupls.sail.GraphSailConnection.addStatementInternal(GraphSailConnection.java:165)
    at org.openrdf.sail.helpers.SailConnectionBase.addStatement(SailConnectionBase.java:471)
    at org.openrdf.repository.sail.SailRepositoryConnection.addWithoutCommit(SailRepositoryConnection.java:281)
    at org.openrdf.repository.base.RepositoryConnectionBase.add(RepositoryConnectionBase.java:469)
    at org.openrdf.repository.util.RDFInserter.handleStatement(RDFInserter.java:207)
    at org.openrdf.rio.ntriples.NTriplesParser.parseTriple(NTriplesParser.java:319)
    at org.openrdf.rio.ntriples.NTriplesParser.parse(NTriplesParser.java:193)
    at org.openrdf.rio.ntriples.NTriplesParser.parse(NTriplesParser.java:132)
    at org.openrdf.repository.util.RDFLoader.loadInputStreamOrReader(RDFLoader.java:325)
[Full GC 963967K->963934K(963968K), 5.8010570 secs]
    at org.openrdf.repository.util.RDFLoader.load(RDFLoader.java:222)
    at org.openrdf.repository.util.RDFLoader.load(RDFLoader.java:180)
    at org.openrdf.repository.base.RepositoryConnectionBase.add(RepositoryConnectionBase.java:253)
    at src4neo2graph.QnL2.loadFile(QnL2.java:181)
    at main.Main.main(Main.java:52)

我还尝试在另一个系统上使用 4Gb 运行它,但发生了同样的错误。所以我尝试使用一些命令进行垃圾收集:(不是专门按那个顺序,但我有时都试过了)

Xms2G -Xmx2G -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseConcMarkSweepGC -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -XX:MaxHeapFreeRatio=95

但这也无济于事。

我已经搜索了很多,这似乎是每个人都用来将 .nt 文件加载到 Neo4j 数据库中的实现,就像我写的那样,它适用于少量的三元组。所以基本上:我的实现有问题吗?有更好的吗?我能做些什么(除了购买更多的内存(就像我说我在另一个系统上测试过更多的内存))来完成这项工作?

提前致谢。

4

3 回答 3

5

您实际上不需要将文件分成块;只需在每个语句添加和 commit() 后计算语句。在 blueprints-graph-sail 中有一个便利类SailLoader ( source ) 可以为您执行此操作,例如

public void loadFile() throws Exception {
    File f = new File("/tmp/sp2bench-1000000.nt.gz");

    Neo4j2Graph neo4jGraph = new Neo4j2Graph(this.DB_DIRECTORY);
    try {
        GraphSail sail = new GraphSail(neo4jGraph);
        sail.initialize();

        try {
            SailLoader loader = new SailLoader(sail);
            loader.setBufferSize(1000);  // this is the default
            loader.setVerbose(true);
            loader.load(f);
        } finally {
            sail.shutDown();
        }
    } finally {
        neo4jGraph.shutdown();
    }
}
于 2014-05-31T13:07:59.050 回答
0

我确定 tinkerpop 在内部是如何工作的,但我想一切都发生在一个事务中。在 Neo4j 中,事务首先在内存中建立,在完成 tx 后,它会被持久化,并且在下一次 gc 时释放使用的内存。如果您有大量事务,则需要适当数量的 RAM。

如果没有简单的方法来控制 tinkerpop 中的事务大小,请考虑将您的输入文件分成更小的块并一个接一个地导入它们,并确保.commit()在每个卡盘后调用。

于 2014-05-28T07:03:21.310 回答
0

你想出解决办法了吗?我也有同样的问题。您是否将文件分成块并加载它们?还是别的什么?如果您将文件分成块,您的查询是否按原样工作?

要回答你的问题,

如果您不打算将 Neo4j 用作纯三重存储。这是快速加载海龟文件并创建可以使用密码查询的图形的替代方法。

http://michaelbloggs.blogspot.de/2013/05/importing-ttl-turtle-ontologies-in-neo4j.html

希望能帮助到你!

于 2014-05-30T18:55:53.240 回答