事务处理

本节描述了算法执行期间事务的使用情况。当从 Cypher 调用算法过程时,该过程调用会在与 Cypher 语句相同的事务中执行。

在图投影期间

在图投影期间,会使用新的事务,这些事务不会继承 Cypher 事务的状态。这意味着 Cypher 事务状态中的更改对图投影事务不可见。

这仅适用于原生投影 (native projections),因为 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
表 1. 结果
nodeCount

0

在写入结果期间

算法的结果(例如节点属性)会在新事务中写入图中。所使用的事务数量取决于结果的大小和 writeConcurrency 配置参数(有关详细信息,请参阅 写入通用配置参数 部分)。这些事务与 Cypher 事务是独立提交的。这意味着,如果 Cypher 事务被终止(无论是被用户还是数据库系统),已经提交的写入事务将不会被回滚。

事务写入示例

本节中的代码仅用于说明目的。其目标是演示在 Cypher Shell 和 Java API 中正确使用 GDS 库写入功能的方法。

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();
    });
}

事务终止

Cypher 事务可以由用户或数据库系统终止。这将最终终止在图投影、算法执行或结果写入期间打开的所有事务。这不会立即生效,事务可能需要片刻时间才能识别出 Cypher 事务已被终止。