Перейти к основному содержимому

PropertyObjectSearchDocument

Elasticsearch document PropertyObjectSearchDocument — rebuildable search projection полнотекстового поиска объектов недвижимости публичного каталога (лента /lots, поиск по названию/номеру/адресу/ застройщику). Полнотекстовый поиск реализован на Elasticsearch (ADR-0059).

Назначение

Source of truth — CatalogPropertyObjectCard; проекция хранит только индексируемые/фильтруемые/сортируемые поля карточки. Ключевые возможности поиска — fuzzy (typo-tolerance), транслитерация кириллица↔латиница и алиасы для названий/адресов/застройщиков (ADR-0059 п.1). Поиск проектов (ЖК/апарт-отелей) — отдельная проекция projects.md.

Index

ПолеЗначение
Index aliascatalog-property-objects
Versioned indexcatalog-property-objects-v1
Owner servicecatalog
Source of truthCatalogPropertyObjectCard (catalog.property_object_cards)
Rebuild jobPropertyObjectSearchRebuildJob

Document Id И Routing

  • Document id: Id карточки (Guid объекта = id в chessboard); платформенная витрина не tenanted (ADR-0052 п.3), поэтому tenant-префикс не применяется.
  • Routing key: ProjectId — объекты одного проекта колокализуются (эффективный пересчёт/переиндексация при изменении проекта).
  • Delete/tombstone: карточка Status = Delisted или физическое удаление → удаление документа из индекса; переход в Hidden → документ остаётся, но Status=Hidden вырезается security-trimming-ом до выдачи.

Поля

ПолеТипIndexedStoredAnalyzerSourceSecurity
IdkeywordдадаId
ProjectIdkeywordдадаProjectIdrouting/filter
DeveloperIdkeywordдадаDeveloper.DeveloperIdscope-filter
Titletextданетru_translit_fuzzyTitle
Numbertextданетru_translit_fuzzyNumber
Addresstextданетru_translit_fuzzyAddress
DeveloperNametextданетru_translit_fuzzyDeveloper.DeveloperName
BuildingNametextданетru_translit_fuzzyBuilding.BuildingName
RegionNametextданетru_translit_fuzzyproject-card RegionName (денорм.)
CityNametextданетru_translit_fuzzyproject-card CityName (денорм.)
SearchTexttextданетru_translit_fuzzyTitle ⊕ Number ⊕ Address ⊕ DeveloperName ⊕ RegionName ⊕ CityName (copy_to)основной матч запроса searchTerm
TypeNamekeywordдадаLayout.TypeNameфильтр «тип»
RoomsCountshortдадаLayout.RoomsCountфильтр
PricedoubleдадаPriceфильтр «ценовой диапазон» + сортировка
PropertyObjectStatuskeywordдадаPropertyObjectStatusфильтр доступности
RegionIdkeywordдадаproject-card RegionId (денорм., ссылка на справочник handbook)фильтр «регион»
CityIdkeywordдадаproject-card CityId (денорм., ссылка на справочник handbook)фильтр «город»
DeliveryDatedateдадаDeliveryDateфильтр/сортировка
PromotionBoostintegerдадаPromotionBoostранжирование «Рекомендованные»
DeveloperPriorityintegerдадаDeveloperPriorityранжирование
PopularityScoredoubleдадаPopularityScoreсортировка «по популярности»
PublishedAtdateдадаPublishedAtсортировка «по дате»
StatuskeywordдадаStatussecurity-trimming (Published)
SchemaVersionintegerдададокументверсия схемы проекции
UpdatedAtdateдадакарточка UpdatedAtfreshness watermark
IndexedAtdateдадаиндексаторfreshness

Анализатор ru_translit_fuzzy: русская морфология + ICU-транслитерация (кириллица↔латиница) + edge-ngram для typo-tolerance; словарь синонимов/алиасов застройщиков и типов (ADR-0059 п.1).

Source Events

EventVersionTransform
PropertyObjectCardRecomputedEventv1upsert документа из текущего состояния CatalogPropertyObjectCard (маппинг полей выше)
PropertyObjectCardRecomputedEvent (Status=Delisted)v1delete документа

Проекция наполняется инкрементально доменным событием карточки (тот же коммит, что пересчёт витрины) + периодический/ручной PropertyObjectSearchRebuildJob для bootstrap и восстановления консистентности.

Freshness

  • SLA: search (секунды–минуты; eventual относительно PostgreSQL, FreshnessView).
  • Watermark: UpdatedAt карточки в документе.
  • Stale behavior: показать результаты с freshness-маркером; критичные для брони проверки статуса делает crm в источнике, не поиск.

Security

  • Tenant/brand/scope trimming выполняется до query execution (ADR-0059 п.3): публичный поиск — только Status = Published; developer-facing поиск — дополнительно DeveloperId == актор.CompanyId.
  • PII fields: none (в проекцию не кладутся ФИО/телефон/реквизиты; комиссия агента в индекс не попадает).
  • Полнотекстовый поиск не индексирует secrets, tokens, payment/KYC data.

Rebuild

  1. Create versioned index catalog-property-objects-v{N+1} (маппинг + ru_translit_fuzzy).
  2. Backfill из catalog.property_object_cards (Status != Delisted).
  3. Validate counts/checksums против source.
  4. Atomically switch alias catalog-property-objects на новую версию (ADR-0029).
  5. Keep previous index до окончания rollback-окна.

Деградация и частичный отказ

  • Индекс недоступен. Полнотекстовый поиск объектов недвижимости зависит от Elasticsearch; при недоступности индекса поиск деградирует — пользователю отдаётся признак «поиск временно недоступен», а лента /lots без текстового запроса (сортировки/фильтры по витрине catalog.property_object_cards) продолжает работать через API каталога. «Примерную» FTS-выдачу из PostgreSQL не строим (FTS-колонок в источнике нет, ADR-0059).
  • Отставание проекции. Изменение карточки (публикация/скрытие/цена/доступность) видно в поиске после доезда PropertyObjectCardRecomputedEvent и индексации (секунды–минуты); в окне рассинхронизации выдача помечается признаком свежести (FreshnessView). Критичную для брони проверку статуса делает crm в источнике, а не поиск (значение PropertyObjectStatus в индексе может отставать).
  • Rebuild. Пересборка идёт в теневой индекс catalog-property-objects-v{N+1}; алиас catalog-property-objects переключается только после валидации счётчиков/чек-сумм — частичный или упавший rebuild не отдаёт пользователю неполный индекс, активным остаётся прежний до успешного switch.

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы