【问题标题】:Getting incremental changes from Neo4j DB从 Neo4j DB 获取增量更改
【发布时间】:2013-08-12 12:35:52
【问题描述】:

Neo4j 1.9 中是否有任何方法可以在特定时间跨度内获取所有已修改(创建/更新/删除)的节点/关系 - 就像我们在 SOLR 增量导入中所做的那样?

我能想到的一种粗略方法是为每个节点/关系维护一个时间戳属性,并将它们索引以获取这些节点/关系。

START a=node:custom_index("timestamp:[{start_time} TO {end_time}]")
RETURN a;

但是问题是如果我通过 CYPHER 修改节点,索引将不会更新。

【问题讨论】:

    标签: neo4j


    【解决方案1】:

    不幸的是,Neo4j 中没有类似的内置功能。

    一一解决问题。维护时间戳是不可能的,因为在删除节点/关系的情况下你无处可去。您也不能在属性上放置时间戳。所以你会知道一个节点已被更改,但不知道如何更改。

    一种可能的解决方案是使用 TransactionEventHandlers 在发生更改时将更改记录在某处。然后,您可以 a) 准确选择要记录的内容,b) 不用担心 Cypher,无论您使用什么方法更新数据库,它都会被记录。

    我整理了一个small demo。它只是将每个更改记录到标准输出。为简单起见,它使用了一些 GraphAware 类(免责声明:我是作者),但如果您愿意,也可以不使用它们。

    这是代码的重要部分,以防链接最终被破坏或发生什么:

    @Test
    public void demonstrateLoggingEveryChange() {
        GraphDatabaseService database = new TestGraphDatabaseFactory().newImpermanentDatabase();
    
        database.registerTransactionEventHandler(new ChangeLogger());
    
        //perform mutations here
    }
    
    private class ChangeLogger extends TransactionEventHandler.Adapter<Void> {
    
        @Override
        public void afterCommit(TransactionData data, Void state) {
            ImprovedTransactionData improvedData = new LazyTransactionData(data);
    
            for (Node createdNode : improvedData.getAllCreatedNodes()) {
                System.out.println("Created node " + createdNode.getId()
                        + " with properties: " + new SerializablePropertiesImpl(createdNode).toString());
            }
    
            for (Node deletedNode : improvedData.getAllDeletedNodes()) {
                System.out.println("Deleted node " + deletedNode.getId()
                        + " with properties: " + new SerializablePropertiesImpl(deletedNode).toString());
            }
    
            for (Change<Node> changedNode : improvedData.getAllChangedNodes()) {
                System.out.println("Changed node " + changedNode.getCurrent().getId()
                        + " from properties: " + new SerializablePropertiesImpl(changedNode.getPrevious()).toString()
                        + " to properties: " + new SerializablePropertiesImpl(changedNode.getCurrent()).toString());
            }
    
            for (Relationship createdRelationship : improvedData.getAllCreatedRelationships()) {
                System.out.println("Created relationship " + createdRelationship.getId()
                        + " between nodes " + createdRelationship.getStartNode().getId()
                        + " and " + createdRelationship.getEndNode().getId()
                        + " with properties: " + new SerializablePropertiesImpl(createdRelationship).toString());
            }
    
            for (Relationship deletedRelationship : improvedData.getAllDeletedRelationships()) {
                System.out.println("Deleted relationship " + deletedRelationship.getId()
                        + " between nodes " + deletedRelationship.getStartNode().getId()
                        + " and " + deletedRelationship.getEndNode().getId()
                        + " with properties: " + new SerializablePropertiesImpl(deletedRelationship).toString());
            }
    
            for (Change<Relationship> changedRelationship : improvedData.getAllChangedRelationships()) {
                System.out.println("Changed relationship " + changedRelationship.getCurrent().getId()
                        + " between nodes " + changedRelationship.getCurrent().getStartNode().getId()
                        + " and " + changedRelationship.getCurrent().getEndNode().getId()
                        + " from properties: " + new SerializablePropertiesImpl(changedRelationship.getPrevious()).toString()
                        + " to properties: " + new SerializablePropertiesImpl(changedRelationship.getCurrent()).toString());
            }
        }
    }    
    

    【讨论】:

    • 谢谢 Michal,但有了这个我需要维护另一个系统,所有这些更改都将在其中进行,并将从那里进行查询。我正在寻找的是,让我得到所有已更改的 nodeId,以便我可以处理它们。
    • 小心节点 ID,它们会被回收。所以当你删除一个节点时,它的 ID 最终会被分配给不同的节点。您应该使用自己的标识符。至于维护不同的系统,嗯,这是一个选择。其他选项包括将更改发布到消息队列或文本文件,或将它们存储在图表中的某个位置(小心,如​​果它在一个地方,那么它将成为锁的热点)...
    • 您可以有一个节点的链接列表,即由事务事件处理程序管理的事件列表。 @MichalBachman 关于争用,无论如何只有一个线程可以在任何给定时间提交,所以如果只有处理程序写入该队列,那么它不会成为其他事情的瓶颈。
    • 嗨 Mattias,关于争用,我说的是一个场景,例如,您将每个更改的节点链接到具有 HAS_CHANGED 关系的根节点。在这种情况下,每个 tx 都会尝试锁定根节点,从而导致多线程环境中的吞吐量下降。那是对的吗?谢谢。
    • 关于您的解决方案,这绝对是一个选择,但我猜它不会在重新启动后存活。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-13
    • 2019-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多