ETL Pipeline: JSON to PostgreSQL

Наш фундамент (схема базы данных в PostgreSQL) успешно заложен. Теперь мы переходим ко второму этапу — написанию скрипта (ETL Pipeline), который прочитает 140 000 JSON файлов с партиями и загрузит их в нашу базу.

User Review Required

IMPORTANT

Мне нужно знать точный путь к директории (или ZIP-архиву) на твоем Mac, где сейчас физически лежат эти 140 000 JSON файлов. Во время поиска я нашел только несколько тестовых файлов в dicechess-lab.

Open Questions

  1. Формат JSON: Я посмотрел на benchmark_games.json в репозитории dicechess-lab. Я вижу, что там ходы лежат в gameMoveHistoryStateMap и для каждого микро-хода записан полный FEN и брошенные кубики. Является ли этот формат абсолютно идентичным для всех 140 000 партий, которые ты скачал с сайта?
  2. Пакетная вставка (Batching): Для скорости импорта мы будем использовать пакетную вставку (batch inserts) по 1000 партий за раз. Это займет некоторое время. У нас будет прогресс-бар в консоли. Согласен ли ты на использование библиотеки tqdm для красивого вывода прогресса?

Proposed Changes

Мы создадим Python скрипт src/importer.py (или src/etl/import_games.py), который будет делать следующее:

1. Парсинг FEN (DFEN)

Из каждого состояния мы берем поле fen. Мы разделяем его по пробелам.

parts = fen.split(" ")
normalized_fen = " ".join(parts[0:4]) # piece_placement, color, castling, en_passant

Затем мы считаем хэш: xxhash.xxh64(normalized_fen).intdigest().

2. Сборка микро-ходов в Turn

Поскольку в JSON записан каждый микро-ход (состояние до хода, состояние после первого микро-хода, после второго), скрипт должен объединять их в единый логический ход (Turn).

  • Начало хода: Цвет игрока не меняется, кубики брошены (dices не пустой). Начальная позиция (position_id) фиксируется.
  • Микро-ходы: Мы собираем gameMoveHistoryMove (например, e2e4, g1f3) в список played_moves = ["e2e4", "g1f3"].
  • Конец хода: Цвет активного игрока меняется (или партия завершается).

3. Кэширование позиций в памяти

Поскольку позиций могут быть миллионы, но многие из них повторяются, скрипт будет держать в памяти локальный словарь (dict) хешей позиций, чтобы не делать SELECT к базе данных для каждой позиции. Неизвестные позиции будут записываться в базу ON CONFLICT DO NOTHING (PostgreSQL INSERT ... ON CONFLICT).

4. Вставка данных

Порядок вставки для каждого пакета (например, 1000 JSON файлов):

  1. Распарсить все уникальные Player Вставить ON CONFLICT DO NOTHING.
  2. Распарсить все уникальные Position Вставить ON CONFLICT DO NOTHING.
  3. Вставить Game.
  4. Вставить Turn.
  5. Вставить GameEvent.

Verification Plan

Automated Tests

  • Мы напишем юнит-тест tests/test_importer.py для логики группировки микро-ходов в Turn.
  • Запустим импортер на небольшой тестовой директории (например, из 10 партий) и проверим, что данные корректно легли в PostgreSQL.

Manual Verification

  • После загрузки первых 1000 партий, мы выполним несколько SQL-запросов напрямую в базе данных (через DBeaver/psql), чтобы убедиться, что массивы ходов и JSONB-метаданные выглядят идеально.