簡體   English   中英

在Ruby中,如何將范圍分成多個塊進行批處理操作?

[英]In Ruby, how do I split a range into chunks for batch operations?

對於您所有的Ruby高爾夫球手和體操運動員來說,這都是一個有趣的小難題。

問題:我有數百萬個SQL數據庫記錄,我需要以相反的ID順序(可能是1000個左右)將它們轉移到NoSql數據庫中(所以find_each不是有效的解決方案)。

這將在小型服務器上運行,因此我不想一次將所有ID都保留在內存中,而只希望將一個ID保留在內存中。

我希望在我的代碼庫中使用以下內容:

chunkify max_id, step_size do |ids|
  copy_to_nosql SqlTable.where(id: ids)
end

你能寫成chunkify嗎?

解決方案不應重復任何ID,它應覆蓋所有ID,第一個產生的數組應包含max_id,返回的最低ID應該為1。

PS。 我正在使用Rails框架,因此可以隨時使用Rails特定的語言增強功能。

PPS。 我不想使用數據庫驅動的解決方案,例如“限制”和“偏移”,至少對於我的數據庫實現而言,隨着偏移量的增加,查詢需要更長的時間來處理。

編輯

這是一個可行的解決方案。 任何提高可讀性,簡潔性或效率的替代方法都受到歡迎:

  # yields arrays of ints (chunks), of [chunk_size] or lower length, which,
  # when added together, would cover all values from 0 to [top_value], exactly
  # once each. The highest value 'chunk' is provided first.
  #
  # > chunkify(100, 10) { |chunk| puts chunk.inspect }
  # [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
  # [81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
  # ...
  # [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  # => 100
  # > chunkify(27, 8) { |chunk| puts chunk.inspect }
  # [20, 21, 22, 23, 24, 25, 26, 27]
  # [12, 13, 14, 15, 16, 17, 18, 19]
  # [4, 5, 6, 7, 8, 9, 10, 11]
  # [1, 2, 3]
  # => 27
  def chunkify(top_value, chunk_size)
    top_value.step(1, -chunk_size) do |i|
      yield ((i-chunk_size > 0 ? i-chunk_size+1 : 1)...i+1).to_a
    end
  end

您是否正在尋找像這樣簡單的東西?

def chunkify(max_val,chunk_size);
  max_val.downto(1).each_slice(chunk_size) {|chunk| yield chunk.reverse }
end 

chunkify(100,10) {|c| puts c.inspect }
  #[91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
  #[81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
  #[71, 72, 73, 74, 75, 76, 77, 78, 79, 80]
  #[61, 62, 63, 64, 65, 66, 67, 68, 69, 70]
  #[51, 52, 53, 54, 55, 56, 57, 58, 59, 60]
  #[41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
  #[31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
  #[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
  #[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
  #[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  #=> nil

正如@SergioTulentsev指出的那樣,這似乎微不足道。

而且,由於SQL並不關心IN()子句的順序,所以反向操作的效率較低,並且效果與遞減順序相同。

ActiveRecord提供了find_each方法,可用於加載小批量記錄並在結果集上執行特定操作。

循環遍歷數據庫中的記錄集合(例如,使用all方法)效率很低,因為它將嘗試立即實例化所有對象。

在這種情況下,批處理方法使您可以批量處理記錄,從而大大減少了內存消耗。

find_each方法使用批處理大小為1000 (或由:batch_size選項指定)的find_in_batches

您可能要向必須遷移的列中添加一個新的布爾字段,以確保您將查詢過濾掉,只查找processed為假的記錄。 這樣,即使進程由於某種原因而終止,您也可以恢復它,並且它不會從頭開始。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM