diff --git a/app/core/ranking.py b/app/core/ranking.py new file mode 100644 index 0000000..e9105f3 --- /dev/null +++ b/app/core/ranking.py @@ -0,0 +1,56 @@ +""" +app/core/ranking.py — Kombiniertes Scoring (WP-04) + +Zweck: + Zusammenführen von semantischem Score (normalisiert), Edge-Bonus und + Centrality-Bonus in einen Gesamtscore für die Ergebnisreihung. +Kompatibilität: + Python 3.12+ +Version: + 0.1.0 (Erstanlage) +Stand: + 2025-10-07 +Bezug: + WP-04 Ranking-Formel (w_sem, w_edge, w_cent) +Nutzung: + from app.core.ranking import combine_scores +Änderungsverlauf: + 0.1.0 (2025-10-07) – Erstanlage. +""" + +from __future__ import annotations +from typing import List, Tuple, Dict + + +def normalize_scores(values: List[float]) -> List[float]: + """Min-Max-Normalisierung über die Kandidatenmenge (Fallback 0.5 bei Konstanz).""" + if not values: + return values + lo, hi = min(values), max(values) + if hi - lo < 1e-9: + return [0.5] * len(values) + return [(v - lo) / (hi - lo) for v in values] + + +def combine_scores( + hits: List[Tuple[str, float, dict]], # (id, semantic_score, payload) + edge_bonus_map: Dict[str, float], + centrality_map: Dict[str, float], + w_sem: float = 0.70, + w_edge: float = 0.25, + w_cent: float = 0.05, +) -> List[Tuple[str, float, float, float, float]]: + """ + Liefert Liste von (point_id, total_score, edge_bonus, centrality_bonus, raw_semantic_score), + absteigend nach total_score sortiert. + """ + sem = [h[1] for h in hits] + sem_n = normalize_scores(sem) + out = [] + for (pid, s, payload), s_norm in zip(hits, sem_n): + e = edge_bonus_map.get(pid, 0.0) + c = centrality_map.get(pid, 0.0) + total = w_sem * s_norm + w_edge * e + w_cent * c + out.append((pid, total, e, c, s)) + out.sort(key=lambda t: t[1], reverse=True) + return out