ADR-0002. Index Typesense denormalized điều khiển bởi CDC với cascade fan-out
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-02-15 |
| Deciders | @search-team |
| Supersedes | — |
Bối cảnh
- Dữ liệu nguồn được normalized trên nhiều bảng ở ba schema (
public,pricing,inventory); một product document cần trường từ Product, ProductInfo, ProductCategory, MetaLink, FareSet/Fare, ProductBundler. - Typesense document phải phẳng/denormalized cho query keyword + facet nhanh; trường
referencechỉ hỗ trợ một FK scalar đơn. - Một pipeline CDC Debezium → Kafka đã stream thay đổi dòng; search nên consume nó thay vì poll hoặc bị ghi đồng bộ.
- Một số bảng nguồn là doc principal (Product →
products); số khác là bảng join/related chỉ sửa trường của một principal (ProductCategory ảnh hưởngcategoryIds).
Quyết định
Chúng tôi sẽ duy trì Typesense document denormalized được feed bởi CDC. TableToCollectionMap route direct source tới một collection qua entity mapper; cascade-only source (bảng join/related) được fan out bởi CDCCascadeService để tính lại trường bị ảnh hưởng trên document principal, với CDCEnrichmentService hydrate dữ liệu cross-collection. An toàn sai thứ tự đến từ guard LSN/version (source_lsn, deleted_at).
Hệ quả
| Ưu | Nhược |
|---|---|
| Query phẳng + facet nhanh không cần join lúc runtime | Nhất quán cuối cùng (CDC delay) so với DB nguồn |
| Sync gần-real-time không cần ghi đồng bộ từ nguồn | Logic cascade phải biết mọi trường phụ thuộc theo từng principal |
| Guard LSN làm replay/event sai thứ tự idempotent | Trường denormalized (vd tên parent, flags) có thể drift và cần backfill/reindex |
| Một Kafka consumer phủ 18 topic trên 3 schema | Ghép với đặt tên topic Debezium + config connector |
Các phương án đã cân nhắc
| Phương án | Ưu | Nhược | Lý do loại bỏ |
|---|---|---|---|
| Join lúc-query trong Typesense / app | Luôn tươi | Chậm; reference giới hạn một FK scalar đơn | Đánh bại mục đích của một search index |
| Dual-write đồng bộ từ source service | Nhất quán tức thì | Ghép mọi writer với Typesense; rủi ro partial-failure | Mong manh; lan mối quan tâm search khắp nơi |
| Full reindex định kỳ từ DB | Đơn giản | Stale giữa các lần chạy; tải nặng | Không đủ real-time cho POS |
Tham chiếu
packages/search/src/common/kafka-topics.ts—TableToCollectionMap,ALL_CDC_TOPICS- API Events
- Domain Model