Skip to content

Commit d7eb238

Browse files
authored
Using IndexedScore as part of the search pre-filtering. (#8232)
1 parent b28c3e0 commit d7eb238

File tree

3 files changed

+72
-28
lines changed

3 files changed

+72
-28
lines changed

app/lib/search/mem_index.dart

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -113,31 +113,28 @@ class InMemoryPackageIndex {
113113
}
114114

115115
PackageSearchResult search(ServiceSearchQuery query) {
116-
final packages = Set<String>.of(_documentsByName.keys);
116+
final packageScores = IndexedScore(_packageNameIndex._packageNames, 1.0);
117117

118118
// filter on package prefix
119119
if (query.parsedQuery.packagePrefix != null) {
120120
final String prefix = query.parsedQuery.packagePrefix!.toLowerCase();
121-
packages.removeWhere(
122-
(package) => !_documentsByName[package]!
123-
.package
124-
.toLowerCase()
125-
.startsWith(prefix),
121+
packageScores.retainWhere(
122+
(i, _) => _documents[i].packageNameLowerCased.startsWith(prefix),
126123
);
127124
}
128125

129126
// filter on tags
130127
final combinedTagsPredicate =
131128
query.tagsPredicate.appendPredicate(query.parsedQuery.tagsPredicate);
132129
if (combinedTagsPredicate.isNotEmpty) {
133-
packages.retainWhere((package) => combinedTagsPredicate
134-
.matches(_documentsByName[package]!.tagsForLookup));
130+
packageScores.retainWhere(
131+
(i, _) => combinedTagsPredicate.matches(_documents[i].tagsForLookup));
135132
}
136133

137134
// filter on dependency
138135
if (query.parsedQuery.hasAnyDependency) {
139-
packages.removeWhere((package) {
140-
final doc = _documentsByName[package]!;
136+
packageScores.removeWhere((i, _) {
137+
final doc = _documents[i];
141138
if (doc.dependencies.isEmpty) return true;
142139
for (final dependency in query.parsedQuery.allDependencies) {
143140
if (!doc.dependencies.containsKey(dependency)) return true;
@@ -152,22 +149,18 @@ class InMemoryPackageIndex {
152149

153150
// filter on points
154151
if (query.minPoints != null && query.minPoints! > 0) {
155-
packages.removeWhere((package) {
156-
final doc = _documentsByName[package]!;
157-
return doc.grantedPoints < query.minPoints!;
158-
});
152+
packageScores.removeWhere(
153+
(i, _) => _documents[i].grantedPoints < query.minPoints!);
159154
}
160155

161156
// filter on updatedDuration
162157
final updatedDuration = query.parsedQuery.updatedDuration;
163158
if (updatedDuration != null && updatedDuration > Duration.zero) {
164159
final now = clock.now();
165-
packages.removeWhere((package) {
166-
final doc = _documentsByName[package]!;
167-
final diff = now.difference(doc.updated);
168-
return diff > updatedDuration;
169-
});
160+
packageScores.removeWhere(
161+
(i, _) => now.difference(_documents[i].updated) > updatedDuration);
170162
}
163+
final packages = packageScores.toKeySet();
171164

172165
// do text matching
173166
final parsedQueryText = query.parsedQuery.text;

app/lib/search/search_service.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class PackageDocument {
132132

133133
@JsonKey(includeFromJson: false, includeToJson: false)
134134
late final Set<String> tagsForLookup = Set.of(tags);
135+
136+
late final packageNameLowerCased = package.toLowerCase();
135137
}
136138

137139
/// A reference to an API doc page

app/lib/search/token_index.dart

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,27 +214,26 @@ class TokenIndex {
214214
Map<String, double> _scoreDocs(TokenMatch tokenMatch,
215215
{double weight = 1.0, Set<String>? limitToIds}) {
216216
// Summarize the scores for the documents.
217-
final docScores = List<double>.filled(_length, 0.0);
217+
final scores = IndexedScore(_ids);
218218
for (final token in tokenMatch.tokens) {
219219
final docWeights = _inverseIds[token]!;
220220
for (final e in docWeights.entries) {
221-
final i = e.key;
222-
docScores[i] = math.max(docScores[i], tokenMatch[token]! * e.value);
221+
scores.setValueMaxOf(e.key, tokenMatch[token]! * e.value);
223222
}
224223
}
225224

225+
if (limitToIds != null) {
226+
scores.retainWhere((_, id) => limitToIds.contains(id));
227+
}
226228
final result = <String, double>{};
227229
// post-process match weights
228230
for (var i = 0; i < _length; i++) {
229-
final id = _ids[i];
230-
final w = docScores[i];
231+
final w = scores._values[i];
231232
if (w <= 0.0) {
232233
continue;
233234
}
234-
if (limitToIds != null && !limitToIds.contains(id)) {
235-
continue;
236-
}
237-
result[id] = w * weight;
235+
final id = _ids[i];
236+
result[id] = scores._values[i] * weight;
238237
}
239238
return result;
240239
}
@@ -269,3 +268,53 @@ class TokenIndex {
269268
return Score.multiply(scores);
270269
}
271270
}
271+
272+
/// Mutable score list that can accessed via integer index.
273+
class IndexedScore {
274+
final List<String> _keys;
275+
final List<double> _values;
276+
277+
IndexedScore._(this._keys, this._values);
278+
279+
factory IndexedScore(List<String> keys, [double value = 0.0]) =>
280+
IndexedScore._(keys, List<double>.filled(keys.length, value));
281+
282+
late final length = _values.length;
283+
284+
bool isNotPositive(int index) {
285+
return _values[index] <= 0.0;
286+
}
287+
288+
void setValueMaxOf(int index, double value) {
289+
_values[index] = math.max(_values[index], value);
290+
}
291+
292+
void removeWhere(bool Function(int index, String key) fn) {
293+
for (var i = 0; i < length; i++) {
294+
if (isNotPositive(i)) continue;
295+
if (fn(i, _keys[i])) {
296+
_values[i] = 0.0;
297+
}
298+
}
299+
}
300+
301+
void retainWhere(bool Function(int index, String key) fn) {
302+
for (var i = 0; i < length; i++) {
303+
if (isNotPositive(i)) continue;
304+
if (!fn(i, _keys[i])) {
305+
_values[i] = 0.0;
306+
}
307+
}
308+
}
309+
310+
Set<String> toKeySet() {
311+
final set = <String>{};
312+
for (var i = 0; i < _values.length; i++) {
313+
final v = _values[i];
314+
if (v > 0.0) {
315+
set.add(_keys[i]);
316+
}
317+
}
318+
return set;
319+
}
320+
}

0 commit comments

Comments
 (0)