Vấn đề
Cùng một toà nhà nhưng mỗi nhà cung cấp gọi bằng một mã khác nhau. Resolve sai mã thì cả một vùng tìm kiếm trả về 0 khách sạn — người dùng chỉ thấy "không có phòng", không thấy lỗi.
Cách hiển nhiên là join qua mã GIATA của ngành. Nhưng join thẳng gần như không
ra gì: 2.639 trên 2.773 mã GIATA không tồn tại trong bảng của mình, vì cột
giata_id mới chỉ có ở 362.653 trên 1.896.030 dòng.
Cách làm
Bắc cầu qua nhà cung cấp khác. Với mỗi mã GIATA, lấy các mã mà nó mang cho những supplier khác, tìm ra dòng của mình qua bất kỳ cột nào trong số đó, rồi mới xác minh ứng viên bằng độ giống tên và khoảng cách lat/long trước khi ghi. Số supplier độc lập cùng trỏ về một dòng chính là điểm tin cậy.
Phần so khớp tên: gom theo quốc gia để cắt không gian so sánh, lọc theo khoảng
cách trước khi gọi hàm đắt tiền, ngưỡng cấu hình được, và một model TF-IDF/n-gram
chỉ bỏ đúng hai token chung chung nhất rồi để model tự học trọng số phần còn lại
— giữ fuzzball làm fallback nhanh.
Danh tính khách sạn có tính bắc cầu, nên phần tra cứu chạy trên graph Neo4j
với quan hệ SAME_AS và truy vấn độ sâu thay đổi được.
Mọi campaign: dry-run trước → phân loại rõ điền-chỗ-trống / ghi-đè / bỏ-qua → ghi xong đọc lại từng dòng để verify → chạy dry lần nữa để chứng minh idempotent.
Kết quả
Lần ghi lớn nhất trong một campaign: +109.786 dòng (98.588 điền chỗ trống, 11.198 ghi đè chắc chắn), trong khi 186.593 dòng được cố ý giữ nguyên.
Chất lượng: 1.668 trên 1.702 mapping mới được ít nhất 2 supplier độc lập xác nhận (trung vị 7), độ giống tên trung bình 94,9%, và 1.499 nằm trong bán kính 100 m.
Và nhóm chốt một chính sách: chỉ định danh có bằng chứng từ supplier mới được vào bảng — tên cộng toạ độ chỉ là gợi ý, không phải bằng chứng. Thực thi chính sách đó nghĩa là rollback từng dòng một campaign 11.953 dòng vốn chỉ dựa trên tên với toạ độ, sau rollback verify lại còn đúng 286.105 dòng non-null. Cú rollback ấy không phải chuyện dọn dẹp — đó là chính sách bằng chứng được thực thi lên chính sản phẩm của mình.