2013-05-02 48 views
2

我們在2.0開始使用Mongo。作爲我們經常運行的查詢的一部分,我們運行map/reduce作業,這些作業也會在這些作業執行時從其他集合中提取數據。Mongo 2.4 - 使服務器端代碼中的db對象可用(map/reduce)

由於mongo 2.4,此功能被刪除(http://docs.mongodb.org/manual/release-notes/2.4/#additional-limitations-for-map-reduce-and-where-operations),唯一的建議是「重構你的代碼」。

那麼,有沒有一種方法來重構代碼?我知道這是一個普遍的問題,但我要求提供一個通用的應用程序。涉及的集合和交叉查詢的大小和使用具有足夠的多樣性。

在這一點上,我甚至會採取一個補丁,將db對象帶回服務器代碼範圍。看來,下面的補丁就足夠了(是的,我知道它有這些安全隱患,但我還沒有使用的碎片這是最快捷的方式爲我們奪回我們賴以生存的功能。):

diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp 
index 742392f..225a2b7 100644 
--- a/src/mongo/db/commands/mr.cpp 
+++ b/src/mongo/db/commands/mr.cpp 
@@ -623,6 +623,7 @@ namespace mongo { 
     void State::init() { 
      // setup js 
      _scope.reset(globalScriptEngine->getPooledScope(_config.dbname, "mapreduce").release()); 
+   _scope->localConnect(_config.dbname.c_str()); 

      if (! _config.scopeSetup.isEmpty()) 
       _scope->init(&_config.scopeSetup); 
+0

的問題是,由於數據庫對象分片怎麼跑envos這個功能實際上是一個安全漏洞,可能被用來繞過對其他數據庫的認證來攻擊你的數據。至於如何重構你的代碼;你到底在做什麼?你能給我們一些邏輯嗎? – Sammaye 2013-05-02 17:47:51

+0

@Sammaye不要讓我開始這個「安全」的事情。這不是一個修復,它是一個明顯的插件解決方案,而不是正確地重新設計/修復安全架構。我知道我總是可以重構我的查詢,以預先加入客戶端的數據,或將數據預加載到服務器範圍中。但我不想,而且性價比很高。 – 2013-05-02 18:25:15

回答

3

從概念上講,MapReduce只對輸入文檔集和發射值進行操作。嚴格來說,執行數據庫操作超出了MapReduce作業的範圍。有關更改信息的更多信息,請參閱SERVER-8104SERVER-3130

說了那麼,提供的補丁應該可以工作,但我會提醒不要使用它由於鎖定影響(和上述安全問題)。

至於如何重構可能在過去版本中使用過這個特性的代碼的一般化問題,想到的一個建議是使用多個利用'reduce'輸出類型的MapReduce作業。 incremental MapReduce的文檔在這裏可能會有所幫助。

如果目標是服務器端執行,另一個選項可能是將MapReduce邏輯重構爲可以使用db.eval()執行的腳本。由於問題的性質,這可能有點複雜。

+0

謝謝您驗證該修補程序。就我而言,至少在其中的一些中,實際上不可能使用基於map-reduce的連接(與漸進式方法相同)。連接查找可以將關鍵空間從數百萬個值減少到少數。我不相信在'map'函數或客戶端查找關鍵字之間鎖定使用的區別很大。 – 2013-05-03 00:27:48

2

聽起來像你正在描述需要加入2個集合。我在成功的過去做到了這一點,並寫了包括來自data.gov測試數據和cia.gov這裏一個例子:

http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/

有2周要注意的這種方法主要的事情:

  1. 您的集合之間的連接條件將需要是發出的密鑰。
  2. 正在排出的文件的形狀應該是相同的。

然後,它只是一個結合你的reducer發出的文件的問題。這樣做應該在整個碎片上很好地擴展,甚至可以在整個核心上進行本地擴展(請參閱https://jira.mongodb.org/browse/SERVER-4258)。

+0

這是一個很好的伎倆,我從來沒有考慮過它。當我不得不這樣做簡單的連接時,我仍然會使用客戶端連接。但是,我不可能通過鍵入所有m/r的應用程序。 – 2013-05-03 00:19:31

+0

@PawelVeselov問題在於你在兩個表中進行了無用的查找,然後只是將兩個MR的輸出合併爲一個集合,實際上並沒有進行連接,並且也不會獲得任何受限數據集的好處 – Sammaye 2013-05-03 09:52:31

+0

@Sammaye減少地圖的強大功能是映射函數可以固定在輸出中需要的精確鍵上。派生這些密鑰的函數可能相當複雜和精細。但有時(也是@vrtx)這些函數不能被編碼,並且必須查找一些外部數據源。我將這種查找能力看作是任何其他函數使用的邏輯擴展。 – 2013-05-05 06:55:16

0

我知道一些古老的問題,爲了他人的利益在這裏登錄。這適用於2.6.4。

根據您的要求,您仍然可以在mapreduce期間從其他集合中獲取文檔。您可以聲明dbref並從您的收藏中獲取數據。即使文檔說$ id字段需要id,我已經嘗試過標準mongo查詢,似乎正在工作。基於dbref文檔,你也可以指向不同的數據庫,雖然我還沒有嘗試過。

這裏是我從其他兩個集合中獲取數據,並沒有任何共同的字段名稱我的地圖功能的一個簡單的例子

function() { 
var values = { 
    providerAccount: this, 
}; 

if (!(typeof(this['lastStatusLogId']) === 'undefined')) { 

     var v = new Object(); 
     v["$ref"] = "statuslog"; 
     v["$id"] = new ObjectId(this['lastStatusLogId']); 
     values['lastStatusLog'] = v; 
    } 

    v = new Object(); 
    v["$ref"] = "provider"; 
    v["$id"] = new ObjectId(this.providerId); 
    values["provider"] = v; 

    emit(this._id, values); 
    } 
相關問題