@@ -93,44 +93,98 @@ func (ps *PrefixStore) AddPrefix(ctx context.Context, prefix string, pod types.N
93
93
}
94
94
95
95
// 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 ) {
97
137
ps .mu .RLock ()
98
138
defer ps .mu .RUnlock ()
99
139
100
140
logger := log .FromContext (ctx )
101
141
102
142
if len (prefix ) < ps .config .MinPrefixLen {
103
143
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
105
145
}
106
146
107
147
if len (prefix ) > ps .config .MaxPrefixLen {
108
148
logger .V (logging .DEBUG ).Info ("Truncating prefix" , "originalLength" , len (prefix ), "maxLength" , ps .config .MaxPrefixLen )
109
149
prefix = prefix [:ps .config .MaxPrefixLen ]
110
150
}
111
151
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
118
155
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 )
120
159
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 )
128
167
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
+ }
132
185
133
- return entry .PodRef , true
186
+ logger .V (logging .DEBUG ).Info ("No matching pod found" , "prefix" , prefix )
187
+ return types.NamespacedName {}, 0 , false
134
188
}
135
189
136
190
// evictOldest removes the oldest entry from the store
0 commit comments