0

在我的架構,如在下面的測試數據生成爲例進行說明,我想知道一個好辦法:取消引用模型

取消引用具有參考鍵圖片的情況下,收藏夾的所有實例已被刪除。只需刪除鏈接到已刪除圖片的任何收藏夾即可。

  • Person類是用戶

  • Picture類的東西,可以是一個最喜歡的

  • Favourite類是具有多對一的鏈路模型方式的例子多種關係。

爲什麼這個問題? 首先,我希望它不會超出範圍,第二,因爲這可能發生,第三,因爲它很有趣。

如何? 假設一個人可以擁有多達數千的收藏夾,比如喜歡社交網絡或使其變得更糟,科學應用程序中的訂單,帳戶或無效數據。 在我們的例子中,出於某種原因(以及這些原因發生),一個人正在經歷很多死亡的最愛鏈接,或者我知道,有死的最愛。

什麼是做到這一點的好辦法,減少ndb.get()操作和不是通過每一個迭代收藏

讓事情不會變得複雜。讓我們假設我們有只有一個用戶遭受死的最愛。他有一類Person和被存根的user_id屬性'123'。

在以下示例中,您可以使用以下處理程序及其相應功能。

import time 
import sys 
import logging 
import random 
import cgi 
import webapp2 

from google.appengine.ext import ndb 


class Person(ndb.Expando): 
    pass 

class Picture(ndb.Expando): 
    pass 

class Favourite(ndb.Expando): 
    user_id = ndb.StringProperty(required=True) 
    #picture = ndb.KeyProperty(kind=Picture, required=True) 
    pass 

class GenerateDataHandler(webapp2.RequestHandler): 

    def get(self): 
     try: 
      number_of_models = abs(int(cgi.escape(self.request.get('n')))) 
     except: 
      number_of_models = 10 
      logging.info("GET ?n=parameter not defined. Using default.") 
      pass 
     user_id = '123' #stub 
     person = Person.query().filter(ndb.GenericProperty('user_id') == user_id).get() 
     if not person: 
      person = Person() 
      person.user_id = user_id #Stub 
      person.put() 
      logging.info("Created Person instance") 
     if not self._gen_data(person, number_of_models): 
      return 
     self.response.write("Data generated successfully") 

    def _gen_data(self, person, number_of_models): 
     first, last = Picture.allocate_ids(number_of_models) 
     picture_keys = [ndb.Key(Picture, id) for id in range(first, last+1)] 
     pictures = [] 
     favourites = [] 
     for picture_key in picture_keys: 
      picture = Picture(key=picture_key) 
      pictures.append(picture) 
      favourite = Favourite(parent=person.key, 
          user_id=person.user_id, 
          picture=picture_key 
         ) 
      favourites.append(favourite) 
     entities = favourites 
     entities[1:1] = pictures 
     ndb.put_multi(entities) 
     return True 

class CorruptDataHandler(webapp2.RequestHandler): 

    def get(self): 
     if not self._corrupt_data(0.5):#50% corruption 
      return 
     self.response.write("Data corruption completed successfully") 

    def _corrupt_data(self, n): 
     picture_keys = Picture.query().fetch(99999, keys_only=True) 
     random_picture_keys = random.sample(picture_keys, int(float(len(picture_keys))*n)) 
     ndb.delete_multi(random_picture_keys) 
     return True 

class FixDataHandler(webapp2.RequestHandler): 

    def get(self): 
     user_id = '123' #stub 
     person = Person.query().filter(ndb.GenericProperty('user_id') == user_id).get() 
     self._dereference(person) 

    def _dereference(self, person): 
    #Here if where you implement your answer 

由於最終一致性在 的NDB數據存儲的獨立的處理程序。更多信息: GAE put_multi() entities using backend NDB

當然,我發佈了一個答案,以表明我在發佈之前嘗試了一些東西。

回答

1

ReferenceProperty只是一個鍵,所以如果你有被刪除Person的鍵,你可以用它來查詢Favorite。

否則,有沒有簡單的方法。您必須通過所有收藏夾篩選並找到具有無效圖片的圖片。這在mapreduce作業中非常簡單,但是如果您有很多收藏夾,則可能是一個昂貴的查詢。

+0

是的,如果收藏夾是一個小的非昂貴的數字迭代是最佳的方式。但是如果你有50000收藏夾和99999圖片呢? –

+0

您必須通過50000個收藏夾進行過濾。對於每個收藏夾,檢查圖片,如果無效,請刪除收藏夾。是的,這最終導致成本高達10萬實體提取。如果這是罕見的(例如每月一次或更少)清理操作,那並不是那麼昂貴。無論如何,當你刪除Person和Picture實體時,你應該清理收藏夾,所以你不需要依賴這個掃描和清理。 – dragonx

+0

如果你正在尋找一個更便宜的方法來做到這一點......它不存在(除了預防方法)。你可以做的最好的事情是,當他們已經被訪問時(比如用戶正在加載頁面),檢查'dead'收藏夾,然後清理它。那麼你可能不需要額外的努力來閱讀實體,只是爲了清理的目的。 – dragonx

1

你可以使用預先刪除鉤(看here一種方式來實現它) 當然,如果你使用的NDB API,而不是數據存儲API(hooks on NDB)的可以這樣做更容易,但那麼你就必須改變你做參考的方式

+0

謝謝Nizz ;-)。我會測試和報告。 –

+0

嗯,是的,它只有幫助防止錯誤的鏈接。如果腐敗已經存在,該怎麼辦..... –

+0

我想不出一種便宜的方法來做到這一點。這就是爲什麼預防這種情況會更好......唯一可行的方法就是在出現錯誤時處理錯誤,例如嘗試/除外語句,您將在try塊中加載部分,並在except塊中加載修復。 – nizz