Skip to content

Commit a92e6fd

Browse files
authored
Micro-optimizations of search score handling. (#8230)
1 parent 71f1918 commit a92e6fd

File tree

2 files changed

+36
-10
lines changed

2 files changed

+36
-10
lines changed

app/lib/search/mem_index.dart

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ class InMemoryPackageIndex {
314314
final coreScores = <Score>[];
315315
var wordScopedPackages = packages;
316316
for (final word in words) {
317-
final nameScore =
318-
_packageNameIndex.searchWord(word, packages: wordScopedPackages);
317+
final nameScore = _packageNameIndex.searchWord(word,
318+
filterOnPackages: wordScopedPackages);
319319
if (includeNameMatches && _documentsByName.containsKey(word)) {
320320
nameMatches ??= <String>{};
321321
nameMatches.add(word);
@@ -520,13 +520,33 @@ class PackageNameIndex {
520520
package.replaceAll('_', '').toLowerCase();
521521

522522
/// Search [text] and return the matching packages with scores.
523+
@visibleForTesting
523524
Score search(String text) {
524-
return Score.multiply(splitForQuery(text).map(searchWord).toList());
525+
Score? score;
526+
for (final w in splitForQuery(text)) {
527+
final s = searchWord(w, filterOnPackages: score?.keys);
528+
if (score == null) {
529+
score = s;
530+
} else {
531+
// Note: on one hand, it is inefficient to multiply the [Score] on each
532+
// iteration. However, (1) this is only happening in test, (2) it may be
533+
// better for the next iteration to work on a more limited `filterOnPackages`,
534+
// and (3) it will be updated to a more efficient in-place update (#8225).
535+
score = Score.multiply([score, s]);
536+
}
537+
}
538+
return score ?? Score.empty;
525539
}
526540

527-
/// Search using the parsed [word] and return the match packages with scores.
528-
Score searchWord(String word, {Set<String>? packages}) {
529-
final pkgNamesToCheck = packages ?? _packageNames;
541+
/// Search using the parsed [word] and return the matching packages with scores
542+
/// as a new [Score] instance.
543+
///
544+
/// When [filterOnPackages] is present, only the names present are evaluated.
545+
Score searchWord(
546+
String word, {
547+
Iterable<String>? filterOnPackages,
548+
}) {
549+
final pkgNamesToCheck = filterOnPackages ?? _packageNames;
530550
final values = <String, double>{};
531551
final singularWord = word.length <= 3 || !word.endsWith('s')
532552
? word
@@ -549,11 +569,16 @@ class PackageNameIndex {
549569
matched++;
550570
}
551571
}
572+
573+
// making sure that match score is minimum 0.5
552574
if (matched > 0) {
553-
values[pkg] = matched / parts.length;
575+
final v = matched / parts.length;
576+
if (v >= 0.5) {
577+
values[pkg] = v;
578+
}
554579
}
555580
}
556-
return Score(values).removeLowValues(fraction: 0.5, minValue: 0.5);
581+
return Score(values);
557582
}
558583
}
559584

app/lib/search/token_index.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,10 @@ class TokenIndex {
164164
}
165165
// Document weight is a highly scaled-down proxy of the length.
166166
final dw = 1 + math.log(1 + tokens.length) / 100;
167-
for (final token in tokens.keys) {
167+
for (final e in tokens.entries) {
168+
final token = e.key;
168169
final weights = _inverseIds.putIfAbsent(token, () => {});
169-
weights[i] = math.max(weights[i] ?? 0.0, tokens[token]! / dw);
170+
weights[i] = math.max(weights[i] ?? 0.0, e.value / dw);
170171
}
171172
}
172173
}

0 commit comments

Comments
 (0)