Москва: пред-геокод Авито, Яндекс третьей площадкой, продукт отвечает по региону 77 #3440
2 changed files with 51 additions and 1 deletions
|
|
@ -224,6 +224,7 @@ CREATE TABLE IF NOT EXISTS msk_raw.avito_geocode (
|
|||
resolved_at timestamptz NOT NULL DEFAULT NOW()
|
||||
)
|
||||
"""
|
||||
_GEO_CACHE_EXISTS = "SELECT to_regclass('msk_raw.avito_geocode')"
|
||||
_GEO_CACHE_SELECT = """
|
||||
SELECT cache_key, lat, lon, region_code, full_address
|
||||
FROM msk_raw.avito_geocode
|
||||
|
|
@ -350,7 +351,17 @@ def _resolve_points(
|
|||
return {}
|
||||
|
||||
points: dict[str, GeoPoint | None] = {}
|
||||
cached = db.execute(text(_GEO_CACHE_SELECT), {"keys": list(wanted)}).mappings().all()
|
||||
# Кэш создаётся только боевым прогоном (`geocode and not dry_run`), поэтому на
|
||||
# первом `--dry-run` таблицы ещё нет и SELECT по ней роняет весь замер — то
|
||||
# есть ломается ровно та репетиция, ради которой сухой прогон и существует.
|
||||
# Проверяем наличие отношения, а не ловим исключение: в Postgres упавший
|
||||
# оператор кладёт транзакцию целиком, и except потребовал бы rollback.
|
||||
cache_exists = db.execute(text(_GEO_CACHE_EXISTS)).scalar() is not None
|
||||
cached = (
|
||||
db.execute(text(_GEO_CACHE_SELECT), {"keys": list(wanted)}).mappings().all()
|
||||
if cache_exists
|
||||
else ()
|
||||
)
|
||||
for row in cached:
|
||||
points[row["cache_key"]] = (
|
||||
None
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ class _FakeResult:
|
|||
def all(self) -> list[dict[str, Any]]:
|
||||
return self._rows
|
||||
|
||||
def scalar(self) -> Any:
|
||||
"""Проба существования кэш-таблицы: None = таблицы ещё нет."""
|
||||
return self._rows[0] if self._rows else None
|
||||
|
||||
|
||||
class _FakeSession:
|
||||
"""Отдаёт строки постранично по тому же keyset-условию, что и настоящая вью."""
|
||||
|
|
@ -361,3 +365,38 @@ def test_geocode_is_refused_for_cian(captured: list[dict[str, Any]]) -> None:
|
|||
"""У Циана город виден по префиксу округа даром — квоту на него не тратим."""
|
||||
with pytest.raises(SystemExit):
|
||||
mod.import_msk_raw(_FakeSession(_rows()), source="cian", batch_size=10, geocode=True)
|
||||
|
||||
|
||||
def test_dry_run_survives_missing_geocode_cache(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Первый `--dry-run` идёт по проду, где кэш-таблицы ещё нет.
|
||||
|
||||
Таблицу создаёт только боевой прогон, поэтому SELECT по ней в сухом ронял
|
||||
ровно ту репетицию, ради которой сухой прогон и существует (замер на проде
|
||||
11.09: UndefinedTable msk_raw.avito_geocode). Резолвер обязан молча считать
|
||||
кэш пустым и идти к DaData за остатком.
|
||||
"""
|
||||
|
||||
class _NoCacheSession:
|
||||
def __init__(self) -> None:
|
||||
self.cache_reads = 0
|
||||
|
||||
def execute(self, sql: Any, params: dict[str, Any] | None = None) -> _FakeResult:
|
||||
if "to_regclass" in str(sql):
|
||||
return _FakeResult([]) # таблицы нет
|
||||
self.cache_reads += 1
|
||||
raise AssertionError("к отсутствующей кэш-таблице ходить нельзя")
|
||||
|
||||
point = mod.GeoPoint(55.6412, 37.6089, 77, "г Москва, ш Варшавское, д 62 к 1")
|
||||
|
||||
async def _fake_geocode(misses: list[Any]) -> dict[str, Any]:
|
||||
return {misses[0][0]: point}
|
||||
|
||||
monkeypatch.setattr(mod, "_geocode_many", _fake_geocode)
|
||||
|
||||
db = _NoCacheSession()
|
||||
points = mod._resolve_points(
|
||||
db, [{"id": 1, "payload": _avito()}], mod.GeocodeBudget(10), dry_run=True
|
||||
)
|
||||
|
||||
assert db.cache_reads == 0
|
||||
assert list(points.values()) == [point]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue