0

序章

私は GAE を初めて使用し、データストアにあまりデータがないにもかかわらず、残念ながら 1 日あたりのデータストア読み取りのクォータ制限に非常に急速に達する小さなアプリを作成しました。
この質問は、レイアウトとインデックスの可能な使用に関するものでなければなりません (現在、それらの使用方法についての手がかりがありません)。

アプリがすべきこと

  • アプリは、カードゲームでスコアを追跡する必要があります (興味のある方はTichu ^^)。ゲームはいくつかのラウンドで構成され、1 つのチームが 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 ラウンドで 1 ハンドがゲームでいっぱいで、数回の更新で 1 日の割り当てに達しました。また、memcache を使用しても問題は解決しませんでした。
これが私の2番目のアプローチにつながりました:

アプリの 2 番目のレイアウト

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

現在、everyGameは、もはや ではなくなったラウンドのリストを格納していdb.Modelます。これにより、データセットの読み取り量が大幅に削減されます。

質問

  1. データモデルをどのように設定しますか? BlobProperty(型ではない格納オブジェクトを使用するのは理にかなっていますdb.Modelか?)
  2. このモデルのインデックスはどのようになりますか? (インデックスについての理解が非常に限られているため、詳しく説明してください。)
  3. データストア内の要素の数が増えると、1 日あたりの読み取りのクォータは、最終的には 2 番目のアプローチでも到達します。モデルを設計する際に、この事実をどのように考慮しますか?
4

1 に答える 1

1

簡単な答え - データを「正規化」しないことに慣れてください。これは、NoSQL DBS の優れた点です。リスト プロパティまたは一連の整数プロパティ (アプリケーションにとってより意味のある方) を Player モデルに追加し、ゲームの終了を追跡します。このような:

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

ポイントは、これらの両方が、より多くのリソースをクエリ/使用してから、ユーザーが最初に何回終了したかをプログラムで把握しようとするのを節約するのに役立つということです。

大量に使用することがわかっているデータがある場合は、冗長なプロパティをメイン モデルに格納することを検討してください。そうすれば、再クエリを実行しなくてもいつでもすぐに使用できます。

また、NDB API https://developers.google.com/appengine/docs/python/ndb/propertiesもご覧ください 。ゲーム ラウンドに JsonProperty を利用できます。

要するに、正規化は古い学校の RDB のものです。

于 2013-03-07T13:35:28.013 に答える