gendesign/tradein-mvp/backend/data/sql/217_position_in_serp_unexpressible.sql
bot-backend 27272762ef
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 2m57s
Deploy Trade-In / build-backend (push) Successful in 1m34s
Deploy Trade-In / deploy (push) Successful in 1m27s
fix(tradein): такт в сохранении расписания, position_in_serp невыразим (#2674)
2026-08-06 05:49:48 +00:00

62 lines
6.3 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 217_position_in_serp_unexpressible.sql
-- listings_snapshots.position_in_serp — диагноз «механизм невыразим», шаг 1 из 2.
--
-- Dependencies: 016_listings_snapshots.sql (создала колонку).
-- Apply after: 216_dead_code_sweep.sql
-- Идемпотентно: только COMMENT ON COLUMN (CREATE OR REPLACE-семантика).
--
-- ── ЧТО НАЙДЕНО ──────────────────────────────────────────────────────────────
-- upsert_listing_snapshot принимал position_in_serp, но НИ ОДИН боевой вызывающий
-- его не передавал: три call-site'а (scraper_kit/base.py:801 save_listings,
-- providers/cian/detail.py:382, app/tasks/avito_detail_backfill.py:454) плюс
-- ingest-скрипты — везде аргумент опущен. На проде колонка пуста 0 из 395 240 строк
-- (данные с 2026-05-30 по 2026-08-06).
--
-- ── ПОЧЕМУ ЭТО НЕ «ПОДКЛЮЧИТЬ» ───────────────────────────────────────────────
-- Соблазнительный вывод — «парсер выдачи знает индекс карточки, передайте его».
-- Он неверен: позиция есть свойство пары (объявление, конкретный прогон выдачи с
-- конкретными фильтрами), а выбранная структура этого отношения не выражает.
-- PRIMARY KEY (listing_id, snapshot_date) — максимум ОДНА строка на объявление в
-- сутки; run_id здесь обычный атрибут, да ещё и под COALESCE в ON CONFLICT.
-- Следствия на живых данных:
-- * 2026-08-05: 77 прогонов и 5392 total_seen дали 4595 строк снэпшотов; за
-- 2026-08-03 в таблице 13 разных run_id на одну дату. Четыре SERP-источника
-- (yandex/cian/avito/domclick city_sweep) в одни сутки пишут по одному ключу.
-- * Внутри одного city_sweep обход идёт по десяткам гео-якорей радиусом 1500 м с
-- перекрытием, и save_listings получает `anchor_lots` — 3 страницы ОДНОГО якоря,
-- а не общий ранжированный список. Одно объявление приезжает с разным индексом
-- от разных якорей того же прогона.
-- * Старый ON CONFLICT писал COALESCE(EXCLUDED.position_in_serp, <старое>) — в
-- строке оседал бы индекс последнего писателя дня. Это не «позиция в выдаче», а
-- произвольный представитель суток; хуже NULL, потому что читался бы как факт.
-- Чтобы позицию можно было хранить честно, нужна отдельная таблица с ключом
-- (run_id, listing_id) и сохранёнными фильтрами прогона. Такой задачи сейчас нет —
-- ни один потребитель позицию не читает (0 view/matview на проде ссылаются на
-- колонку), поэтому колонка удаляется, а не переносится.
--
-- ── ПОЧЕМУ DROP НЕ ЗДЕСЬ ─────────────────────────────────────────────────────
-- Шаг 1 (этот файл + правка кода в том же PR): upsert_listing_snapshot перестаёт
-- упоминать колонку; колонка остаётся, комментарий объясняет почему.
-- Шаг 2 (отдельный PR, после того как образ с шагом 1 живёт на проде):
-- ALTER TABLE listings_snapshots DROP COLUMN IF EXISTS position_in_serp;
-- Порядок не косметический. deploy-tradein.yml применяет data/sql/*.sql ДО
-- перезапуска контейнеров («(3) Применяем SQL миграции — ДО app»), так что DROP в
-- одном деплое с правкой кода оставил бы окно в несколько минут, где ещё живой
-- СТАРЫЙ образ выполняет INSERT со списком колонок, включающим удалённую. Запись
-- снэпшотов fault-tolerant (SAVEPOINT + warning), поэтому упало бы тихо — ровно тот
-- класс потерь, который замечают через недели по дырке в истории цен.
BEGIN;
COMMENT ON COLUMN listings_snapshots.position_in_serp IS
'МЁРТВАЯ, удаляется следующей миграцией (#2674). Пуста 0/395240 на 2026-08-06: '
'писатель принимал аргумент, ни один вызывающий его не передавал. Не подключена, '
'потому что механизм невыразим в этой таблице: позиция — свойство пары '
'(объявление, конкретный прогон выдачи с конкретными фильтрами), а PK здесь '
'(listing_id, snapshot_date) — одна строка на объявление в сутки, при том что в '
'одни сутки по этому ключу пишут до 13 прогонов и 4 разных SERP-источника, а '
'внутри одного прогона объявление приходит с разным индексом от перекрывающихся '
'гео-якорей. Честное хранение требует таблицы с ключом (run_id, listing_id) и '
'сохранёнными фильтрами прогона; читателей у позиции нет ни одного.';
COMMIT;