programing

mongoDB 레코드 일괄 찾기(mongoid 루비 어댑터 사용)

topblog 2023. 5. 23. 21:18
반응형

mongoDB 레코드 일괄 찾기(mongoid 루비 어댑터 사용)

mongoid 어댑터와 함께 레일 3 및 mongoDB를 사용하여 mongo DB를 일괄 검색하려면 어떻게 해야 합니까?특정 mongo DB 컬렉션의 모든 레코드를 가져와 solr(검색을 위한 데이터의 초기 인덱스)로 인덱싱해야 합니다.

제가 겪고 있는 문제는 모델을 하는 것입니다.모두가 모든 기록을 수집하여 메모리에 저장합니다.그리고 나서 제가 그것들을 처리하고 솔라 색인을 작성할 때, 제 기억은 다 소모되고 그 과정은 사라집니다.

제가 하려는 것은 mongo에서 발견한 것을 일괄 처리해서 한 번에 1,000개 이상의 레코드를 반복해서 솔러 인덱스에 전달하고 다음 1,000개를 처리하는 것입니다.

제가 현재 가지고 있는 코드는 다음과 같습니다.

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

약 150만 개의 레코드가 있는 컬렉션의 경우 8GB 이상의 메모리를 소비하고 프로세스를 중단합니다.ActiveRecord에는 find_in_batchs 메서드가 있어 쿼리를 관리 가능한 배치로 청크업하여 메모리를 제어할 수 없게 합니다.하지만 mongoDB/mongoid에 대해서는 이런 것을 찾을 수 없을 것 같습니다.

저는 다음과 같은 일을 할 수 있기를 바랍니다.

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

그러면 매번 관리 가능한 문제 세트만 수행하여 메모리 문제와 쿼리 문제를 완화할 수 있습니다.그러나 mongoDB에서 배치 찾기를 수행하는 경우에는 설명서가 거의 없습니다.배치 삽입을 수행하는 것에 대한 문서는 많이 볼 수 있지만 배치 찾기는 그렇지 않습니다.

Mongoid를 사용하면 쿼리를 수동으로 배치할 필요가 없습니다.

Mongoid에서,Model.all를 반환합니다.Mongoid::Criteria사례.부르면 바로#each이 기준에서 Mongo 드라이버 커서는 인스턴스화되어 레코드를 반복하는 데 사용됩니다.이 기본 Mongo 드라이버 커서는 이미 모든 레코드를 배치합니다.기본적으로batch_size100입니다.

이 항목에 대한 자세한 내용은 Mongoid 작성자유지 관리자의 설명을 참조하십시오.

요약하면 다음과 같은 작업을 수행할 수 있습니다.

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

각 레코드가 많은 처리(즉, 각 항목에 대한 외부 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

다음은 배치 기능을 추가하는 데 사용할 수 있는 도우미 방법입니다.다음과 같이 사용할 수 있습니다.

Post.all.order_by(:id => 1).in_batches_of(7).each_with_index do |post, index|
  # call external slow API
end

항상 문의 사항에 대한 주문_by가 있는지 확인하십시오.그렇지 않으면 페이징이 사용자가 원하는 대로 수행되지 않을 수 있습니다.또한 저는 100개 이하의 배치를 고수할 것입니다.승인된 답변에서 언급한 것처럼 Mongoid는 100개의 묶음으로 쿼리하므로 처리하는 동안 커서를 열어두고 싶지 않습니다.

태양 흑점에도 배치를 보내는 것이 더 빠릅니다.이렇게 해야 합니다.

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

no_timeout이 끊어지지 .

only합니다.

batch_size100100$ 대신 의 항목을 . 1000$ 대 가 져 오 기

배치 처리에 대해서는 잘 모르겠지만, 당신은 이 방법으로 할 수 있습니다.

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

하지만 완벽한 장기 솔루션을 찾고 있다면 추천하지 않을 것입니다.제 앱에서 동일한 시나리오를 어떻게 처리했는지 설명하겠습니다.일괄 작업을 하는 대신,

  • 솔러 인덱스를 업데이트하는 레스크 작업을 만들었습니다.

    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.enqueue(SolrUpdator, item.id.to_s)
    
  • 이상입니다, 레스크를 시작하면 모든 것을 처리할 것입니다.

@Ryan McGeary가 말했듯이, 당신은 쿼리를 일괄 처리하는 것에 대해 걱정할 필요가 없습니다.그러나 개체를 한 번에 하나씩 인덱싱하는 것은 개체를 배치하는 것보다 훨씬 느립니다.

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

다음 사항이 도움이 될 것입니다. 사용해 보십시오.

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

언급URL : https://stackoverflow.com/questions/7041224/finding-mongodb-records-in-batches-using-mongoid-ruby-adapter

반응형