【问题标题】:Why aren't entities of the same kind implicitly in the same entity group为什么同一实体组中不隐含相同类型的实体
【发布时间】:2013-01-15 22:26:22
【问题描述】:

当它们没有父实体(它们是根实体)时,为什么同一类型的实体不隐含在同一个实体组中?这是否意味着如果我想做例如将数据从 MySQL 写入 HRD 的批处理操作:

db.put([Person(name=person.name) for person in cursor.execute("SELECT * FROM person")])

因为这个原因我必须使用事务:

注意:对于某些实体,对 db.put() 或 db.delete() 的批量调用可能会成功,但对于其他实体则不会。如果调用完全成功或完全失败很重要,则必须使用事务,并且所有受影响的实体必须在同一个实体组中。

来源:https://developers.google.com/appengine/docs/python/datastore/entities#Batch_Operations

我需要创建一个公共的根父密钥,它不作为真实实体存在,仅用于交易目的?

parent_key = db.Key.from_path('Human', 'human')
db.put([Person(parent=parent_key, name=person.name) for person in cursor.execute("SELECT * FROM person")])

【问题讨论】:

    标签: google-app-engine transactions google-cloud-datastore batch-processing


    【解决方案1】:

    同类实体并不隐含在同一个实体组中,因为它通常会在大多数用例中提供糟糕的性能。

    虽然不完全准确,但您可以将实体组视为控制分片的一种方式。同一组中的实体存储在物理上非常接近(即在同一服务器上),允许对所有实体进行事务操作,但也限制了该实体组的性能。实体组内的父关系不限于种类,父实体不必与子实体属于同一种类。

    大多数时候,实体组将包含不同种类的各种实体,这些实体在逻辑上属于一起,因为事务往往基于组。例如,一个 Account 可能是一堆 Transactions 的父级,或者一个 BlogPost 可能是一堆 Comments 的父级。

    将一个 Kind 的所有实体放在同一个父级下会阻止它们在事务中真正需要的其他操作被正确地设置为父级。

    在您的情况下,最好不要在事务中运行操作,并有额外的代码来处理失败情况。

    【讨论】:

    • 在你的情况下,最好不要在事务中运行操作,并且有额外的代码来处理失败情况。我正在寻找用于 put 操作的 API:@987654321 @,它确实表示如果某些实体失败,您可以捕获异常: 如果在操作过程中发生任何错误,即使实际写入了某些实体,也会始终引发异常。如果调用返回而没有引发异常,则所有实体都已成功写入。 但是您如何知道应该重复哪些实体?
    • @Jernej:你没有。这就是为什么 GAE 文档说您在事务中的操作应该是幂等的(即重复操作会产生相同的结果)。
    【解决方案2】:

    不,kind 和 parent 是密钥的两个不同部分。完整键实际上由应用程序 id(隐式设置)、命名空间 id、父键(根的所有父键)和名称或 id 组成。

    如果省略父实体,则实体是实体组的根,并且是该实体组中的唯一实体。

    在您的情况下,一批Person 实体不会构成一个实体组,而是每个Person(从事务的角度来看)都在其自己的实体组中。所以你的批量 put 不会是原子的。

    注意:实体组是“让我们将所有这些实体放在同一台机器上”的花哨名称。

    注意 2:现在有新的Cross-Group transactions,它使您能够跨 5 个不同的实体组进行交易。

    【讨论】:

    • 在您的情况下,一批 Person 实体不会组成一个实体组,而是每个 Person(从事务的角度)都在自己的实体组中。 我认为放入 HRD 中的每个人都在它自己的事务中。但是所有 Person 实体都应该在一个实体组下,因为它们都具有相同的父级?那么如果我批量放入 5 个人,我将有 5 笔交易?
    • 首先,如果需要,您必须明确使用事务。其次,从您的代码中,我没有看到 Person 有父集。
    • 看第二个sn-p,是不是设置了parent:db.put([Person(parent=parent_key, name=person.name) for person in cursor.execute("SELECT *来自人")])
    • 啊,是的,我错过了那个。另请注意,将实体放在同一组中会产生性能影响:每个实体组的写入次数限制为 1 次/秒。
    猜你喜欢
    • 1970-01-01
    • 2021-06-26
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多