Областной ДомКлик отбирается ещё и по координате, не только по префиксу
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m31s
CI / changes (pull_request) Successful in 10s
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
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m31s
CI / changes (pull_request) Successful in 10s
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
Замер на собранном корпусе: у 2 960 из 2 961 карточки областного батча первый компонент адреса — «Московская область», а у одной «Можайский муниципальный округ, д. Семёновское, 1» (55.5116/35.8293). Это настоящая область, строгий префикс выбросил бы её молча. Фильтр стал payload-уровневым: префикс → да; «Москва» первым компонентом → нет (раньше гео-ветки, иначе вложенный в областной bbox Москвы протащил бы столицу); иначе координата внутри bbox_region региона 50 из реестра. Московский батч тем же замером даёт «Москва» у всех 22 836 карточек — вторая опора его не трогает.
This commit is contained in:
parent
a7470f0c3d
commit
02a1ec08f3
2 changed files with 75 additions and 1 deletions
|
|
@ -141,6 +141,7 @@ from sqlalchemy.orm import Session
|
|||
from app.core.db import SessionLocal
|
||||
from app.services import dadata
|
||||
from app.services.geocoder import normalize_address
|
||||
from app.services.regions import REGIONS, is_within_bbox
|
||||
from app.services.scraper_adapters import RealMatcherAdapter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -606,6 +607,36 @@ def is_oblast_domclick_address(address: str | None) -> bool:
|
|||
return bool(parts) and parts[0] == "Московская область"
|
||||
|
||||
|
||||
def _payload_point(payload: dict) -> tuple[float, float] | None:
|
||||
"""(lat, lon) из сырья ДомКлика, если сборщик их положил и они читаются."""
|
||||
try:
|
||||
return float(payload["lat"]), float(payload["lon"])
|
||||
except (KeyError, TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def is_oblast_domclick_payload(payload: dict) -> bool:
|
||||
"""Область у ДомКлика: префикс адреса ИЛИ координата внутри bbox области.
|
||||
|
||||
Одного префикса мало. Замер на собранном корпусе 12.09.2026 (2 961 карточка
|
||||
областного батча): «Московская область» стоит первым компонентом у 2 960, а
|
||||
у одной — «Можайский муниципальный округ, д. Семёновское, 1», 55.5116/35.8293.
|
||||
Это настоящая область (Можайск), и строгий префикс выбросил бы её молча.
|
||||
Московский батч тем же замером даёт «Москва» первым компонентом у ВСЕХ
|
||||
22 836 карточек, поэтому явный отказ Москве идёт раньше гео-ветки и bbox
|
||||
Москвы (вложенный в областной) не может протащить столичную карточку в 50.
|
||||
"""
|
||||
address = payload.get("address")
|
||||
if is_oblast_domclick_address(address):
|
||||
return True
|
||||
if is_moscow_domclick_address(address):
|
||||
return False
|
||||
point = _payload_point(payload)
|
||||
if point is None:
|
||||
return False
|
||||
return is_within_bbox(point[0], point[1], REGIONS[OBLAST_REGION_CODE].bbox_region)
|
||||
|
||||
|
||||
def _by_address(fn: Callable[[str | None], bool]) -> Callable[[dict], bool]:
|
||||
"""Адаптер: фильтр по адресу → фильтр по всему payload'у (для реестра)."""
|
||||
return lambda payload: fn(payload.get("address"))
|
||||
|
|
@ -622,7 +653,7 @@ REGION_FILTERS: dict[tuple[str, int], Callable[[dict], bool]] = {
|
|||
("yandex", MOSCOW_REGION_CODE): _by_address(is_moscow_yandex_address),
|
||||
("yandex", OBLAST_REGION_CODE): _by_address(is_oblast_yandex_address),
|
||||
("domclick", MOSCOW_REGION_CODE): _by_address(is_moscow_domclick_address),
|
||||
("domclick", OBLAST_REGION_CODE): _by_address(is_oblast_domclick_address),
|
||||
("domclick", OBLAST_REGION_CODE): is_oblast_domclick_payload,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -491,6 +491,48 @@ def test_domclick_oblast_is_recognised_without_geocode() -> None:
|
|||
assert not mod.is_oblast_domclick_address(None)
|
||||
|
||||
|
||||
def test_domclick_oblast_without_prefix_is_saved_by_its_coordinates() -> None:
|
||||
"""Живой случай: областная карточка БЕЗ префикса «Московская область».
|
||||
|
||||
В собранном корпусе 12.09.2026 такая ровно одна на 2 961 — Можайск, и
|
||||
строгий префикс выбросил бы её молча. Координата внутри bbox области —
|
||||
вторая опора фильтра, а не замена первой.
|
||||
"""
|
||||
mozhaysk = _payload(
|
||||
source="domclick",
|
||||
address="Можайский муниципальный округ, д. Семёновское, 1",
|
||||
lat=55.511625,
|
||||
lon=35.829308,
|
||||
)
|
||||
assert mod.is_oblast_domclick_payload(mozhaysk)
|
||||
|
||||
# Строки вместо чисел (JSON сырья бывает и таким) читаются так же.
|
||||
assert mod.is_oblast_domclick_payload({**mozhaysk, "lat": "55.511625", "lon": "35.829308"})
|
||||
|
||||
|
||||
def test_domclick_oblast_geo_branch_cannot_swallow_moscow() -> None:
|
||||
"""bbox Москвы вложен в областной — отказ по адресу обязан идти РАНЬШЕ гео."""
|
||||
moscow = _payload(
|
||||
source="domclick",
|
||||
address="Москва, улица Нижние Мнёвники, 16 к2",
|
||||
lat=55.7558,
|
||||
lon=37.6173,
|
||||
)
|
||||
assert not mod.is_oblast_domclick_payload(moscow)
|
||||
|
||||
|
||||
def test_domclick_oblast_geo_branch_needs_a_usable_point() -> None:
|
||||
"""Нет префикса и нечего проверить координатой → карточка НЕ область."""
|
||||
bare = _payload(source="domclick", address="Можайский муниципальный округ, д. Семёновское, 1")
|
||||
bare.pop("lat", None)
|
||||
bare.pop("lon", None)
|
||||
assert not mod.is_oblast_domclick_payload(bare)
|
||||
assert not mod.is_oblast_domclick_payload({**bare, "lat": None, "lon": None})
|
||||
assert not mod.is_oblast_domclick_payload({**bare, "lat": "н/д", "lon": "н/д"})
|
||||
# Координата за пределами области (Екатеринбург) тоже не проходит.
|
||||
assert not mod.is_oblast_domclick_payload({**bare, "lat": 56.8300, "lon": 60.6000})
|
||||
|
||||
|
||||
def test_domclick_view_is_wired_into_source_views() -> None:
|
||||
assert mod.SOURCE_VIEWS["domclick"] == "msk_raw.domclick_latest"
|
||||
filt77 = mod.REGION_FILTERS[("domclick", 77)]
|
||||
|
|
@ -498,6 +540,7 @@ def test_domclick_view_is_wired_into_source_views() -> None:
|
|||
assert not filt77(_payload(source="domclick", address="Московская область, Химки, 9 Мая, 21к3"))
|
||||
|
||||
filt50 = mod.REGION_FILTERS[("domclick", 50)]
|
||||
assert filt50 is mod.is_oblast_domclick_payload
|
||||
assert filt50(_payload(source="domclick", address="Московская область, Химки, 9 Мая, 21к3"))
|
||||
assert not filt50(_payload(source="domclick", address="Москва, улица Нижние Мнёвники, 16 к2"))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue