Files
陈世睿 917613c5ce 初始化 dish-image-toolkit:菜品图爬虫 + 图片名称检索平台
- crawler/:豆果(主)/下厨房/Bing 爬虫 + dishes.jsonl(3056 菜→9167 图映射)+ verify_repair 按 URL 重下
- retrieval/:三路检索(BM25 + 本地 BGE-M3 向量 + RRF 融合),FastAPI + 前端;
  写死图片目录(默认 crawler/images,可 IMAGE_DIR 覆盖)、绑 0.0.0.0 局域网访问、
  启动自动建索引、服务器 serve 图片
- 图片(1.7G)与向量模型(2.3G)不进 git

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 10:27:51 +08:00

20 lines
873 B
Python

# -*- coding: utf-8 -*-
"""RRF(Reciprocal Rank Fusion)融合多路排名。
RRF 只看「排名」不看「分数量纲」,天然解决 BM25 分数与余弦相似度不可比的问题:
fused(d) = Σ_method w_method * 1 / (k + rank_method(d))
k 越大,头部名次的权重差异越平缓(经验默认 60)。
"""
from __future__ import annotations
def rrf(rankings: dict[str, list[str]], weights: dict[str, float],
k: int = 60) -> list[tuple[str, float]]:
"""rankings: {method: [name 按相关性降序]};返回 [(name, fused_score)] 降序。"""
score: dict[str, float] = {}
for method, names in rankings.items():
w = weights.get(method, 1.0)
for rank, name in enumerate(names, start=1):
score[name] = score.get(name, 0.0) + w * (1.0 / (k + rank))
return sorted(score.items(), key=lambda kv: kv[1], reverse=True)