Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 批量查找mongoDB记录(使用mongoid ruby适配器)_Ruby On Rails_Mongodb_Mongoid - Fatal编程技术网

Ruby on rails 批量查找mongoDB记录(使用mongoid ruby适配器)

Ruby on rails 批量查找mongoDB记录(使用mongoid ruby适配器),ruby-on-rails,mongodb,mongoid,Ruby On Rails,Mongodb,Mongoid,使用带有mongoid适配器的rails 3和mongoDB,如何批量查找mongoDB?我需要获取特定mongo DB集合中的所有记录,并在solr(用于搜索的数据初始索引)中对它们进行索引 我遇到的问题是执行Model.all会获取所有记录并将其存储到内存中。然后,当我对它们进行处理并在solr中建立索引时,我的内存被消耗殆尽,这个过程也就结束了 我想做的是在mongo中批量查找,这样我可以一次迭代1000条记录,将它们传递给solr到index,然后处理下一个1000条记录,以此类推 我目

使用带有mongoid适配器的rails 3和mongoDB,如何批量查找mongoDB?我需要获取特定mongo DB集合中的所有记录,并在solr(用于搜索的数据初始索引)中对它们进行索引

我遇到的问题是执行Model.all会获取所有记录并将其存储到内存中。然后,当我对它们进行处理并在solr中建立索引时,我的内存被消耗殆尽,这个过程也就结束了

我想做的是在mongo中批量查找,这样我可以一次迭代1000条记录,将它们传递给solr到index,然后处理下一个1000条记录,以此类推

我目前拥有的代码实现了以下功能:

Model.all.each do |r|
  Sunspot.index(r)
end
对于一个拥有大约150万条记录的集合,这会占用8+GB的内存并终止进程。在ActiveRecord中,有一个find_In_batches方法,允许我将查询分为可管理的批,以防止内存失控。然而,对于mongoDB/mongoid,我似乎找不到类似的东西

我希望能够做到以下几点:

Model.all.in_batches_of(1000) do |batch|
  Sunpot.index(batch)
end

这将减轻我的记忆问题和查询困难,每次只做一个可管理的问题集。然而,在mongoDB中进行批处理查找的文档很少。我看到了很多关于批插入的文档,但没有批查找的文档。

我不确定批处理,但您可以这样做

current_page = 0
item_count = Model.count
while item_count > 0
  Model.all.skip(current_page * 1000).limit(1000).each do |item|
    Sunpot.index(item)
  end
  item_count-=1000
  current_page+=1
end
但是如果你正在寻找一个完美的长期解决方案,我不会推荐这个。让我解释一下我是如何在我的应用程序中处理相同的场景的。而不是做批量作业

  • 我创建了一个更新solr索引的作业

    class SolrUpdator
     @queue = :solr_updator
    
     def self.perform(item_id)
       item = Model.find(item_id)
       #i have used RSolr, u can change the below code to handle sunspot
       solr = RSolr.connect :url => Rails.application.config.solr_path
       js = JSON.parse(item.to_json)
       solr.add js         
     end
    
    结束

  • 添加项目后,我只是将一个条目放入resque队列

    Resque.enqueue(SolrUpdator, item.id.to_s)
    
  • 就这么多,重新开始,一切都会好起来的

使用Mongoid,您无需手动批处理查询。

在Mongoid中,
Model.all
返回一个
Mongoid::Criteria
实例。根据此条件调用
#each
,Mongo驱动程序游标将被实例化并用于迭代记录。此基础Mongo驱动程序游标已批处理所有记录。默认情况下,
批次大小为100

有关此主题的更多信息,请阅读

总之,您可以这样做:

Model.all.each do |r|
  Sunspot.index(r)
end

正如@RyanMcGeary所说,您不需要担心批处理查询。但是,一次索引一个对象要比批处理它们慢得多

Model.all.to_a.in_groups_of(1000, false) do |records|
  Sunspot.index! records
end

向太阳黑子发送批次也会更快。 我就是这样做的:

records = []
Model.batch_size(1000).no_timeout.only(:your_text_field, :_id).all.each do |r|
  records << r
  if records.size > 1000
    Sunspot.index! records
    records.clear
  end
end
Sunspot.index! records
记录=[]
型号。批量大小(1000)。无超时。仅(:您的文本字段,:\u id)。全部。每个都有|
记录1000
太阳黑子指数!记录
记录,清除
结束
结束
太阳黑子指数!记录
无超时
:防止光标断开连接(默认情况下,10分钟后)

:仅选择实际索引的id和字段


batch\u size
:获取1000个条目,而不是100个条目如果在每个记录都需要大量处理(即查询每个项目的外部API)的集合上进行迭代,则光标可能会超时。在这种情况下,您需要执行多个查询,以避免光标处于打开状态

require 'mongoid'

module Mongoid
  class Criteria
    def in_batches_of(count = 100)
      Enumerator.new do |y|
        total = 0

        loop do
          batch = 0

          self.limit(count).skip(total).each do |item|
            total += 1
            batch += 1
            y << item
          end

          break if batch == 0
        end
      end
    end
  end
end

只要确保您的查询中始终有一个order\u by即可。否则,分页可能无法实现您希望的功能。此外,我会坚持批量100或更少。正如在接受答案中所说的,Mongoid查询以100个为一批,因此在处理过程中,您永远不想让光标保持打开状态。

以下内容适用于您,请尝试一下

Model.all.in_groups_of(1000, false) do |r|
  Sunspot.index! r
end

Ramesh,您提供的第一块代码非常适合我的用例。它只是使用脚本文件一次性加载和索引数据,所以对于我的特殊情况,使用resque可能会有点过头。但是批处理功能非常有效!这是没有必要的。Mongoid和底层Mongo驱动程序已经使用游标批处理查询。这将使内存占用空间保持较小。您确定这会导致内存问题吗?Mongoid和底层Mongo驱动程序已经使用游标批处理查询。这样可以减少内存占用。顺便说一句,您应该将已接受的答案更改为@RyanMcGeary的答案-然后您的问题的所有未来访问都将看到正确的答案,并且没有人不会执行驱动程序已经完成的手动优化。感谢@RyanMcGeary提供的信息,天哪,我怎么会错过光标的事情,,,在durran指定的关于批处理大小的链接中,我们如何指定外部…?@Edmund“Hit”可能不是这里使用的最佳词语,因为它意味着每次都要重新运行查询。这是一个数据库游标。想想看,这更像是成批地将数据传输到100个数据中。@RyanMcGeary,你答案中的链接被破坏了。你能编辑/更正吗?@p.matsinopoulos我花了一段时间才找到相同的评论。将近5年了,Mongoid从GitHub问题转向了JIRA问题。我想我找到了合适的注释。对于最新版本中的记录,批大小在内部通常从100开始,然后增加以减少对数据库的调用次数。它的优点还在于,它可以与所有可枚举方法一起使用,因此如果您希望以实际的ruby批处理(如100个数组)获取记录,您可以这样做:
Model.all.each_slice(100){| array |…}
Model.all.to_a
将整个集合加载到内存中。没错,请不要这样做:当我们谈论大型数据集时,避免将整个集合一次性转换为数组:使用
Model.find_each
或batch以任何方式,但决不要
Model.all.to_a
Model.find_each不是Mongoid方法。您将使用Model.all.each代替。请记住“Sunspot.index!”!在循环后记录,否则您不会索引最后一组<1000我相信是正确的。我忘了复制这个部分。crite上的
.no\u timeout
方法
Model.all.in_groups_of(1000, false) do |r|
  Sunspot.index! r
end