首頁  >  問答  >  主體

python - mongodb 去重

爬取了一个用户的论坛数据,但是这个数据库中有重复的数据,于是我想把重复的数据项给去掉。数据库的结构如下

里边的forundata是这个帖子的每个楼层的发言情况。
但是因为帖子爬取的时候有可能重复爬取了,我现在想根据里边的urlId来去掉重复的帖子,但是在去除的时候我想保留帖子的forumdata(是list类型)字段中列表长度最长的那个。
用mongodb的distinct方法只能返回重复了的帖子urlId,都不返回重复帖子的其他信息,我没法定位。。。假如重复50000个,那么我还要根据这些返回的urlId去数据库中find之后再在mongodb外边代码修改吗?可是即使这样,我发现运行的时候速度特别慢。
之后我用了group函数,但是在reduce函数中,因为我要比较forumdata函数的大小,然后决定保留哪一个forumdata,所以我要传入forumdata,但是有些forumdata大小超过了16M,导致报错,然后这样有什么解决办法吗?
或者用第三种方法,用Map_reduce,但是我在map-reduce中的reduce传入的forumdata大小限制竟然是8M,还是报错。。。

代码如下
group的代码:

reducefunc=Code(
    'function(doc,prev){'
    'if (prev==null){'
    'prev=doc'
    '}'
    'if(prev!=null){'
    'if (doc.forumdata.lenth>prev.forumdata.lenth){'
    'prev=doc'
    '}'
    '}'
    '}'
                )

map_reduce的代码:


reducefunc=Code(
    'function(urlId,forumdata){'
    'if(forumdata.lenth=1){'
    'return forumdata[0];'
    '}'
    'else if(forumdata[0].lenth>forumdata[1].lenth){'
    'return forumdata[0];'
    '}'
    'else{'
    'return forumdata[1]}'
    '}'
                )
mapfunc=Code(
    'function(){'
    'emit(this.urlId,this.forumdata)'
    '}'
)

望各位高手帮我看看这个问题该怎么解决,三个方案中随便各一个就好,或者重新帮我分析一个思路,感激不尽。
鄙人新人,问题有描述不到位的地方请提出来,我会立即补充完善。

怪我咯怪我咯2741 天前952

全部回覆(3)我來回復

  • 黄舟

    黄舟2017-04-18 10:34:12

    如果這個問題還沒解決,不妨參考下面的想法:

    1、MongoDB中推薦使用aggregation,不建議使用map-reduce;

    2、您的需求中,很重要的一點是取得Forumdata的長度:陣列的長度,從而找到陣列長度最長的document。您原文說Forumdata是列表(在MongoDB中應該是陣列);MongoDB提供了$size運算符號取得陣列的大小。

    請參考下面的栗子:

    > db.data.aggregate([ {$project : { "_id" : 1, "name" : 1, "num" : 1, "length" : { $size : "$num"}}}])
    { "_id" : ObjectId("58e631a5f21e5d618900ec20"), "name" : "a", "num" : [ 12, 123, 22, 34, 1 ], "length" : 5 }
    { "_id" : ObjectId("58e631a5f21e5d618900ec21"), "name" : "b", "num" : [ 42, 22 ], "length" : 2 }
    { "_id" : ObjectId("58e631a7f21e5d618900ec22"), "name" : "c", "num" : [ 49 ], "length" : 1 }

    3、有了上面的資料後,然後可以利用aggregation中的$sort,$group等找到滿足您的需求的Document的objectId,具體做法可以參考下面的帖子:

    https://segmentfault.com/q/10...

    4、最後批次刪除相關的ObjectId

    類似於:
    var dupls = [] 保存要刪除的objectId
    db.collectionName.remove({_id:{$in:dupls}})

    供參考。

    Love MongoDB! Have Fun!


    戳我<--請戳左邊,就在四月! MongoDB中文社群深圳用戶大會開始報名囉!大神雲集!

    回覆
    0
  • 迷茫

    迷茫2017-04-18 10:34:12

    資料量的規模不是很大的話可以考慮重新爬取一次,每次存的時候查詢一下,只存資料最多的一組資料。
    優秀的爬蟲策略>>優秀的資料清洗策略

    回覆
    0
  • PHPz

    PHPz2017-04-18 10:34:12

    感謝各位網友,在qq群中,有人給出了思路,是在map的是先以urlId對forumdata進行處理,返回urlId和forumdatad.length,之後再在reduce中處理,保留forumdata.length最大的那個和對應的urlId,最後保存成一個資料庫,之後透過這個資料庫中的urlId來從原始資料庫中將所有資料讀取出來。我試過了,雖然效率不是我期望的那種,不過速度還是比以前用python處理快了不少。
    附上map和reduce的程式碼:
    '''javaScript
    mapfunc=Code(

    'function(){'
    'data=new Array();'
    'data={lenth:this.forumdata.length,'
    'id:this._id};'
    # 'data=this._id;'
    'emit({"id":this.urlId},data);'
    '}'
    )
    

    reducefunc=Code(

    'function(tieziID,dataset){'
    'reduceid=null;'
    'reducelenth=0;'
    ''
    ''
    'redecenum1=0;'
    'redecenum2=0;'
    ''
    'dataset.forEach(function(val){'
    'if(reducelenth<=val["lenth"]){'
    'reducelenth=val["lenth"];'
    'reduceid=val["id"];'
    'redecenum1+=1;'
    '}'
    'redecenum2+=1;'
    '});'
    'return {"lenth":reducelenth,"id":reduceid};'
    '}'
                )
    上边是先导出一个新的数据库的代码,下边是处理这个数据库的代码:
    

    mapfunc=Code(

    'function(){'
    # 'data=new Array();'
    'lenth=this.forumdata.length;'
    ''
    'emit(this.urlId,lenth);'
    '}'

    )

    reducefunc=Code(

    'function(key,value){'
    'return value;'
    '}'

    )

    之后添加到相应的map_reduce中就行了。
    感觉Bgou回答的不错,所以就选他的答案了,还没有去实践。上边是我的做法,就当以后给遇到同样问题的人有一个参考。
    

    回覆
    0
  • 取消回覆