Coverage for src/qdrant_loader_mcp_server/search/hybrid/components/scoring.py: 91%
23 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-08 06:06 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-08 06:06 +0000
1from __future__ import annotations
3from collections.abc import Iterable
4from dataclasses import dataclass
7@dataclass
8class ScoreComponents:
9 vector_score: float
10 keyword_score: float
11 metadata_score: float
14class HybridScorer:
15 """Compute hybrid scores from component scores using simple weighted sum.
17 This is an initial scaffold to enable modularization. The engine continues
18 to own the weights; this class only applies them deterministically.
19 """
21 def __init__(
22 self, vector_weight: float, keyword_weight: float, metadata_weight: float
23 ):
24 self.vector_weight = float(vector_weight)
25 self.keyword_weight = float(keyword_weight)
26 self.metadata_weight = float(metadata_weight)
28 def compute(self, components: ScoreComponents) -> float:
29 return (
30 components.vector_score * self.vector_weight
31 + components.keyword_score * self.keyword_weight
32 + components.metadata_score * self.metadata_weight
33 )
35 def normalize_many(self, scores: Iterable[float]) -> list[float]:
36 values = list(scores)
37 if not values:
38 return []
39 max_value = max(values)
40 if max_value <= 0:
41 return [0.0 for _ in values]
42 return [v / max_value for v in values]