事务处理
本节介绍在执行算法期间使用事务的情况。当从 Cypher 调用算法过程时,该过程调用将在与 Cypher 语句相同的交易中执行。
在图投影期间
在图投影期间,将使用不会继承 Cypher 事务状态的新事务。这意味着 Cypher 事务状态中的更改对于图投影事务不可见。
这仅适用于原生投影,因为 Cypher 投影使用相同的 Cypher 事务而不是。 |
例如,以下语句将仅投影一个空图(假设 `MyLabel` 标签之前不存在于 Neo4j 数据库中)
CREATE (n:MyLabel) // the new node is part of Cypher transaction state
WITH *
CALL gds.graph.project('myGraph', 'MyLabel', '*')
YIELD nodeCount
RETURN nodeCount
nodeCount |
---|
0 |
在结果写入期间
算法的结果(例如节点属性)将在新事务中写入图。使用的事务数量取决于结果的大小和 `writeConcurrency` 配置参数(有关详细信息,请参阅部分 写入 和 常见配置参数)。这些事务与 Cypher 事务独立提交。这意味着,如果 Cypher 事务终止(由用户或数据库系统终止),已经提交的写入事务 _不会_ 回滚。
事务写入示例
本节中的代码用于说明目的。目标是演示 GDS 库写入功能与 Cypher Shell 和 Java API 的正确用法。 |
Cypher Shell
不正确使用的示例。
:BEGIN
// Project a graph
MATCH (a:Artist)<-[:RELEASED_BY]-(:Album)-[:HAS_GENRE]->(g:Genre)
RETURN gds.graph.project('test', g, a, { relationshipType: 'IS_ASSOCIATED_WITH' });
// Delete the old stuff
MATCH ()-[r:SIMILAR_TO]->() DELETE r;
// Run the algorithm
CALL gds.nodeSimilarity.write(
'test', {
writeRelationshipType: 'SIMILAR_TO',
writeProperty: 'score'
}
);
:COMMIT
上述语句的问题是所有查询都在同一事务中运行。
正确处理上述语句的方法是让每个语句在自己的事务中运行,如下所示。请注意语句的重新排序,这确保了在删除关系后,内存中的图将具有最新的更改。
首先删除不需要的关系。
:BEGIN
MATCH ()-[r:SIMILAR_TO]->() DELETE r;
:COMMIT
投影一个图。
:BEGIN
MATCH (a:Artist)<-[:RELEASED_BY]-(:Album)-[:HAS_GENRE]->(g:Genre)
RETURN gds.graph.project('test', g, a, { relationshipType: 'IS_ASSOCIATED_WITH' });
:COMMIT
运行算法。
:BEGIN
CALL gds.nodeSimilarity.write(
'test', {
writeRelationshipType: 'SIMILAR_TO',
writeProperty: 'score'
}
);
:COMMIT
Java API
使用 Java API 可以看到相同的问题,示例如下所示。
以下示例中使用的常量
// Removes the in-memory graph (if exists) from the graph catalog
static final String CYPHER_DROP_GDS_GRAPH_IF_EXISTS =
"CALL gds.graph.drop('test', false)";
// Projects a graph
static final String CYPHER_PROJECT_GDS_GRAPH_ARTIST_GENRE =
"MATCH (a:Artist)<-[:RELEASED_BY]-(:Album)-[:HAS_GENRE]->(g:Genre)" +
"RETURN gds.graph.project(" +
" 'test', g, a, { relationshipType: 'IS_ASSOCIATED_WITH' }" +
")";
// Runs NodeSimilarity in `write` mode over the in-memory graph
static final String CYPHER_WRITE_SIMILAR_TO =
"CALL gds.nodeSimilarity.write(" +
" 'test', {" +
" writeRelationshipType: 'SIMILAR_TO'," +
" writeProperty: 'score'"+
" }"
");";
使用不当
try (var session = driver.session()) {
var params = Map.<String, Object>of("graphName", "genre-related-to-artist");
session.writeTransaction(tx -> {
tx.run(CYPHER_DROP_GDS_GRAPH_IF_EXISTS, params).consume();
tx.run(CYPHER_PROJECT_GDS_GRAPH_ARTIST_GENRE, params).consume();
tx.run("MATCH ()-[r:SIMILAR_TO]->() DELETE r").consume();
return tx.run(CYPHER_WRITE_SIMILAR_TO, params).consume();
});
}
在这里,我们遇到了在同一事务中运行所有内容的相同问题。可以通过将每个语句拆分为自己的事务来正确编写。
语句的正确处理
try (var session = driver.session()) {
// First run the remove statement
session.writeTransaction(tx -> {
return tx.run("MATCH ()-[r:SIMILAR_TO]->() DELETE r").consume();
});
// Project a graph
var params = Map.<String, Object>of("graphName", "genre-related-to-artist");
session.writeTransaction(tx -> {
tx.run(CYPHER_DROP_GDS_GRAPH_IF_EXISTS, params).consume();
return tx.run(CYPHER_PROJECT_GDS_GRAPH_ARTIST_GENRE, params).consume();
});
// Run the algorithm
session.writeTransaction(tx -> {
return tx.run(CYPHER_WRITE_SIMILAR_TO, params).consume();
});
}