7.12 Hybrid: RRF và DBSF
Tầng 2 — Hybrid & Fusion đã nói vì sao hợp nhất hai nhánh lại giúp, và khi nào nó không giúp. Mục này nói về hai cách fusion mà Qdrant cài sẵn, công thức thật của chúng, và một cái bẫy riêng của chế độ phân tán mà tài liệu chung về hybrid không nhắc tới.
Bài toán: cộng hai thang đo không cùng đơn vị
Phần tiêu đề “Bài toán: cộng hai thang đo không cùng đơn vị”BM25 trả về: d008 → 12,4 d031 → 9,1 d012 → 7,8Cosine trả về: d008 → 0,71 d019 → 0,68 d031 → 0,52Cộng thẳng thì BM25 nuốt chửng cosine — không phải vì nó đúng hơn, mà vì số của nó to hơn. Chuẩn hoá bằng min-max cũng không cứu được: BM25 không có trần, và trần của nó thay đổi theo từng truy vấn.
Hai lời giải, hai triết lý ngược nhau:
| RRF | DBSF | |
|---|---|---|
| Đọc cái gì | chỉ thứ hạng | điểm số |
| Vứt đi cái gì | độ lớn của khoảng cách | không vứt gì |
| Bền với thang đo lệch | rất | vừa |
| Bền với ngoại lai | rất | kém |
| Có sẵn từ | v1.10 | v1.10 |
RRF — fusion theo thứ hạng
Phần tiêu đề “RRF — fusion theo thứ hạng”Công thức Qdrant cài đặt:
tổng chạy trên thứ hạng của ở mỗi danh sách có chứa .
r_d là thứ hạng của d trong một danh sách, đếm từ 0, và k mặc định là 2
(cấu hình được từ v1.16).
Tính bằng tay cho ví dụ trên, k = 2:
| doc | hạng BM25 | hạng cosine | RRF |
|---|---|---|---|
d008 | 0 | 0 | 1/2 + 1/2 = 1,000 |
d031 | 1 | 2 | 1/3 + 1/4 = 0,583 |
d012 | 2 | — | 1/4 = 0,250 |
d019 | — | 1 | 1/3 = 0,333 |
Thứ tự ra: d008, d031, d019, d012.
Ba điều đọc ra được từ bảng này:
- Xuất hiện ở cả hai danh sách là một lợi thế lớn.
d008thắng vì cả hai nhánh đều xếp nó đầu. Đây chính là tính chất bạn muốn ở hybrid. - Điểm gốc bị vứt hoàn toàn.
d031có BM25 = 9,1 (rất cao) nhưng chỉ được tính là “hạng 1”. Nếu độ lớn ấy có nghĩa, RRF đang phí thông tin. knhỏ làm đỉnh dốc hơn.k = 2khiến chênh lệch giữa hạng 0 và hạng 1 rất lớn (0,5 so với 0,333).klớn làm mọi thứ phẳng lại. Đây là núm ít người vặn nhưng có tác dụng thật.
Từ v1.17 có RRF có trọng số: mỗi prefetch nhân thêm một hệ số. Cảnh báo của chính Qdrant, và đáng nghe:
Trọng số là một lựa chọn cấu hình, không phải thứ vặn tuỳ hứng. Cách đáng tin duy nhất để đặt nó là thử trên dữ liệu của bạn với tập train/val tách riêng.
Nói cách khác: chỉnh trọng số bằng cảm giác trên vài truy vấn tự nghĩ ra là cách nhanh nhất để overfit vào chính những truy vấn đó. Xem Phần 2 — 6. Ý nghĩa thống kê.
DBSF — fusion theo phân phối điểm
Phần tiêu đề “DBSF — fusion theo phân phối điểm”DBSF đưa hai danh sách về cùng một thang bằng cách dùng trung bình và độ lệch chuẩn của chính danh sách đó trong truy vấn hiện tại:
Tức là: coi khoảng [μ − 3σ, μ + 3σ] là toàn bộ dải, rồi chiếu tuyến tính về [0, 1].
Sau đó cộng hai điểm đã chuẩn hoá lại.
Bốn đặc tính cần biết:
- Điểm không bị cắt về
[0, 1]. Giá trị ngoài dải 3σ vẫn nằm ngoài. Đây là chủ ý — một tài liệu vượt trội thật sự vẫn giữ được ưu thế của nó. - Khi mọi điểm bằng nhau, kết quả là 0,5 (tránh chia cho 0).
- Tính lại cho mỗi truy vấn, chỉ dựa trên top-k hiện tại. Không có trạng thái lưu giữa các truy vấn.
- Vì (3), một ngoại lai duy nhất trong top-k làm lệch chuẩn hoá. Qdrant khuyên: nếu
thấy thứ hạng không ổn định, tăng
limitcủa prefetch để μ và σ được ước lượng trên mẫu lớn hơn.
Khác biệt cốt lõi so với RRF: DBSF giữ được “thắng bao xa”. Một tài liệu bỏ xa phần còn lại trong một nhánh sẽ mang lợi thế đó vào kết quả fusion. RRF thì không — với RRF, thắng sát nút và thắng cách biệt đều chỉ là “hạng 0”.
Chọn cái nào
Phần tiêu đề “Chọn cái nào”Không cái nào thắng tuyệt đối. Khung quyết định của Qdrant, viết lại cho gọn:
| Tình huống của bạn | Chọn |
|---|---|
| Có golden set, có thể tách train/val | RRF có trọng số, chỉnh trọng số trên tập train |
| Không có golden set, nhưng tin rằng điểm số của hai nhánh có nghĩa và được hiệu chuẩn | DBSF |
| Không có golden set, không biết gì về điểm số | RRF — mặc định an toàn |
| Điểm số một nhánh hay có ngoại lai | RRF (DBSF nhạy với ngoại lai) |
Và một câu nên nhắc lại từ Tầng 2:
Hybrid không phải lúc nào cũng giúp. Nếu nhánh sparse của bạn kém, fusion chỉ kéo nhánh dense xuống. Đo từng nhánh riêng trước, rồi mới đo bản fusion.
⚠️ Bẫy phân tán: fusion tính theo từng shard
Phần tiêu đề “⚠️ Bẫy phân tán: fusion tính theo từng shard”Đây là chi tiết ít được nhắc mà hậu quả thì lớn, và nó chỉ xuất hiện khi collection có nhiều shard:
Nếu
fusionnằm bên trong mộtprefetch, mỗi shard tự hợp nhất kết quả cục bộ của nó. Thứ hạng sau fusion là theo từng shard, không phải toàn cục.Muốn fusion toàn cục,
fusionphải là truy vấn chính.
SAI (khi nhiều shard): ĐÚNG:{ { "prefetch": { "prefetch": [ {dense}, {sparse} ], "prefetch": [{dense},{sparse}], "query": { "fusion": "rrf" } "query": {"fusion":"rrf"} } }, "query": <rerank>}⇒ fusion chạy trong từng shard ⇒ fusion chạy trên kết quả gộpHệ quả xấu tính: hệ của bạn chạy đúng suốt thời gian dev trên một shard, rồi thay đổi hành vi khi lên production nhiều shard — mà không có lỗi nào. Nếu bạn đang xây cascade “hybrid rồi rerank” trên cụm phân tán, đọc lại đoạn này hai lần.
Formula chồng lên fusion: cẩn thận độ lớn
Phần tiêu đề “Formula chồng lên fusion: cẩn thận độ lớn”Mẫu rất hay dùng: fusion bằng RRF trong prefetch, rồi bọc bằng một formula để thêm
logic nghiệp vụ (ưu tiên tài liệu mới, đẩy sản phẩm phổ biến lên — xem
7.14).
Cái bẫy nằm ở độ lớn:
Điểm RRF là tổng của các
1/(k + hạng)— rất nhỏ (ví dụ trên: 1,0 là điểm cao nhất có thể khi có hai danh sách vàk=2). Trong khi hàm decay trả về giá trị trong[0, 1]. Cộng thẳng thì thành phần nghiệp vụ nuốt chửng thành phần liên quan.
Phải nhân thành phần decay với một hệ số nhỏ. Và phải đo lại sau khi làm — đây đúng là loại thay đổi làm nDCG tụt mà không ai nhận ra, vì kết quả “trông vẫn hợp lý”.