28

メンバーがGoogleAppEngineを使用してアクティビティを作成し、他のメンバーのアクティビティをフォローするソーシャルアプリケーションを設計するための最良の方法は何でしょうか。

具体的には、次のエンティティがあると仮定します。

  • 友達がいるユーザー
  • ユーザーが行ったアクションを表すアクティビティ(それぞれに文字列メッセージとその所有者ユーザーへのReferencePropertyがある場合、またはappengineのキーを介して親の関連付けを使用できる場合)

難しいのは、友達のアクティビティをフォローすることです。つまり、すべての友達の最新のアクティビティを集約することです。通常、これはアクティビティテーブルと友達リストの間の結合ですが、Nクエリ(Nは友達の数)を起動してメモリにマージする必要があることをシミュレートする結合がないため、appengineで実行可能な設計ではありません-非常に高価で、おそらくリクエストの期限を超えるでしょう...)

私は現在、受信トレイキューを使用してこれを実装することを考えています。ここで、新しいアクティビティを作成すると、後続のすべてのユーザーの「受信トレイ」に新しいアクティビティのキーを配置するバックグラウンドプロセスが起動されます。

  • 「Xをフォローしているすべてのユーザー」を取得することは、可能なappengineクエリです
  • 基本的に(ユーザー、アクティビティキー)タプルを格納する新しい「受信トレイ」エンティティへのそれほど高価なバッチ入力ではありません。

このデザインや代替案などについてのご意見をお待ちしております。

4

4 に答える 4

25

Google I /OでBrettSlatkinが行った魅力的な講演である、 AppEngineでのスケーラブルで複雑なアプリの構築pdf )をご覧ください。彼は、Twitterのようなスケーラブルなメッセージングサービスを構築する問題に取り組んでいます。

listプロパティを使用した彼の解決策は次のとおりです。

class Message(db.Model):
    sender = db.StringProperty()
    body = db.TextProperty()

class MessageIndex(db.Model):
    #parent = a message
    receivers = db.StringListProperty()

indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id)
keys = [k.parent() for k in indexes)
messages = db.get(keys)

このキーのみのクエリは、受信者のリストを逆シリアル化およびシリアル化せずに、指定したものと等しい受信者を持つメッセージインデックスを検索します。次に、これらのインデックスを使用して、必要なメッセージのみを取得します。

これを行う間違った方法は次のとおりです。

class Message(db.Model):
    sender = db.StringProperty()
    receivers = db.StringListProperty()
    body = db.TextProperty()

messages = Message.all().filter('receivers =', user_id)

クエリはクエリによって返されるすべての結果をアンパッケージする必要があるため、これは非効率的です。したがって、各受信者リストに1,000人のユーザーがいる100個のメッセージを返した場合、100,000(100 x 1000)のリストプロパティ値を逆シリアル化する必要があります。データストアのレイテンシとCPUのコストが高すぎます。

最初はこれらすべてにかなり混乱していたので、listプロパティの使用に関する短いチュートリアルを作成しました。楽しみ :)

于 2009-10-27T17:41:08.740 に答える
7

ソーシャルアプリケーションに最適なデザインかどうかはわかりませんが、 jaikuはGoogleに買収されたときに、元の作成者によってApp Engineに移植されたため、妥当なはずです。

Actors and Tigers and Bears、Oh My!のセクションを参照してください。design_funument.txt内。エンティティはcommon/models.pyで定義され、クエリはcommon/api.pyにあります。

于 2009-10-27T19:58:05.813 に答える
1

ロバート、あなたの提案した解決策について:

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])

ndb.TextPropertyの「body」は、インデックスが作成されていないため、プロジェクションでは使用できないと思います。プロジェクションは、インデックス付きのプロパティのみをサポートします。有効な解決策は、MessageとMessageIndexの2つのテーブルを維持することです。

于 2014-04-23T18:49:55.110 に答える
0

これは、NDBの新しいプロジェクションクエリで解決できると思います。

class Message(ndb.Model):
    sender = ndb.StringProperty()
    receivers = ndb.StringProperty(repeated=True)
    body = ndb.TextProperty()

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])

これで、リストプロパティを逆シリアル化するための高額なコストに対処する必要がなくなります。

于 2014-02-17T18:49:18.580 に答える