6

我剛剛看過Batch data processing with App Engine session of Google I/O 2010,閱讀MapReduce article from Google Research的某些部分,現在我想用MapReduce on Google App Engine來實現Python中的推薦系統。MapReduce在Google App Engine中的多個數據存儲種類

我更喜歡使用appengine-mapreduce而不是Task Queue API,因爲前者提供了對某種類型的所有實例,自動批處理,自動任務鏈等的簡單迭代。問題是:我的推薦系統需要計算實例之間的關聯兩種不同的模型,即兩種不同類型的實例。

例如: 我有這兩個模型:用戶和項目。每個人都有一個標籤列表作爲屬性。以下是計算用戶和項目之間相關性的函數。需要注意的是calculateCorrelation應要求用戶和項目的每個組合:

def calculateCorrelation(user, item): 
    return calculateCorrelationAverage(u.tags, i.tags) 

def calculateCorrelationAverage(tags1, tags2): 
    correlationSum = 0.0 
    for (tag1, tag2) in allCombinations(tags1, tags2): 
     correlationSum += correlation(tag1, tag2) 
    return correlationSum/(len(tags1) + len(tags2)) 

def allCombinations(list1, list2): 
    combinations = [] 
    for x in list1: 
     for y in list2: 
      combinations.append((x, y)) 
    return combinations    

但這calculateCorrelation是不是在AppEngine上-MapReduce的一個有效的映射,也許這個功能是不是即使MapReduce計算概念相兼容。然而,我需要確定的是,對於我擁有像自動批處理和任務鏈這樣的appengine-mapreduce優勢,這將非常棒。

有沒有解決方案?

我應該定義我自己的InputReader嗎?一個新的讀取兩種不同類型的所有實例的InputReader與當前的appengine-mapreduce實現兼容嗎?

或者我應該嘗試以下方法嗎?

  • 由兩個結合所有鍵這兩個類型的所有實體,二,成(MapReduce的可能使用)一個新的模型的實例
  • 迭代使用映射器在這種新的模式
  • 的情況下,對於每個實例中,使用其中的鍵來獲取不同種類的兩個實體並計算它們之間的相關性。
+0

標準是什麼在用戶和項目通過呢?它是用戶和項目的每個組合嗎?只是那些以某種方式相關的?另外,那是什麼語言?這不是(完全)Python! – 2010-09-24 10:26:34

+0

應爲每個用戶和項目的組合調用'calculateCorrelation'。現在我刪除了各種變量以避免混淆。 – fjsj 2010-09-24 17:34:53

回答

3

按照Nick Johnson的建議,我寫了自己的InputReader。這個閱讀器從兩種不同的類型獲取實體。它產生具有這些實體的所有組合的元組。那就是:當你需要處理2種實體的所有組合

class TwoKindsInputReader(InputReader): 
    _APP_PARAM = "_app" 
    _KIND1_PARAM = "kind1" 
    _KIND2_PARAM = "kind2" 
    MAPPER_PARAMS = "mapper_params" 

    def __init__(self, reader1, reader2): 
     self._reader1 = reader1 
     self._reader2 = reader2 

    def __iter__(self): 
     for u in self._reader1: 
      for e in self._reader2: 
       yield (u, e) 

    @classmethod 
    def from_json(cls, input_shard_state): 
     reader1 = DatastoreInputReader.from_json(input_shard_state[cls._KIND1_PARAM]) 
     reader2 = DatastoreInputReader.from_json(input_shard_state[cls._KIND2_PARAM]) 

     return cls(reader1, reader2) 

    def to_json(self): 
     json_dict = {} 
     json_dict[self._KIND1_PARAM] = self._reader1.to_json() 
     json_dict[self._KIND2_PARAM] = self._reader2.to_json() 
     return json_dict 

    @classmethod 
    def split_input(cls, mapper_spec): 
     params = mapper_spec.params 
     app = params.get(cls._APP_PARAM) 
     kind1 = params.get(cls._KIND1_PARAM) 
     kind2 = params.get(cls._KIND2_PARAM) 
     shard_count = mapper_spec.shard_count 
     shard_count_sqrt = int(math.sqrt(shard_count)) 

     splitted1 = DatastoreInputReader._split_input_from_params(app, kind1, params, shard_count_sqrt) 
     splitted2 = DatastoreInputReader._split_input_from_params(app, kind2, params, shard_count_sqrt) 
     inputs = [] 

     for u in splitted1: 
      for e in splitted2: 
       inputs.append(TwoKindsInputReader(u, e)) 

     #mapper_spec.shard_count = len(inputs) #uncomment this in case of "Incorrect number of shard states" (at line 408 in handlers.py) 
     return inputs 

    @classmethod 
    def validate(cls, mapper_spec): 
     return True #TODO 

此代碼應被使用。你也可以概括這兩種以上。

這是一個有效的TwoKindsInputReader的mapreduce.yaml:

mapreduce: 
- name: recommendationMapReduce 
    mapper: 
    input_reader: customInputReaders.TwoKindsInputReader 
    handler: recommendation.calculateCorrelationHandler 
    params: 
    - name: kind1 
     default: kinds.User 
    - name: kind2 
     default: kinds.Item 
    - name: shard_count 
     default: 16 
2

很難知道推薦的內容,而無需詳細說明您實際計算的內容。一個簡單的選擇是簡單地在地圖調用中獲取相關實體 - 沒有什麼能夠阻止您在那裏進行數據存儲操作。

雖然這會導致很多小的調用。正如您所建議的那樣,編寫一個自定義的InputReader將允許您並行獲取兩組實體,這將顯着提高性能。

如果您提供有關如何加入這些實體的更多詳細信息,我們可能會提供更具體的建議。

+0

只需添加更多信息! – fjsj 2010-09-23 19:15:13

相關問題