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

ProjectSearchDocument

Elasticsearch document ProjectSearchDocument — rebuildable search projection полнотекстового поиска проектов (ЖК/апарт-отелей) публичного каталога (лента /hotels и главная, поиск по названию/адресу/ застройщику). Полнотекстовый поиск реализован на Elasticsearch (ADR-0059).

Назначение

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

Index

ПолеЗначение
Index aliascatalog-projects
Versioned indexcatalog-projects-v1
Owner servicecatalog
Source of truthCatalogProjectCard (catalog.project_cards)
Rebuild jobProjectSearchRebuildJob

Document Id И Routing

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

Поля

ПолеТипIndexedStoredAnalyzerSourceSecurity
IdkeywordдадаId
DeveloperIdkeywordдадаDeveloper.DeveloperIdrouting/scope-filter
Nametextданетru_translit_fuzzyName
Addresstextданетru_translit_fuzzyAddress
DeveloperNametextданетru_translit_fuzzyDeveloper.DeveloperName
RegionNametextданетru_translit_fuzzyRegionName
CityNametextданетru_translit_fuzzyCityName
SearchTexttextданетru_translit_fuzzyName ⊕ Address ⊕ DeveloperName ⊕ RegionName ⊕ CityName (copy_to)основной матч запроса searchTerm
KindkeywordдадаKindфильтр «тип» (ResidentialComplex/ApartHotel)
PropertyClasskeywordдадаPropertyClassфильтр «класс»
RegionIdkeywordдадаRegionId (ссылка на справочник handbook)фильтр «регион»
CityIdkeywordдадаCityId (ссылка на справочник handbook)фильтр «город»
ConstructionStatuskeywordдадаConstructionStatusфильтр «статус строительства»
Price.MindoubleдадаPrice.Min (NullableRange<decimal>)фильтр «ценовой диапазон» + сортировка
Price.MaxdoubleдадаPrice.Maxфильтр
PropertyObjectsAvailableintegerдадаPropertyObjectsAvailableфильтр «есть доступные»
PromotionBoostintegerдадаPromotionBoostранжирование «Рекомендованные»
DeveloperPriorityintegerдадаDeveloperPriorityранжирование
PopularityScoredoubleдадаPopularityScoreсортировка «по популярности»
PublishedAtdateдадаPublishedAtсортировка «по дате»
StatuskeywordдадаStatussecurity-trimming (Published)
SchemaVersionintegerдададокументверсия схемы проекции
UpdatedAtdateдадакарточка UpdatedAtfreshness watermark
IndexedAtdateдадаиндексаторfreshness
к сведению
Анализатор ru_translit_fuzzy

Общий с property-objects.md: русская морфология + ICU-транслитерация

  • edge-ngram (typo-tolerance) + синонимы/алиасы (ADR-0059 п.1).

Source Events

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

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

Freshness

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

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-projects-v{N+1} (маппинг + ru_translit_fuzzy).
  2. Backfill из catalog.project_cards (Status != Delisted).
  3. Validate counts/checksums против source.
  4. Atomically switch alias catalog-projects (ADR-0029).
  5. Keep previous index до окончания rollback-окна.

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

Индекс недоступен

Полнотекстовый поиск и лента с searchTerm зависят от Elasticsearch; при недоступности индекса поиск деградирует — пользователю отдаётся признак «поиск временно недоступен», а интерфейс предлагает ленту без текстового запроса (сортировки/фильтры обслуживает витрина catalog.project_cards через API каталога и продолжают работать). «Примерную» FTS-выдачу из PostgreSQL не строим — FTS-колонок в источнике нет по построению (ADR-0059).

Отставание проекции

Только что опубликованный проект появляется в поиске (а скрытый — исчезает) после доезда ProjectCardRecomputedEvent и индексации (секунды–минуты); в окне рассинхронизации выдача помечается признаком свежести (FreshnessView). Точный статус для действий (бронь) поиском не подтверждается — это делает источник.

Rebuild без деградации выдачи

Пересборка идёт в теневой индекс catalog-projects-v{N+1}; алиас catalog-projects переключается только после валидации счётчиков/чек-сумм, поэтому частичный или упавший rebuild не отдаёт пользователю неполный индекс — активным остаётся прежний до успешного switch.

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

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

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