如何布局GAE数据存储

介绍

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

该应用应该做什么

  • 该应用程序应该跟踪卡牌游戏中的分数(对你感兴趣的人来说是Tichu ^^)。 一场比赛由几轮比赛组成,一旦一支球队达到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并不能解决此处的问题。
    这导致了我的第二种方法:

    应用程序的第二个布局

    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()
        Rounds = db.BlobProperty()
    
        def GetRounds(self):
            if self.Rounds:
                return pickle.loads(self.Rounds)
            else:
                return []
    
        def AddRound(self, R):
            Rounds = self.GetRounds()
            Rounds.append(R)
            self.Rounds = pickle.dumps(Rounds, -1)
    
    class Round(object):
        def __init__(self, Game, RoundNumber, PointsTeamA, PointsTeamB, FinishedFirst, TichuCalls):
            self.Game = Game
            self.RoundNumber = RoundNumber
            self.PointsTeamA = PointsTeamA
            self.PointsTeamB = PointsTeamB
            self.FinishedFirst = FinishedFirst
            self.TichuCalls = TichuCalls
    

    现在每个Game存储一个不再是db.Model的Rounds列表。 这大大减少了数据集的读取量。

    问题

  • 你将如何设置数据模型? (使用BlobProperty存储非db.Model类型的对象是否有意义?)
  • 这个模型的索引怎么样? (请详细说明,因为我对索引的理解非常有限。)
  • 随着数据存储中元素的数量不断增加,每天的读数配额最终也将随着第二个应用程序一起达成。 在设计模型时如何考虑这个事实?

  • 简短的回答 - 习惯于不对数据进行“规范化”。 这就是NoSQL DBS的美妙之处。 我会向玩家模型添加一个list属性或一堆整数属性(无论哪个更适合您的应用程序),以跟踪他们的游戏结束。 喜欢这个:

    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
    

    重点在于这两点都将帮助您节省查询/使用更多资源的费用,然后以编程方式试图弄清楚用户首先完成了多少次。

    如果您知道要使用A LOT的数据,请考虑在主模型中存储冗余属性,以便始终触手可及,而无需重新查询。

    另外,请查看NDB API https://developers.google.com/appengine/docs/python/ndb/properties您可以利用JsonProperty进行游戏回合。

    底线,正常化是老派RDB的东西。

    链接地址: http://www.djcxy.com/p/67457.html

    上一篇: How to layout GAE datastore

    下一篇: My GAE python development datastore is never persisted to a file