Neo4j - 使用Neo4j REST图形数据库进行批量插入

3

我正在使用2.0.1版本。

我有成千上万个需要插入的节点。我的neo4j图形数据库在独立服务器上,并且我正在使用neo4j rest图形数据库库通过RestApi来实现这一点。

然而,我面临着缓慢的性能结果。我将我的查询分成批处理,每次发送500个cypher语句的单个http调用。我得到的结果是:

10:38:10.984 INFO commit
10:38:13.161 INFO commit
10:38:13.277 INFO commit
10:38:15.132 INFO commit
10:38:15.218 INFO commit
10:38:17.288 INFO commit
10:38:19.488 INFO commit
10:38:22.020 INFO commit
10:38:24.806 INFO commit
10:38:27.848 INFO commit
10:38:31.172 INFO commit
10:38:34.767 INFO commit
10:38:38.661 INFO commit

等等。 我正在使用的查询如下:

MERGE (a{main:{val1},prop2:{val2}}) MERGE (b{main:{val3}}) CREATE UNIQUE (a)-[r:relationshipname]-(b);

我的代码是这样的:

private RestAPI restAPI;
private RestCypherQueryEngine engine;
private GraphDatabaseService graphDB = new RestGraphDatabase("http://localdomain.com:7474/db/data/");

...

restAPI = ((RestGraphDatabase) graphDB).getRestAPI();
engine = new RestCypherQueryEngine(restAPI);

...

    Transaction tx = graphDB.getRestAPI().beginTx();

    try {
        int ctr = 0;
        while (isExists) {
            ctr++;
            //excute query here through engine.query()
            if (ctr % 500 == 0) {
                tx.success();
                tx.close();
                tx = graphDB.getRestAPI().beginTx();
                LOGGER.info("commit");
            }
        }
        tx.success();
    } catch (FileNotFoundException | NumberFormatException | ArrayIndexOutOfBoundsException e) {
        tx.failure();
    } finally {
        tx.close();            
    }

谢谢!

更新基准。 抱歉造成困扰,我发布的基准不准确,并且不适用于500个查询。我ctr变量实际上并不是指cypher查询的数量。

所以现在,我每3秒钟有500个查询,而且这3秒钟还在不断增加。与嵌入式Neo4j相比,速度仍然非常慢。


1
你应该从 https://dev59.com/4njZa4cB1Zd3GeqPjN-3 给出的提示中受益。 - tstorms
如果您正在使用Java,则应使用事务性终端点,您可能想尝试JDBC驱动程序:https://github.com/neo4j-contrib/neo4j-jdbc/tree/2.0 - Michael Hunger
1个回答

4

如果您有能力使用Neo4j 2.1.0-M01(但不要在生产环境中使用!!),您可以受益于新功能。如果您创建/生成类似以下的CSV文件:

val1,val2,val3
a_value,another_value,yet_another_value
a,b,c
....

您只需要启动以下代码:

final GraphDatabaseService graphDB = new RestGraphDatabase("http://server:7474/db/data/");
final RestAPI restAPI = ((RestGraphDatabase) graphDB).getRestAPI();
final RestCypherQueryEngine engine = new RestCypherQueryEngine(restAPI);
final String filePath = "file://C:/your_file_path.csv";
engine.query("USING PERIODIC COMMIT 500 LOAD CSV WITH HEADERS FROM '" + filePath
    + "' AS csv MERGE (a{main:csv.val1,prop2:csv.val2}) MERGE (b{main:csv.val3})"
    + " CREATE UNIQUE (a)-[r:relationshipname]->(b);", null);

你需要确保文件可以从安装服务器的机器访问。
查看我的服务器插件,该插件可以在服务器上为您完成此操作。如果构建并将其放入插件文件夹中,您可以在java中如下使用该插件:
final RestAPI restAPI = new RestAPIFacade("http://server:7474/db/data");
final RequestResult result = restAPI.execute(RequestType.POST, "ext/CSVBatchImport/graphdb/csv_batch_import",
    new HashMap<String, Object>() {
        {
            put("path", "file://C:/.../neo4j.csv");
        }
    });

编辑:

您还可以在Java REST包装器中使用BatchCallback来提高性能,并删除事务样板代码。您可以编写类似于以下脚本:

final RestAPI restAPI = new RestAPIFacade("http://server:7474/db/data");
int counter = 0;
List<Map<String, Object>> statements = new ArrayList<>();
while (isExists) {
    statements.add(new HashMap<String, Object>() {
        {
            put("val1", "abc");
            put("val2", "abc");
            put("val3", "abc");
        }
    });
    if (++counter % 500 == 0) {
        restAPI.executeBatch(new Process(statements));
        statements = new ArrayList<>();
    }
}

static class Process implements BatchCallback<Object> {

    private static final String QUERY = "MERGE (a{main:{val1},prop2:{val2}}) MERGE (b{main:{val3}}) CREATE UNIQUE (a)-[r:relationshipname]-(b);";

    private List<Map<String, Object>> params;

    Process(final List<Map<String, Object>> params) {
        this.params = params;
    }

    @Override
    public Object recordBatch(final RestAPI restApi) {
        for (final Map<String, Object> param : params) {
            restApi.query(QUERY, param);
        }
        return null;
    }    
}

嗨,Tim!听起来很不错!!我可以拿到2.1.0 M1版本,但恐怕我们需要在几周内将其部署到生产环境中。我会关注这个问题的进展。你有什么建议可以让它在2.0.1上运行吗?在你发布的另一个SO问题链接中,它谈到了模式索引。你能详细解释一下这个想法吗?谢谢! - lorraine batol
谢谢更新!我会尝试并发布我的基准测试结果。 - lorraine batol
模式索引仅与标签相关,因此您无法将其用于关系。 - tstorms
嗨@tstorms,我已经更新了我的基准测试,并附上了解释和问题。谢谢!我还尝试了neo4j 2.1.0 M1 +您的服务器插件,但我得到的结果时间比我需要扩展的rest读取超时时间更长。 - lorraine batol
服务器插件应该是最快的解决方案。因为你直接在服务器上工作,你正在使用嵌入式数据库。正如你所说,那总是做事情最快的方式。 - tstorms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接