2011-02-28 24 views
9

我仍在學習關於bigtable/nosql中的數據建模的經驗教訓,並希望得到一些反饋。 如果我經常需要與父母合計處理子女,那麼我應該在數據建模中避免父母與子女的關係是否公平?appengine python(bigtable)中的parent-> child關係

作爲一個例子,假設我正在構建一個博客,這個博客將由許多作者貢獻,並且彼此有帖子,每個帖子都有標籤。所以我可以設置這樣的東西:

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.StringListProperty() 

據我所知,這將創建一個基於作者父母的實體組。 這是否會導致效率低下,如果我主要需要通過標籤查詢帖子,我希望這些標籤可以跨越多個作者?

我知道在列表屬性上執行查詢可能效率低下。假設每個帖子平均有大約3個標籤,但可以一直達到7個。我希望我的可能標籤收藏數量可以達到數百個。 將此模型改爲這樣的模型有什麼好處嗎?

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.ListProperty(db.Key) 

class Tag(db.Model): 
    name = db.StringProperty() 

不然我就更好做這樣的事情?

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    owner = db.ReferenceProperty(Author, 
    collection_name='posts') 

class Tag(db.Model): 
    name = db.StringProperty() 

class PostTag(db.Model): 
    post = db.ReferenceProperty(Post, 
    collection_name='posts') 
    tag = db.ReferenceProperty(Tag, 
    collection_name='tags') 

而最後一個問題......如果我的最常見的情況將被查詢的內容由多個標籤的帖子。例如,「在{'蘋果','橙子','黃瓜','自行車'}中查找標籤中的所有帖子。」其中一種方法更適合查找具有任何標籤集合的帖子的查詢?

謝謝,我知道這是一口。 :-)

+0

您的示例都不會創建實體組。在第一個例子中,您使用了一個ReferenceProperty,它創建了對另一個實體的引用 - 這是可變的,並不意味着所有權。通過爲實體的構造函數指定「parent」參數來創建父引用 - 有關詳細信息,請參閱此頁:http://code.google.com/appengine/docs/python/datastore/entities.html#Entity_Groups_and_Ancestor_Paths –

+0

啊,謝謝Nick。我錯過了那部分......認爲這是創建父關係的引用,並且缺少了需要將父項傳遞給構造函數的引用。這是有道理的。 –

回答

5

類似於第一種或第二種方法非常適合App Engine。考慮以下設置:

class Author(db.Model): 
    owner = db.UserProperty() 

class Post(db.Model): 
    author = db.ReferenceProperty(Author, 
    collection_name='posts') 
    tags = db.StringListProperty() 

class Tag(db.Model): 
    post_count = db.IntegerProperty() 

如果你使用字符串變量(區分標準化)作爲標籤實體KEY_NAME,可以高效的帖子與特定的標籤查詢,或列出後的標籤,或者取標籤統計:

post = Post(author=some_author, tags=['app-engine', 'google', 'python']) 
post_key = post.put() 
# call some method to increment post counts... 
increment_tag_post_counts(post_key) 

# get posts with a given tag: 
matching_posts = Post.all().filter('tags =', 'google').fetch(100) 
# or, two tags: 
matching_posts = Post.all().filter('tags =', 'google').filter('tags =', 'python').fetch(100) 

# get tag list from a post: 
tag_stats = Tag.get_by_key_name(post.tags) 

第三種方法需要額外的查詢或爲獲取最基本的操作,如果你想查詢多個標籤是比較困難的。

+0

真棒,謝謝羅伯特。這實際上是我寫的。但我還是新手,所以我不確定這是否是最好的方式,所以我感謝您分享您的經驗! –

+1

@Bob Ralian,需要警惕的是爆炸指數。總的概念是好的;你也可能會發現「關係索引」模式很有用,但是因爲你的列表非常小,並且你想要這些標籤,所以你不需要單獨的實體。 (http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html) –

2

我會選擇最後一種方法,因爲它允許直接給定標籤檢索帖子列表。

第一種方法基本上使得不可能保留標準的標籤集合。換句話說,「系統中當前存在哪些標籤」的問題回答非常昂貴。

第二種方法解決了這個問題,但正如我所提到的,不能幫助您檢索給定標籤的帖子。

實體組是有點玄獸,但我只想說第一種方法不會創建一個實體組,他們只用於事務的數據庫操作需要,有時優化數據讀取有用,但可能不需要一個小的應用程序。

應該指出,您採取的任何方法都只能與智能緩存策略結合使用。 GAE應用程序喜歡緩存。熟悉memcache api,學習memcache和數據存儲的批量讀/寫操作。

+0

謝謝三聯。其實我並不擔心這個規範問題,因爲我會在保存之前在驗證過程中處理這個問題。 回覆:實體組,文檔說:「要創建一個組中的實體,你創建它時聲明另一個實體是新實體的父代。」因此,我認爲如果父子關係在創建時在子項上聲明,則它將創建一個實體組。 我明白實體組的意義在於交易。但是它們是否會導致實體組間選擇的延遲/低效?跨組交易可能嗎? –

+0

跨組交易是不可能的,但是如果您在整個實體組中進行了大量選擇,那麼這表示您不應該使用它們。此外,要明白,如果使用第一種方法,則驗證過程將需要讀取數據存儲區中每個Post模型中的每個標記。 – Triptych

+0

無論如何我都會有一個單獨的標記模型。我會把它們保存在memcache中。剛剛纏繞的第一種方法實際上與他們綁定,但會用它們來指定可接受的字符串。對於我通過標籤選擇的帖子來說,這並不一定合適,但是對於像Reader閱讀器偏好這樣的內容,我只需要拉取標籤列表就可以。 –

相關問題