在写了几千条记录后,Neo4j的速度变慢了。
存在两个加速查询的索引。 另外,使用EXPLAIN我知道每个查询都是一个恒定的时间过程。
indexOrder = schema.indexFor(ORDER)
.on("id")
.create();
indexShop = schema.indexFor(SHOP)
.on("domain")
这是我使用的查询:
WITH {json} as log
WITH log.order as order, log.shop as shop
MERGE (s:Shop {domain:shop.domain})
ON CREATE SET s=shop
MERGE (s)-[:Scored]->(r:Order {id:order.id})
ON CREATE SET r=order
以下是我如何将其存储到DB:
private void log() {
try (Transaction tx = graphDb.beginTx()) {
for (Map map : list) {
graphDb.execute(query,
singletonMap("json", map));
}
list = new ArrayList<>();
tx.success();
}
}
当我有1k日志时,我会调用上面的内容。
list.add(map);
count++;
if (count % 1000 == 0) {
log();
System.out.println(count);
}
其他信息:我使用这些配置设置:
.setConfig(GraphDatabaseSettings.pagecache_memory, "512M")
.setConfig(GraphDatabaseSettings.string_block_size, "60")
.setConfig(GraphDatabaseSettings.array_block_size, "300")
如果所有内容都在一个事务中完成,那么该系统可以处理200k个条目,但后来遇到内存问题。
那么,为什么只有5个事务(5k条目)被提交到数据库后,1k条目/事务处理方法会停止?
如何解决问题?
答案 0 :(得分:2)
您应该在MERGE
节点上单独执行Order
,以允许Cypher规划器使用:Order(id)
索引。 (此外,在在路径模式上执行MERGE
之前,您应该MERGE
路径模式中的节点,以避免在某些情况下创建重复的节点。)通过此更改,您的查询将如下所示(但它还不理想):
WITH {json} as log
WITH log.order as order, log.shop as shop
MERGE (s:Shop {domain:shop.domain})
ON CREATE SET s=shop
MERGE (r:Order {id:order.id})
ON CREATE SET r=order
MERGE (s)-[:Scored]->(r)
您应该尽量减少对execute()
的呼叫次数,因为每个呼叫都有很多开销。实际上,您可以轻松地创建一个查询来处理1000个项目的整个list
。因此,您可以将log()
代码更改为以下内容(我假设list
定义为List<Map<String, Object>>
或类似内容):
private void log() {
try (Transaction tx = graphDb.beginTx()) {
graphDb.execute(query, singletonMap("logList", list));
list = new ArrayList<Map<String, Object>>();
tx.success();
}
}
以下是相应的Cypher查询:
UNWIND {logList} as log
WITH log.order as order, log.shop as shop
MERGE (s:Shop {domain:shop.domain})
ON CREATE SET s=shop
MERGE (r:Order {id:order.id})
ON CREATE SET r=order
MERGE (s)-[:Scored]->(r)