2016-06-28 53 views
4

我竭力尋找解決一個問題,蒙戈DB:的MongoDB - 排序計算字段

我需要運行在高寫一個集合的查詢/讀取率。 該查詢在於通過從屬於同一文檔的其他 字段派生的字段對文檔進行排序。此外,其中一個字段是數組的大小,這使得它更難。

一個簡單的例子:

D1 - { _id: 1, field: 1, array_field: [a,b,c,d] } -> score = 1 + 4 = 5 
D2 - { _id: 2, field: 2, array_field: [a,b] }  -> score = 2 + 2 = 4 

預期結果:

D1 - { _id: 2, score: 4 } 
D2 - { _id: 1, score: 5 } 

(不是在結果所需的分數)

到目前爲止,我已經嘗試瞭解決方案:

  1. A dd將得分作爲文檔的一個字段,這是持續更新其他字段更新。問題:

    • 這是不可能的參數一度將比分已經計算查詢(微調)
    • 它是昂貴的,因爲在比分指數必須非常頻繁地更新
  2. 創建一個聚合管道,使開發變得容易並解決參數化問題。 但是,性能下降真的很高,因爲mongo不能依賴計算字段上的使用索引,導致內存問題(100MB查詢錯誤)。 可能的解決方案是啓用allowDiskUse標誌。但是,查詢將變得太慢。

更新:我想指出的是,查詢將被運行第二個10倍左右。因此,預先計算並將分數存儲在不同的文檔中可能不是一個可行的解決方案。

實際使用:因爲問題非常困難。讓我給你更多的背景。我有一個文章的帖子(如Facebook的帖子)我目前正在按創建日期和上次更新進行排序。我希望能夠按照我所說的分數定義的「熱度」對帖子進行排序。我認爲,計算分數的有趣的方式可能爲:

score = a * likes - b * dislikes + c * num_comments + d * (now - creation_date) 

其中abcd是我的參數可以改變來調整算法。 likesdislikes是參考用戶的ObjectID的數組,而num_comments僅僅是評論的數量。 運行查詢以向REST端點提供響應。沒有進一步的操作:請求 - >查詢 - >響應。

你對派生/聚合字段有任何經驗嗎? 謝謝!

+1

當我遇到類似的問題後,我最終推遲了報告。我創建了一個具有聚合和$ out的新集合,其中沒有其他寫入,因此我可以使用索引來優化它。我不確定這是否是最佳解決方案,但對我有用。 – Tiramisu

回答

0

它看起來像一個複雜的問題。

此查詢將完成這項工作,但我想聽取您的表現。

db.perlz.aggregate([ 
// {$match:{whatever is needed here}} 
     { 
      $project : { 
       _id : 1, 
       score : { 
        $sum : [{ 
          "$size" : "$array_field" 
         }, "$field"] 
       } 
      } 
     }, { 
      $sort : { 
       score : 1 
      } 
     } 

    ]) 

由於這是繁忙的服務器上完成,我會考慮一個副本集的設置,並嘗試通過發行從服務器上某些查詢,以平衡負載。

編輯

按照您的更新,我想知道,如果這些步驟可以適用於這個問題:

  1. 更新文檔結構有兩種類型的喜歡: processednewProcessed就像是被添加到文件得分由工人(這影響likes, dislikes, numComments領域)和設置得分 - 那麼我們需要計算delta/difference價值。

  2. 嘗試基於先前點(預先計算的得分)

  3. 限制輸出到的文獻中已知的量(實施尋呼)

作爲每個動態字段值,以確定最低輸入集 - 獲得得分值不需要大量的計算。可以考慮的是將計算和_id中使用的字段進行投影,然後使用$lookup作爲最後一個階段,並將macz父文檔與得分和排序結果一起使用。

歡迎任何評論!

+0

不幸的是,這就是我所做的。這會導致'100MB查詢錯誤',因爲它無法使用索引進行排序。 –

+0

好的,該輸出過程中的下一步是什麼? – profesor79

+0

我已經更新了更多關於爲什麼我們需要這樣的查詢的上下文的問題。 –