Google App Engineでの成果のための可能なデータスキーム
-
21-09-2019 - |
質問
Google App Engineを使用してフラッシュゲームWebサイトを構築しています。私はそれに成果を上げ、このデータを正確に保存する方法に頭をかいています。 (グーグル以外の)ユーザーモデルがあります。各種類の達成(名前、説明、写真)を保存する方法を知る必要があり、それらを獲得したユーザーとリンクする必要があります。また、私は彼らがいつそれを獲得したかを追跡する必要があります。
誰かが検出やその他の達成関連タスクについて提案をしたい場合は、お気軽に。
編集:
Nongoogleユーザーモデル:
class BeardUser(db.Model):
email = db.StringProperty()
username = db.StringProperty()
password = db.StringProperty()
settings = db.ReferenceProperty(UserSettings)
is_admin = db.BooleanProperty()
user_role = db.StringProperty(default="user")
datetime = db.DateTimeProperty(auto_now_add=True)
解決
ユーザーが(ユーザーが自分のゲームをアップロードできるKongregateなどのようなものなどのように、エーチャーを動的に追加しない限り、達成リストは静的になります。つまり、メインのPythonファイルに(名前、説明、画像)リストを、または達成モジュールなどとして保存できます。このリストで指定されているように、名前またはIDで動的データの成果を参照できます。
特定のユーザーが成果を得たかどうかを示すために、簡単な方法は、プレーヤーが得た成果を保持するプレーヤーモデルにListPropertyを追加することです。デフォルトでは、これがインデックスが作成されるため、どのプレーヤーがどの成果などを獲得したかを照会できます。
また、ユーザーが達成を取得した日付/時刻を保存したい場合は、組み込みのプロパティが理想的ではない領域に入ります。各成果に対応するDateTimeプロパティを備えた別のListPropertyを追加できますが、それは厄介です。私たちが本当に好きなのは、達成時間/名前を達成した時間と一緒に保存して簡単にすることができるように、TupleまたはDictです。将来の各成果に関連する追加のプロパティを追加する。
このようなケースに対する私の通常のアプローチは、私の理想的なデータ構造をブロブプロパティに捨てることですが、それにはいくつかの欠点があり、別のアプローチを好むかもしれません。
もう1つのアプローチは、ユーザーモデルとは別に達成モデルを持つことと、ユーザーが得たすべての成果に対するReferencePropertiesでいっぱいのListPropertyを使用することです。これには、すべてを非常にうまくインデックス化できるという利点がありますが、特に検索するための多くの成果がある場合は、実行時に追加のAPI CPUコストになります。すべてのユーザーの成果を削除するなどの操作は、上記に比べて非常に高価です。
他のヒント
ここでブランドンの答えに基づいています。
可能であれば、Pythonファイルのすべての成果を定義する方がはるかに高速になるため、それらはメモリ内であり、データベースフェッチを必要としません。これを実装する方が簡単です。
class StaticAchievement(object):
"""
An achievement defined in a Python file.
"""
by_name = {}
by_index = []
def __init__(self, name, description="", picture=None):
if picture is None: picture = "static/default_achievement.png"
StaticAchievement.by_name[name] = self
StaticAchievement.by_index.append(self)
self.index = len(StaticAchievement.by_index)
# This automatically adds an entry to the StaticAchievement.by_name dict.
# It also adds an entry to to the StaticAchievement.by_index list.
StaticAchievement(
name="tied your shoe",
description="You successfully tied your shoes!",
picture="static/shoes.png"
)
その場合、DB.StringListPropertyで各プレイヤーの成果のIDを保持することだけです。プレーヤーのオブジェクトをロードしている場合、成果をレンダリングするには追加のDBルックアップが必要ありません - すでにIDを持っているので、Staticachievement.allでそれらを調べる必要があります。これは簡単に実装でき、どのユーザーが特定の成果を持っているなどを簡単にクエリすることができます。他に何も必要ありません。
ユーザーが成果を所有していることに関連付けられている追加データ(たとえば、取得された日付)が必要な場合は、アプローチの選択肢があります。
1:同じ長さの別のリストプロパティに保存します。
これにより、実装のシンプルさとプロパティのインデックス性が保持されます。ただし、この種の解決策は、すべての人の好みにとってではありません。このデータの使用を厄介にする必要がある場合は、次のようなプレーヤーオブジェクトにメソッドを書くだけです。
def achievement_tuples(self):
r = []
for i in range(0, len(self.achievements)):
r.append( (self.achievements[i], self.achievement_dates[i]) )
return r
整数の並列リストプロパティを維持し、ユーザーが進行したときにそれらの整数を増やすことにより、進捗を処理できます。
データがどのように表現されているかを理解できる限り、必要な方法の背後にあるその表現を簡単に隠すことができます。これにより、必要なインターフェイスと、必要なパフォーマンスとインデックス作成の特性の両方を持つことができます。ただし、実際にインデックスが必要で、リストが気に入らない場合は、オプション#2を参照してください。
2:追加データをBlobpropertyに保存します。
これには、データをシリアル化して脱着する必要があり、ListPropertiesの素晴らしいクエリを放棄する必要がありますが、並列リストの概念を嫌うと幸せになるでしょう。これは、アプリエンジンの方法とは異なるように、人々が実際に物事を行う方法を本当に望んでいるときに行う傾向があります。
3:追加データをDBに保存します
(たとえば、Achievement IDのStringPropertyとDateProperty、およびuserPropertyの両方を含むPlayerSachievementオブジェクト。
プレイヤーは潜在的に多数の成果を得ることを期待しているため、これのオーバーヘッドは速く悪くなります。 Memcache、プレレンダリングHTMLのブロブやタプルのシリアル化リストなどの中間データの保存、タスクのセットアップなど:非常に迅速に非常に複雑になります。これは、達成定義が必要な場合にしなければならないことでもあります。 DBに変更/保存される/保存する。