fix(tradein/scraper): исключить Верхнюю Пышму из вторички Циана — грязная городская метка
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m40s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 8s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 2m40s
This commit is contained in:
parent
034ab48cfe
commit
6dda48fc6c
2 changed files with 47 additions and 17 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
-- 204_cian_oblast_sweeps_secondary.sql
|
-- 204_cian_oblast_sweeps_secondary.sql
|
||||||
-- Включить сбор вторички Циана по 5 областным city-sweep'ам (Свердловская обл.,
|
-- Включить сбор вторички Циана по 4 областным city-sweep'ам (Свердловская обл.,
|
||||||
-- миграция 179 — nizhniy_tagil/kamensk_uralskiy/pervouralsk/verkhnyaya_pyshma/serov).
|
-- миграция 179 — nizhniy_tagil/kamensk_uralskiy/pervouralsk/serov).
|
||||||
--
|
--
|
||||||
-- ПРОБЛЕМА: _job_cian_city_sweep (scraper_kit.orchestration.scheduler:570) читает
|
-- ПРОБЛЕМА: _job_cian_city_sweep (scraper_kit.orchestration.scheduler:570) читает
|
||||||
-- newbuilding_only = bool(default_params.get("newbuilding_only", True)) — дефолт True.
|
-- newbuilding_only = bool(default_params.get("newbuilding_only", True)) — дефолт True.
|
||||||
|
|
@ -20,12 +20,28 @@
|
||||||
-- pervouralsk 55 увидено, 53 выброшено (сохранено 2)
|
-- pervouralsk 55 увидено, 53 выброшено (сохранено 2)
|
||||||
-- kamensk_uralskiy 113 увидено, 108 выброшено (сохранено 5)
|
-- kamensk_uralskiy 113 увидено, 108 выброшено (сохранено 5)
|
||||||
-- nizhniy_tagil 184 увидено, 176 выброшено (сохранено 3)
|
-- nizhniy_tagil 184 увидено, 176 выброшено (сохранено 3)
|
||||||
-- verkhnyaya_pyshma 38 увидено, 16 выброшено (сохранено 9)
|
-- verkhnyaya_pyshma 38 увидено, 16 выброшено (сохранено 9) -- см. EXCLUSION ниже
|
||||||
--
|
--
|
||||||
-- FIX: newbuilding_only: false для ПЯТИ областных source'ов. cian_city_sweep (ЕКБ,
|
-- FIX: newbuilding_only: false для ЧЕТЫРЁХ областных source'ов. cian_city_sweep (ЕКБ,
|
||||||
-- БЕЗ суффикса города) НЕ трогаем — для него дефолт корректен (вторичку ЕКБ
|
-- БЕЗ суффикса города) НЕ трогаем — для него дефолт корректен (вторичку ЕКБ
|
||||||
-- собирает cian_full_load), включение дало бы дублирующую нагрузку на источник.
|
-- собирает cian_full_load), включение дало бы дублирующую нагрузку на источник.
|
||||||
--
|
--
|
||||||
|
-- !!! EXCLUSION: cian_city_sweep_verkhnyaya_pyshma НЕ включён в эту миграцию !!!
|
||||||
|
-- Верхняя Пышма физически ~15 км от центра Екатеринбурга — geo-проверка по
|
||||||
|
-- ST_DWithin (координаты listings vs центр города) показала, что 5 из 22 (23%)
|
||||||
|
-- текущих cian-строк с меткой city="Верхняя Пышма" физически лежат в 15 км от
|
||||||
|
-- центра ЕКБ, т.е. это загрязнённая городская разметка (sweep по anchor'у В.Пышмы
|
||||||
|
-- зацепляет краевые екатеринбургские объявления и подписывает их не тем городом).
|
||||||
|
-- Колонка listings.city — money-critical: её читает asking_to_sold_ratio.py
|
||||||
|
-- (city-скоуп ASKING vs SOLD стороны, #2583 H2) — неверная метка двигает выкупные
|
||||||
|
-- цены. При newbuilding_only=false объём cian-строк под меткой В.Пышма вырастет с
|
||||||
|
-- 22 до нескольких сотен (те же ~38 увидено/16 выброшено за один run, помноженные
|
||||||
|
-- на число прогонов) — 23%-загрязнение умножилось бы пропорционально.
|
||||||
|
-- nizhniy_tagil/kamensk_uralskiy/pervouralsk/serov — загрязнение по той же
|
||||||
|
-- geo-проверке НУЛЕВОЕ (0 из 8/5/2 соответственно физически в ЕКБ) — включать
|
||||||
|
-- безопасно. cian_city_sweep_verkhnyaya_pyshma будет включён ОТДЕЛЬНОЙ миграцией
|
||||||
|
-- после починки городской разметки sweep'а (правится параллельно) — НЕ забыт.
|
||||||
|
--
|
||||||
-- Нагрузка на источник (см. PR description / vault fix-запись для полного разбора):
|
-- Нагрузка на источник (см. PR description / vault fix-запись для полного разбора):
|
||||||
-- fetch_around_multi_room (providers/cian/serp.py:209) НЕ принимает newbuilding_only/
|
-- fetch_around_multi_room (providers/cian/serp.py:209) НЕ принимает newbuilding_only/
|
||||||
-- secondary_only — SERP-фаза (все rooms×pages) выполняется ОДИНАКОВО независимо от
|
-- secondary_only — SERP-фаза (все rooms×pages) выполняется ОДИНАКОВО независимо от
|
||||||
|
|
@ -37,7 +53,7 @@
|
||||||
--
|
--
|
||||||
-- Дубли: run_cian_full_load всегда region_code=EKB (city_region_id=4743 через
|
-- Дубли: run_cian_full_load всегда region_code=EKB (city_region_id=4743 через
|
||||||
-- CianScraper() без city_slug), областные sweeps используют CITY_LOCATIONS[<slug>]
|
-- CianScraper() без city_slug), областные sweeps используют CITY_LOCATIONS[<slug>]
|
||||||
-- .cian_region_id (4886/4781/4925/4697/4982 — все != 4743) — SERP-запросы физически
|
-- .cian_region_id (4886/4781/4925/4982 — все != 4743) — SERP-запросы физически
|
||||||
-- разных региональных выдач. dedup_hash = sha256(source|source_id) — глобальный
|
-- разных региональных выдач. dedup_hash = sha256(source|source_id) — глобальный
|
||||||
-- Cian offer_id, ON CONFLICT (dedup_hash) DO UPDATE — даже в теоретическом edge-case
|
-- Cian offer_id, ON CONFLICT (dedup_hash) DO UPDATE — даже в теоретическом edge-case
|
||||||
-- совпадения upsert НЕ создаёт дубль-строку.
|
-- совпадения upsert НЕ создаёт дубль-строку.
|
||||||
|
|
@ -51,7 +67,7 @@
|
||||||
-- enrich_houses/pages_per_anchor/request_delay_sec (см. 179_scrape_schedules_seed_oblast_city_sweeps.sql
|
-- enrich_houses/pages_per_anchor/request_delay_sec (см. 179_scrape_schedules_seed_oblast_city_sweeps.sql
|
||||||
-- за текущими прод-значениями). Idempotent: повторный прогон ставит то же значение.
|
-- за текущими прод-значениями). Idempotent: повторный прогон ставит то же значение.
|
||||||
--
|
--
|
||||||
-- ЗАВИСИМОСТИ: 052_scrape_schedules.sql (таблица), 179 (seed этих 5 source'ов).
|
-- ЗАВИСИМОСТИ: 052_scrape_schedules.sql (таблица), 179 (seed этих source'ов).
|
||||||
-- deploy order: только миграция — код scheduler.py/pipeline.py НЕ меняется в этом PR,
|
-- deploy order: только миграция — код scheduler.py/pipeline.py НЕ меняется в этом PR,
|
||||||
-- дефолт newbuilding_only=True в коде остаётся (правильный fallback для будущих
|
-- дефолт newbuilding_only=True в коде остаётся (правильный fallback для будущих
|
||||||
-- source'ов без явного default_params override).
|
-- source'ов без явного default_params override).
|
||||||
|
|
@ -65,7 +81,6 @@ WHERE source IN (
|
||||||
'cian_city_sweep_nizhniy_tagil',
|
'cian_city_sweep_nizhniy_tagil',
|
||||||
'cian_city_sweep_kamensk_uralskiy',
|
'cian_city_sweep_kamensk_uralskiy',
|
||||||
'cian_city_sweep_pervouralsk',
|
'cian_city_sweep_pervouralsk',
|
||||||
'cian_city_sweep_verkhnyaya_pyshma',
|
|
||||||
'cian_city_sweep_serov'
|
'cian_city_sweep_serov'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
"""Static guards for migration 204 (включить сбор вторички Циана по 5 областным
|
"""Static guards for migration 204 (включить сбор вторички Циана по 4 областным
|
||||||
city-sweep'ам — Свердловская обл., см. миграцию 179).
|
city-sweep'ам — Свердловская обл., см. миграцию 179).
|
||||||
|
|
||||||
Прод применяет data/sql построчно строго (ON_ERROR_STOP). Полный DB-прогон требует
|
Прод применяет data/sql построчно строго (ON_ERROR_STOP). Полный DB-прогон требует
|
||||||
живой БД; здесь фиксируем структурные инварианты: транзакционность, отсутствие DDL,
|
живой БД; здесь фиксируем структурные инварианты: транзакционность, отсутствие DDL,
|
||||||
отсутствие psycopg CAST-ловушки, jsonb-мердж (не перезапись), ровно 5 таргетных
|
отсутствие psycopg CAST-ловушки, jsonb-мердж (не перезапись), ровно 4 таргетных
|
||||||
source'ов — и, главное, ЯВНЫЙ regression-guard, что екатеринбургское расписание
|
source'а — и, главное, ДВА regression-guard'а:
|
||||||
('cian_city_sweep' без суффикса города) в списке НЕ фигурирует (для него текущий
|
1. 'cian_city_sweep' (ЕКБ, без суффикса города) НЕ фигурирует — для него текущий
|
||||||
дефолт newbuilding_only=True в коде корректен — вторичку ЕКБ собирает
|
дефолт newbuilding_only=True в коде корректен (вторичку ЕКБ авторитетно собирает
|
||||||
run_cian_full_load; включение дало бы дублирующую нагрузку на источник).
|
run_cian_full_load; включение дало бы дублирующую нагрузку на источник).
|
||||||
|
2. 'cian_city_sweep_verkhnyaya_pyshma' НЕ фигурирует — geo-проверка (ST_DWithin от
|
||||||
|
центра ЕКБ) показала 23% (5 из 22) загрязнение городской метки cian-строк В.Пышмы
|
||||||
|
екатеринбургскими объявлениями; listings.city — money-critical (читает
|
||||||
|
asking_to_sold_ratio.py). Включат отдельной миграцией после починки разметки.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -22,7 +26,6 @@ _OBLAST_SOURCES = (
|
||||||
"cian_city_sweep_nizhniy_tagil",
|
"cian_city_sweep_nizhniy_tagil",
|
||||||
"cian_city_sweep_kamensk_uralskiy",
|
"cian_city_sweep_kamensk_uralskiy",
|
||||||
"cian_city_sweep_pervouralsk",
|
"cian_city_sweep_pervouralsk",
|
||||||
"cian_city_sweep_verkhnyaya_pyshma",
|
|
||||||
"cian_city_sweep_serov",
|
"cian_city_sweep_serov",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -76,13 +79,14 @@ def test_migration_204_updates_default_params_via_jsonb_merge() -> None:
|
||||||
assert "set default_params = '{" not in flat
|
assert "set default_params = '{" not in flat
|
||||||
|
|
||||||
|
|
||||||
def test_migration_204_targets_exactly_five_oblast_sources() -> None:
|
def test_migration_204_targets_exactly_four_oblast_sources() -> None:
|
||||||
flat = _flat(_executable_sql())
|
flat = _flat(_executable_sql())
|
||||||
for source in _OBLAST_SOURCES:
|
for source in _OBLAST_SOURCES:
|
||||||
assert f"'{source}'" in flat, f"missing target source: {source}"
|
assert f"'{source}'" in flat, f"missing target source: {source}"
|
||||||
# Ровно 5 закавыченных source-литералов в WHERE ... IN (...) — не больше, не меньше.
|
# Ровно 4 закавыченных source-литерала в WHERE ... IN (...) — не больше, не меньше.
|
||||||
quoted = re.findall(r"'(cian_city_sweep_[a-z_]+)'", flat)
|
quoted = re.findall(r"'(cian_city_sweep_[a-z_]+)'", flat)
|
||||||
assert sorted(set(quoted)) == sorted(_OBLAST_SOURCES)
|
assert sorted(set(quoted)) == sorted(_OBLAST_SOURCES)
|
||||||
|
assert len(quoted) == 4
|
||||||
|
|
||||||
|
|
||||||
def test_migration_204_does_not_touch_ekaterinburg_schedule() -> None:
|
def test_migration_204_does_not_touch_ekaterinburg_schedule() -> None:
|
||||||
|
|
@ -103,11 +107,22 @@ def test_migration_204_does_not_touch_ekaterinburg_schedule() -> None:
|
||||||
"nizhniy_tagil",
|
"nizhniy_tagil",
|
||||||
"kamensk_uralskiy",
|
"kamensk_uralskiy",
|
||||||
"pervouralsk",
|
"pervouralsk",
|
||||||
"verkhnyaya_pyshma",
|
|
||||||
"serov",
|
"serov",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_migration_204_does_not_touch_verkhnyaya_pyshma() -> None:
|
||||||
|
"""Regression-guard против «Пышму забыли обратно включить»: geo-проверка
|
||||||
|
(ST_DWithin от центра ЕКБ) показала 23% (5 из 22) cian-строк с меткой
|
||||||
|
city="Верхняя Пышма" физически лежат в 15 км от центра Екатеринбурга — загрязнённая
|
||||||
|
городская разметка. listings.city — money-critical (asking_to_sold_ratio.py читает
|
||||||
|
его для city-скоупа ASKING vs SOLD стороны). Включение вторички умножило бы это
|
||||||
|
загрязнение (22 → несколько сотен строк). Пышму включат отдельной миграцией
|
||||||
|
ПОСЛЕ починки городской разметки sweep'а — сейчас её НЕ должно быть в WHERE."""
|
||||||
|
flat = _flat(_executable_sql())
|
||||||
|
assert "cian_city_sweep_verkhnyaya_pyshma" not in flat
|
||||||
|
|
||||||
|
|
||||||
def test_migration_204_no_psycopg_cast_trap() -> None:
|
def test_migration_204_no_psycopg_cast_trap() -> None:
|
||||||
"""Никаких :param::type — psycopg v3 требует CAST(... AS type) (не применимо
|
"""Никаких :param::type — psycopg v3 требует CAST(... AS type) (не применимо
|
||||||
в чистом .sql без bind params, но проверяем на регресс copy-paste из Python)."""
|
в чистом .sql без bind params, но проверяем на регресс copy-paste из Python)."""
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue