Files
wiki/tasks/flightradar24/reports/TZ-fr24-schedule-supplement.md
2026-04-22 00:10:02 +03:00

6.1 KiB
Raw Blame History

ТЗ: Дополнение расписания из FR24 flight-summary/full

Дата: 2026-04-21
Статус: READY FOR DEV
Приоритет: Высокий


Контекст

FR24 /api/flight-summary/full уже используется в fr24_worker.py и возвращает все реальные рейсы через московские аэропорты за сутки (до 20 000 записей).

Текущее поведение:

  • enrich_schedule() — только UPDATE существующих строк в fr24_ext.schedule
  • Рейсы из flight_actual, которых нет в Яндекс.Расписании, теряются

Проблема: Яндекс не покрывает 100% рейсов (чартеры, грузовые, технические, задержанные). FR24 имеет полные данные. Нужно использовать flight_actual как дополнительный источник расписания.


Что нужно сделать

1. Функция supplement_schedule() в fr24_worker.py

def supplement_schedule(conn, target_date: date) -> int:
    """
    Insert into fr24_ext.schedule flights from flight_actual
    that have no matching schedule record.
    
    Source: fr24_ext.flight_actual
    Target: fr24_ext.schedule (source='fr24')
    
    Returns: number of rows inserted
    """

Логика:

  1. Найти все рейсы в flight_actual за дату, у которых нет соответствия в schedule
  2. Определить direction: если origin_icao в московских аэропортах → departure, иначе arrival
  3. INSERT в schedule с source='fr24', status='actual'

SQL-скелет для поиска незаматченных:

SELECT fa.*
FROM fr24_ext.flight_actual fa
WHERE fa.flight_date = %(date)s
  AND NOT EXISTS (
    SELECT 1 FROM fr24_ext.schedule s
    WHERE UPPER(REPLACE(s.flight_number,' ','')) = UPPER(REPLACE(fa.flight,' ',''))
      AND s.flight_date = fa.flight_date
  )
  AND fa.flight IS NOT NULL
  AND fa.flight != ''

Поля для INSERT в schedule:

flight_date     = target_date
airport_iata    = ICAO_TO_IATA[origin_icao или dest_icao] (московский аэропорт)
direction       = 'departure' если origin_icao московский, иначе 'arrival'
flight_number   = fa.flight (нормализовать: убрать лишние пробелы)
airline_iata    = первые 2 символа IATA (если можно определить)
origin_iata     = ICAO_TO_IATA.get(fa.origin_icao)
destination_iata = ICAO_TO_IATA.get(fa.dest_icao)
aircraft_type   = NULL (нет в flight_actual)
scheduled_at    = fa.datetime_takeoff (или datetime_landed для arrival)
actual_takeoff  = fa.datetime_takeoff
actual_landed   = fa.datetime_landed
status          = 'actual'
source          = 'fr24'
fr24_id         = fa.fr24_id

ON CONFLICT: (flight_number, airport_iata, scheduled_at, direction) — уже есть.

2. Также исправить баги из ревью

Баг A: ZBAD/PKX не в словаре ICAO_TO_IATA

Файл: build_mart.py Добавить в словарь ICAO_TO_IATA:

"ZBAD": "PKX",   # Beijing Daxing
"RKSI": "ICN",   # Seoul Incheon (уже есть, проверить)

Баг B: Soft match для FA/FR24 когда destination не совпадает

Файл: build_mart.py, функции find_fa_track() и find_fr24_track()

Текущая логика:

if origin_iata and not destination_iata:  # только если dest == NULL
    # soft match by origin only

Нужно изменить на:

# Если полный матч не нашёл → fallback на origin only
if origin_iata:
    for row in rows:
        orig_iata = ICAO_TO_IATA.get(row[2])
        if orig_iata == origin_iata:
            return (row[0], row[1])

(убрать условие not destination_iata)

3. Вызов supplement_schedule() в run() fr24_worker.py

После enrich_schedule():

# 4. Supplement schedule with flights from FR24 not in Yandex
try:
    supplemented = supplement_schedule(conn, target_date)
    conn.commit()
    stats["schedule_supplemented"] = supplemented
    log.info("FR24 worker: supplemented %d new schedule rows", supplemented)
except Exception as e:
    conn.rollback()
    log.error("FR24 worker: supplement_schedule failed: %s", e)
    stats["errors"] += 1

Что НЕ нужно делать

  • НЕ менять DDL/схему БД (колонки fr24_id, actual_takeoff, actual_landed в schedule уже есть или добавить как nullable)
  • НЕ трогать RTL-SDR матч — он работает корректно
  • НЕ запускать backfill — только текущая логика для новых дат

Проверка результата

  1. Запустить build для 19.04 или 20.04 (данные уже есть в flight_actual)
  2. Проверить:
SELECT source, count(*) FROM fr24_ext.schedule 
WHERE flight_date = '2026-04-19' GROUP BY source;
-- Ожидаемо: yandex=~1570, fr24=N (новые)

SELECT count(*) FROM fr24_ext.schedule s
JOIN fr24_ext.flight_actual fa ON UPPER(REPLACE(fa.flight,' ','')) = UPPER(REPLACE(s.flight_number,' ',''))
WHERE s.flight_date = '2026-04-19' AND s.source = 'fr24';
  1. Перезапустить mart build для даты — посмотреть увеличение schedule_flights и with_track

Файлы для изменения

Файл Изменение
ingest/tracks_fr24/fr24_worker.py Добавить supplement_schedule(), вызвать в run()
ingest/mart/build_mart.py Добавить ZBAD→PKX в словарь, исправить soft match

Путь к проекту на VM

/home/fr24/fr24/ingest/

Деплой: docker cp <file> fr24-tracks-fr24:/app/<file> && docker restart fr24-tracks-fr24