2013-01-07 78 views
4

我有對象的集合至少X值,每個具有場稱爲指紋,其包含20個散列:查找條目,其中陣列A包含從陣列乙

{ 
    title: 'The Chronicles of Narnia', 
    authors: ['C.S. Lewis'], 
    fingerprint: ['50e...', 'ae2...', ...] 
} 

我然後有另外20的查詢指紋哈希值。我想要做的是找到至少共享X哈希的所有條目。換句話說,兩個陣列的交集必須是一定的大小。

我有一個使用MySQL的類似系統的舊實現。有查詢看起來是這樣的:

SELECT * 
FROM Document d 
INNER JOIN Fingerprint f 
    ON d.id = f.document_id 
WHERE f.whorl IN (:hashes) 
GROUP BY d.id 
HAVING COUNT(d.id) >= X 

Fingerprint表中的每個條目包含文檔ID和指紋單螺紋。每個文檔將有Fingerprint 20條目。

據我瞭解,這個查詢正在做什麼是每當一個螺紋匹配時複製文檔,然後按獨特的文檔分組。這看起來有些浪費,但它有效。

我想在MongoDB中重新實現這個系統,但我沒有太多的運氣。我能得到的所有條目的列表共享至少一個或所有的旋渦:

at least one: db.objects.find({ fingerprint: {$in: [hashes]}) 
     all: db.objects.find({ fingerprint: {$all: [hashes]}) 

而且我明白,我可以在應用層掃描此列表中找到我之後的比賽。如果我預計數以百萬計的對象(目前大約150萬),那麼這似乎是一個壞主意。

我已經看過了aggregate()功能,但對我已經無法改進:

db.objects.aggregate({$match: {fingerprint: {$in: [hashes]}}}) 

在這裏,我想我能集團和過濾:

db.objects.aggregate({$match: {fingerprint: {$in: [hashes]}}}, 
        {$group: {_id: "$_id", matches: {$sum: 1}}}) 

在這裏,我是試圖複製MySQL查詢所做的事情:爲每個匹配發出一個文檔,然後對這些文檔進行計數。當然,這裏我們只發一次文件,不管有多少比賽。

然後我想到$unwind匹配的列表,但每次產生20個文件。

理想的情況下,會有一個$some運營商,我可以用這樣的:

db.objects.find(fingerprint: {$some: {from: [hashes], count: X}}) 

是這樣的可能,高效的什麼?我希望能夠響應用戶的搜索來運行這些查詢,所以我認爲MapReduce不存在問題?

感謝

+0

你非常接近找到自己的答案 - 關鍵是先放棄$展開,然後匹配,重新組合再次匹配。 –

回答

5

這其實很簡單,你想和聚合框架是什麼。我相信你可以細化以下幾點來完成你需要的東西:

db.objects.aggregate([ 
    {$unwind : "$fingerprint" }, 
    {$match : {fingerprint : {$in: [hashes] } } }, 
    {$group : {_id:"$title", numMatches: {$sum:1} } }, 
    {$match : {numMatches : {$gt: X} } } 
]) 
+0

我剛剛從幾年前收到關於此問題的另一個答案的通知。非常抱歉,因爲當時沒有將您的答案標記爲正確。我現在已經這麼做了...... – WilliamMayor

+0

不用擔心 - 比從未更好的遲到!:) –