Google app engine 如何布局GAE数据存储 介绍

Google app engine 如何布局GAE数据存储 介绍,google-app-engine,google-cloud-datastore,Google App Engine,Google Cloud Datastore,我是GAE的新手,写了一个小应用程序,不幸的是,虽然数据存储中没有太多数据,但它每天的读取速度非常快,达到了数据存储的配额限制。 这个问题应该是关于布局和索引的可能使用(目前我不知道如何使用它们) 应用程序应该做什么 应用程序应该记录纸牌游戏的分数(对于那些感兴趣的人来说^^)。一场比赛由几轮组成,当一队得分达到1000分时结束 应用程序应显示已玩游戏的统计信息 应用程序的第一个布局 我的第一种布局方法是使用以下实体: class Player(db.Model): Name = d

我是GAE的新手,写了一个小应用程序,不幸的是,虽然数据存储中没有太多数据,但它每天的读取速度非常快,达到了数据存储的配额限制。
这个问题应该是关于布局和索引的可能使用(目前我不知道如何使用它们)

应用程序应该做什么
  • 应用程序应该记录纸牌游戏的分数(对于那些感兴趣的人来说^^)。一场比赛由几轮组成,当一队得分达到1000分时结束
  • 应用程序应显示已玩游戏的统计信息
应用程序的第一个布局 我的第一种布局方法是使用以下实体:

class Player(db.Model):
    Name = db.StringProperty(required = True)

class Game(db.Model):
    Players = db.ListProperty(db.Key)
    Start = db.DateTimeProperty(auto_now_add = True, required = True)
    End = db.DateTimeProperty()

class Round(db.Model):
    Game = db.Reference(Game, required = True)
    RoundNumber = db.IntegerProperty(required = True)
    PointsTeamA = db.IntegerProperty(required = True)
    PointsTeamB = db.IntegerProperty(required = True)
    FinishedFirst = db.ReferenceProperty(Player, required = True)
    TichuCalls = db.ListProperty(db.Key)
正如您在上面看到的,这些实体是规范化的(至少我希望是这样)。然而,使用这种方法,简单的计算如下

  • 哪位选手赢得的比赛最多
这可能看起来像这样

#Untested snippet just to get an idea of what I am doing here
Wins = dict.fromkeys(Player.all().fetch(None), 0)
for r in Round.all():
    wins[r.FinishedFirst] += 1
还有其他统计数据,比如

  • 哪位选手最常先完成
  • 哪位选手获胜率最高
  • 等等
产生大量的数据集读取操作。在一个只显示有限数量统计数据的页面上,一天的配额只需几次刷新,只需60轮,一手游戏。此外,memcache的使用并没有解决这里的问题。
这导致了我的第二种方法:

应用程序的第二个布局 现在,每一场
游戏
都会存储一个不再是
db.Model的回合列表
。这大大减少了数据集的读取量

问题
  • 您将如何设置数据模型?(使用
    BlobProperty
    存储非
    db.Model类型的对象有意义吗?)
  • 这个模型的索引是什么样子的?(请详细说明,因为我对索引的理解非常有限。)
  • 随着数据存储中元素数量的增加,每天的读取配额最终也将通过第二种方法达到。在设计模型时,您将如何考虑这一事实

  • 简短回答-习惯于不“规范化”数据。这就是NoSQL DBS的优点。我会在玩家模型中添加一个列表属性或一组整数属性(无论哪个对你的应用程序更有意义),跟踪他们的游戏结束。像这样:

    class Player(db.Model):
        Name = db.StringProperty(required = True)
        FinishedFirst = db.IntegerProperty(default=0)
        FinishedSecond = db.IntegerProperty(default=0)
        ...
    

    关键是,这两种方法都将帮助您避免查询/使用更多资源,然后以编程方式尝试计算用户在第一次中完成了多少次

    当您拥有知道将要大量使用的数据时,请考虑在主模型中存储冗余属性,这样就可以随时使用,而无需重新查询

    另外,看看NDB API 您可以利用JsonProperty进行游戏回合


    归根结底,规范化是老式的RDB东西

    考虑在免费获得memcaching时使用ndb.models(保存数据存储读取/写入)使用ndb属性,您可以得到一个重复的属性/结构,它可能会取代整个循环属性。有没有一种好方法可以确保数据存储中的冗余信息同步且不相互冲突?这是存储冗余信息的一个缺点-写入次数过多,这肯定会减少阅读量。第一道防线是确保您知道存储相同数据的所有位置,例如名称,并且每次更新名称时,确保以编程方式更新每个相对实体。第二道防线是创建经常运行的cron作业,自动比较数据,如果数据与某个基本实体不同步,则更新它。你不应该依赖这个。它表示数据不同步的时间段。
    class Player(db.Model):
        Name = db.StringProperty(required = True)
        FinishedFirst = db.IntegerProperty(default=0)
        FinishedSecond = db.IntegerProperty(default=0)
        ...
    
    class Player(db.Model):
        Name = db.StringProperty(required = True)
        Finishes = db.ListProperty() # A list of 1s, 2s, 3s, etc... for each finish