2010-02-11 52 views
3

考慮一個允許用戶評論歌曲的GAE(python)應用程序。預期用戶數量爲1,000,000+。預計的歌曲數量是5000。如何計算Google App Engine中多對多關係的雙方

應用程序必須能夠:

  • 給歌曲的用戶已經對
  • 評論數給誰有一首歌

計數器管理必須評論的用戶數是事務性的,以便它們始終反映基礎數據。

看起來,GAE應用程序必須始終保持這些計數類型的計數,因爲在請求時查詢它們將是低效的。

我的數據模型

class Song(BaseModel): 
    name = db.StringProperty() 
    # Number of users commenting on the song 
    user_count = db.IntegerProperty('user count', default=0, required=True) 
    date_added = db.DateTimeProperty('date added', False, True) 
    date_updated = db.DateTimeProperty('date updated', True, False) 

class User(BaseModel): 
    email = db.StringProperty() 
    # Number of songs commented on by the user 
    song_count = db.IntegerProperty('song count', default=0, required=True) 
    date_added = db.DateTimeProperty('date added', False, True) 
    date_updated = db.DateTimeProperty('date updated', True, False) 

class SongUser(BaseModel): 
    # Will be child of User 
    song = db.ReferenceProperty(Song, required=True, collection_name='songs') 
    comment = db.StringProperty('comment', required=True) 
    date_added = db.DateTimeProperty('date added', False, True) 
    date_updated = db.DateTimeProperty('date updated', True, False) 

代碼
此處理用戶的歌曲算事務而不是歌曲的用戶數。

s = Song(name='Hey Jude') 
s.put() 

u = User(email='[email protected]') 
u.put() 

def add_mapping(song_key, song_comment, user_key): 
    u = User.get(user_key) 

    su = SongUser(parent=u, song=song_key, song_comment=song_comment, user=u); 
    u.song_count += 1 

    u.put() 
    su.put() 

# Transactionally add mapping and increase user's song count 
db.run_in_transaction(add_mapping, s.key(), 'Awesome', u.key()) 

# Increase song's user count (non-transactional) 
s.user_count += 1 
s.put() 

的問題是:我怎樣才能事務管理兩個計數器?

基於我的理解,這將是不可能的,因爲用戶,歌曲和SongUser必須是相同的entity group的一部分。他們不能在一個實體組中,因爲那時我的所有數據都將在一個組中,並且不能由用戶分配。

回答

1

你真的不應該擔心處理用戶在交易中評論過的歌曲的數量,因爲用戶似乎不太可能一次對多首歌曲發表評論,對嗎?

現在,很多用戶可能一次對同一首歌曲發表評論,因此您必須擔心確保數據不會因競爭條件而失效。但是,如果您保留在Song實體中評論歌曲的用戶數量,並用事務鎖定實體,則您將爭奪該實體的非常高的爭用,並且數據存儲超時將會使你的應用程序有很多問題。

此問題的答案是。

爲了確保您可以創建一個新的SongUser實體並更新相關樂曲的分片計數器,您應該考慮讓SongUser實體將相關樂曲作爲父項。這將把他們放在同一個實體組中,你可以創建SongUser並在同一個事務中更新分片計數器。 SongUser與創建它的用戶的關係可以保存在ReferenceProperty中。

關於您對兩個更新(事務型和用戶更新)的關注並非都成功,這總是可能的,但是如果更新可能失敗,則需要進行適當的異常處理以確保都成功了。這是一個重要的觀點:事務內更新不保證成功。如果交易因任何原因無法完成,您可能會收到TransactionfailedError異常。

因此,如果您的事務完成而不引發異常,請在事務中運行用戶更新。如果出現一些錯誤,這將使您自動重新嘗試更新到用戶。除非我對用戶實體有可能的爭論有些不明白之處,否則它最終不會成功的可能性是超越小型。如果這是一個不可接受的風險,那麼我認爲那個AppEngine沒有爲你解決這個問題的完美解決方案。

首先問問自己:如果某人評論過的歌曲數量已經減少了一個,這真的很糟嗎?這與更新銀行賬戶餘額或完成股票銷售一樣重要嗎?

+0

您的解決方案可以減少爭用,但我真正想要做的是確保兩個計數器都匹配底層'SongUser'記錄。如果我使用'Song'實體的分片計數器,那麼當創建'SongUser'時仍然可以成功,並且增加歌曲的計數器失敗(反之亦然)。 – cope360 2010-02-11 15:09:59

+0

已注意。我更新了我的答案以反映您的擔憂。 – 2010-02-11 15:55:43

+0

我認爲最後一段中的解決方案可能是GAE限制中的最佳選擇。在那個解決方案中,我們翻轉了我第一個評論的例子。例如,現在可以更新/創建樂曲計數器和SongUser記錄,但用戶記錄更新失敗(反之亦然)。你是否同意不可能更新兩個計數器(分片還是不分片)? – cope360 2010-02-11 17:34:44

相關問題