Этот бонус-таск базируется на задании https://github.com/spajic/task-4
В исходном задании вы импортировали файлы small.json, medium.json и large.json (1k, 10k и 100k trip-ов).
В этом задании нужно справиться с файлами 1M.json (codename mega) и 10M.json (codename hardcore)
При реализации импорта нужно учесть наши инсайдерские знания о данных:
- первичным ключом для автобуса считаем
(model, number) - уникальных автобусов в файле
10M.json~10_000 - ункикльных городов в файле
10M.json~100 - сервисов ровно
10, те что перечислены вService::SERVICES
Файл 10M.json весит ~ 3Gb.
Поэтому лучше не пытаться грузить его целиком в память и парсить.
Вместо этого лучше читать и парсить его потоково.
Это более-менее привычная схема, но знали ли вы, что в Posgtres тоже можно писать данные потоком?
Вот набросок потокового чтения из файла с потоковой записью в Postgres:
@cities = {}
ActiveRecord::Base.transaction do
trips_command =
"copy trips (from_id, to_id, start_time, duration_minutes, price_cents, bus_id) from stdin with csv delimiter ';'"
ActiveRecord::Base.connection.raw_connection.copy_data trips_command do
File.open(file_name) do |ff|
nesting = 0
str = +""
while !ff.eof?
ch = ff.read(1) # читаем по одному символу
case
when ch == '{' # открывается объект, повышается вложенность
nesting += 1
str << ch
when ch == '}' # закрывается объкет, понижается вложенность
nesting -= 1
str << ch
if nesting == 0 # если закрылся объкет уровня trip, парсим и импортируем его
trip = Oj.load(str)
import(trip)
progress_bar.increment
str = +""
end
when nesting >= 1
str << ch
end
end
end
end
end
def import(trip)
from_id = @cities[trip['from']]
if !from_id
from_id = cities.size + 1
@cities[trip['from']] = from_id
end
# ...
# стримим подготовленный чанк данных в postgres
connection.put_copy_data("#{from_id};#{to_id};#{trip['start_time']};#{trip['duration_minutes']};#{trip['price_cents']};#{bus_id}\n")
end- чистим базу
- идём по большому файлу
- по пути формируем в памяти вспомогательные справочники ограниченного размера (
cities,buses,buses_services) - сразу же стримим основные данные в базу (
trips), чтобы не накапливать их - после завершения файла сохраняем в базу сформированные справочники
- можно использовать любые библиотеки для потоковой обработки
jsonи вообще
Довести до ума потоковый импорт данных.
Начать с отработки на маленьких файлах, оптимизировать до состояния, в котором файл 10M.json импортируется за приемлемое время.
Сделать PR в этот репозиторий, где есть:
- файлы с кодом, выполняющим импорт
- описание процесса оптимизации и результатов