Skip to content

Commit b3a2149

Browse files
committed
Add partial match scoring
Signed-off-by: Ricardo Noriega <rnoriega@redhat.com>
1 parent 037fadd commit b3a2149

File tree

2 files changed

+80
-31
lines changed

2 files changed

+80
-31
lines changed

pkg/epp/scheduling/prefix_aware_scorer.go

+6-11
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (s *PrefixAwareScorer) ScoreTargets(ctx *types.Context, pods []*types.PodMe
5959
}
6060

6161
// Find the best matching pod for the prompt
62-
matchedPod, found := s.prefixStore.FindPodForPrefix(ctx, prompt, ctx.Req.ResolvedTargetModel)
62+
matchedPod, score, found := s.prefixStore.FindPodForPrefix(ctx, prompt, ctx.Req.ResolvedTargetModel)
6363
if !found {
6464
logger.V(logging.DEBUG).Info("No matching prefix found, returning zero scores for all pods")
6565
// If no matching prefix found, return zero scores for all pods
@@ -72,23 +72,18 @@ func (s *PrefixAwareScorer) ScoreTargets(ctx *types.Context, pods []*types.PodMe
7272
return scoredPods, nil
7373
}
7474

75-
// Assign scores based on pod match
75+
// Assign scores based on whether the pod matches the best matching pod
7676
for i, pod := range pods {
7777
if pod.NamespacedName == matchedPod {
78-
logger.V(logging.DEBUG).Info("Pod matched for prefix",
79-
"prompt", prompt,
80-
"pod", pod.NamespacedName.String(),
81-
"score", s.weight)
78+
logger.V(logging.DEBUG).Info("Pod matched for prefix", "prompt", prompt, "pod", pod.String(), "score", score)
8279
scoredPods[i] = PodScore{
83-
Score: s.weight, // Use the configured weight for the matching pod
80+
Score: score,
8481
Pod: pod,
8582
}
8683
} else {
87-
logger.V(logging.DEBUG).Info("Pod did not match",
88-
"pod", pod.NamespacedName.String(),
89-
"score", 0)
84+
logger.V(logging.DEBUG).Info("Pod did not match", "pod", pod.String(), "score", 0)
9085
scoredPods[i] = PodScore{
91-
Score: 0, // Zero score for non-matching pods
86+
Score: 0,
9287
Pod: pod,
9388
}
9489
}

pkg/epp/scheduling/prefix_store.go

+74-20
Original file line numberDiff line numberDiff line change
@@ -93,44 +93,98 @@ func (ps *PrefixStore) AddPrefix(ctx context.Context, prefix string, pod types.N
9393
}
9494

9595
// FindPodForPrefix finds the best matching pod for a given prefix and model
96-
func (ps *PrefixStore) FindPodForPrefix(ctx context.Context, prefix string, modelName string) (types.NamespacedName, bool) {
96+
func (ps *PrefixStore) FindPodForPrefix(ctx context.Context, prefix string, modelName string) (types.NamespacedName, float64, bool) {
97+
pod, score, found := ps.FindBestMatch(ctx, prefix, modelName)
98+
if found && score > 0.2 { // Only consider matches with score > 20%
99+
return pod, score, true
100+
}
101+
return types.NamespacedName{}, 0, false
102+
}
103+
104+
// calculateMatchScore calculates the similarity score between two strings
105+
// Returns a value between 0 and 1, where 1 is a perfect match
106+
func calculateMatchScore(s1, s2 string) float64 {
107+
// Convert to runes to handle Unicode properly
108+
r1 := []rune(s1)
109+
r2 := []rune(s2)
110+
111+
// Find the shorter length
112+
minLen := len(r1)
113+
if len(r2) < minLen {
114+
minLen = len(r2)
115+
}
116+
if minLen == 0 {
117+
return 0
118+
}
119+
120+
// Count matching characters
121+
matches := 0
122+
for i := 0; i < minLen; i++ {
123+
if r1[i] == r2[i] {
124+
matches++
125+
} else {
126+
break // Stop at first mismatch
127+
}
128+
}
129+
130+
// Calculate score based on the length of the match
131+
return float64(matches) / float64(len(r1))
132+
}
133+
134+
// FindBestMatch finds the best matching pod for a given prefix and model
135+
// Returns the pod reference, match score (0-1), and whether a match was found
136+
func (ps *PrefixStore) FindBestMatch(ctx context.Context, prefix string, modelName string) (types.NamespacedName, float64, bool) {
97137
ps.mu.RLock()
98138
defer ps.mu.RUnlock()
99139

100140
logger := log.FromContext(ctx)
101141

102142
if len(prefix) < ps.config.MinPrefixLen {
103143
logger.V(logging.DEBUG).Info("Prefix too short", "prefix", prefix, "minLength", ps.config.MinPrefixLen)
104-
return types.NamespacedName{}, false
144+
return types.NamespacedName{}, 0, false
105145
}
106146

107147
if len(prefix) > ps.config.MaxPrefixLen {
108148
logger.V(logging.DEBUG).Info("Truncating prefix", "originalLength", len(prefix), "maxLength", ps.config.MaxPrefixLen)
109149
prefix = prefix[:ps.config.MaxPrefixLen]
110150
}
111151

112-
// Use LongestPrefix to find the best match
113-
matchedPrefix, val, found := ps.tree.LongestPrefix(prefix)
114-
if !found {
115-
logger.V(logging.DEBUG).Info("No matching prefix found", "prefix", prefix)
116-
return types.NamespacedName{}, false
117-
}
152+
var bestPod types.NamespacedName
153+
var bestScore float64
154+
var found bool
118155

119-
entry := val.(*PrefixEntry)
156+
// Walk through all prefixes in the tree
157+
ps.tree.Walk(func(storedPrefix string, value interface{}) bool {
158+
entry := value.(*PrefixEntry)
120159

121-
// Check if entry has expired or model doesn't match
122-
if time.Since(entry.LastUsed) > ps.config.EntryTTL {
123-
return types.NamespacedName{}, false
124-
}
125-
if entry.ModelName != modelName {
126-
return types.NamespacedName{}, false
127-
}
160+
// Skip if model doesn't match or entry has expired
161+
if entry.ModelName != modelName || time.Since(entry.LastUsed) > ps.config.EntryTTL {
162+
return false
163+
}
164+
165+
// Calculate match score
166+
score := calculateMatchScore(prefix, storedPrefix)
128167

129-
// Update LastUsed time for the matched entry
130-
entry.LastUsed = time.Now()
131-
ps.tree.Insert(matchedPrefix, entry)
168+
// Update best match if this is better
169+
if score > bestScore {
170+
bestScore = score
171+
bestPod = entry.PodRef
172+
found = true
173+
}
174+
175+
return false // Continue walking
176+
})
177+
178+
if found {
179+
logger.V(logging.DEBUG).Info("Found best matching pod",
180+
"prefix", prefix,
181+
"pod", bestPod.String(),
182+
"score", bestScore)
183+
return bestPod, bestScore, true
184+
}
132185

133-
return entry.PodRef, true
186+
logger.V(logging.DEBUG).Info("No matching pod found", "prefix", prefix)
187+
return types.NamespacedName{}, 0, false
134188
}
135189

136190
// evictOldest removes the oldest entry from the store

0 commit comments

Comments
 (0)