Дедупликация 200 ты...
 
Уведомления
Очистить всё

Дедупликация 200 тысяч строк идёт двадцать минут. Что не так с циклом?

5 Сообщения
4 Пользователи
5 Реакции
529 Просмотры
Виктор1987
Сообщения: 3
Автор темы
Пишет в irb data engineer
Присоединился: 2 года назад
[#77]

Перед загрузкой в ClickHouse чищу выгрузку от дублей по паре клиент + дата. На 10 тысячах строк всё было мгновенно, на 200 тысячах скрипт крутится минут двадцать, процессор в сотку, память в норме. Ruby 3.4.

seen = []
unique = []

rows.each do |row|
  key = [row["client_id"], row["event_date"]]
  next if seen.include?(key)

  seen << key
  unique << row
end

Подозреваю include?, но хочу понять, как это правильно делается в Ruby, а не тащить привычки из Python.


4 ответа
TimurK62
Сообщения: 31
Читает чужие PR бэкенд-разработчик
Присоединился: 3 года назад

Да, include? каждый раз проходит массив целиком, на 200 тысячах это квадрат. Нужен Set и его add?, который возвращает nil для уже виденного элемента:

require "benchmark"

seen = Set.new
Benchmark.realtime do
  rows.select { |row| seen.add?([row["client_id"], row["event_date"]]) }
end
# массив и include?: 1184 с
# Set#add?:          0,21 с

Замерил на 200 тысячах сгенерированных строк с 15% дублей. require "set" с Ruby 3.2 не нужен.


Ответ
kirill_spb
Сообщения: 27
Собрал свой gem разработчик инструментов
Присоединился: 4 года назад

Можно и в одну строку: rows.uniq { |r| r.values_at("client_id", "event_date") }. Внутри тоже хэш, а читается проще


Ответ
artem_67
Сообщения: 18
Пишет тесты разработчик на Go
Присоединился: 4 года назад

В Python со списком вместо set будет ровно та же картина, язык ни при чём. Хотя в Go я бы сразу взял map со struct-ключом и не задумывался)


Ответ
TimurK62
Сообщения: 31
Читает чужие PR бэкенд-разработчик
Присоединился: 3 года назад

kirill_spb, uniq с блоком у меня вышел 0,24 с против 0,21 у add?, это в пределах шума. Я бы тоже взял uniq, он понятнее.


Ответ