Skip to content

Commit

Permalink
Pre-compute overallScore hit ordered list in search. (#7137)
Browse files Browse the repository at this point in the history
  • Loading branch information
isoos authored Oct 31, 2023
1 parent 61cb8b2 commit 60c114d
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 22 deletions.
43 changes: 31 additions & 12 deletions app/lib/search/mem_index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ class InMemoryPackageIndex {
final TokenIndex _descrIndex = TokenIndex();
final TokenIndex _readmeIndex = TokenIndex();
final TokenIndex _apiSymbolIndex = TokenIndex();

/// Adjusted score takes the overall score and transforms
/// it linearly into the [0.4-1.0] range.
final _adjustedOverallScores = <String, double>{};
late final List<PackageHit> _overallOrderedHits;
late final List<PackageHit> _createdOrderedHits;
late final List<PackageHit> _updatedOrderedHits;
late final List<PackageHit> _popularityOrderedHits;
Expand All @@ -42,7 +47,10 @@ class InMemoryPackageIndex {
if (_packages.values.any((e) => e.likeScore == null)) {
_packages.values.updateLikeScores();
}
_updateOverallScores();
_lastUpdated = clock.now().toUtc();
_overallOrderedHits = _rankWithComparator(_compareOverall,
score: (doc) => doc.overallScore ?? 0.0);
_createdOrderedHits = _rankWithComparator(_compareCreated);
_updatedOrderedHits = _rankWithComparator(_compareUpdated);
_popularityOrderedHits = _rankWithComparator(_comparePopularity,
Expand Down Expand Up @@ -143,11 +151,16 @@ class InMemoryPackageIndex {
late List<PackageHit> packageHits;
switch (query.effectiveOrder ?? SearchOrder.top) {
case SearchOrder.top:
final scores = <Score>[
_getOverallScore(packages),
if (textResults != null) textResults.pkgScore,
];
final overallScore = Score.multiply(scores);
if (textResults == null) {
packageHits = _overallOrderedHits.whereInSet(packages);
break;
}

/// Adjusted score takes the overall score and transforms
/// it linearly into the [0.4-1.0] range, to allow better
/// multiplication outcomes.
final overallScore = textResults.pkgScore
.map((key, value) => value * _adjustedOverallScores[key]!);
// If the search hits have an exact name match, we move it to the front of the result list.
final parsedQueryText = query.parsedQuery.text;
final priorityPackageName =
Expand Down Expand Up @@ -201,18 +214,18 @@ class InMemoryPackageIndex {
);
}

Score _getOverallScore(Iterable<String> packages) {
final values = Map<String, double>.fromEntries(packages.map((package) {
final doc = _packages[package]!;
/// Update the overall score both on [PackageDocument] and in the [_adjustedOverallScores] map.
void _updateOverallScores() {
for (final doc in _packages.values) {
final downloadScore = doc.popularityScore ?? 0.0;
final likeScore = doc.likeScore ?? 0.0;
final popularity = (downloadScore + likeScore) / 2;
final points = doc.grantedPoints / math.max(1, doc.maxPoints);
final overall = popularity * 0.5 + points * 0.5;
// don't multiply with zero.
return MapEntry(package, 0.4 + 0.6 * overall);
}));
return Score(values);
doc.overallScore = overall;
// adding a base score prevents later multiplication with zero
_adjustedOverallScores[doc.package] = 0.4 + 0.6 * overall;
}
}

_TextResults? _searchText(Set<String> packages, String? text) {
Expand Down Expand Up @@ -359,6 +372,12 @@ class InMemoryPackageIndex {
return -a.updated.compareTo(b.updated);
}

int _compareOverall(PackageDocument a, PackageDocument b) {
final x = -(a.overallScore ?? 0.0).compareTo(b.overallScore ?? 0.0);
if (x != 0) return x;
return _compareUpdated(a, b);
}

int _comparePopularity(PackageDocument a, PackageDocument b) {
final x = -(a.popularityScore ?? 0.0).compareTo(b.popularityScore ?? 0.0);
if (x != 0) return x;
Expand Down
3 changes: 3 additions & 0 deletions app/lib/search/search_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class PackageDocument {
final int grantedPoints;
final int maxPoints;

/// The normalized overall score between [0.0-1.0] for default package listing.
double? overallScore;

final Map<String, String> dependencies;

final List<ApiDocPage>? apiDocPages;
Expand Down
3 changes: 2 additions & 1 deletion app/lib/search/search_service.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions app/test/search/mem_index_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'packageHits': [
{
'package': 'chrome_net',
'score': closeTo(0.54, 0.1),
'score': closeTo(0.08, 0.1),
},
],
});
Expand Down Expand Up @@ -328,8 +328,8 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'totalCount': 2,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'http', 'score': closeTo(0.96, 0.01)},
{'package': 'async', 'score': closeTo(0.65, 0.01)},
{'package': 'http', 'score': closeTo(0.92, 0.01)},
{'package': 'async', 'score': closeTo(0.41, 0.01)},
],
});

Expand All @@ -347,7 +347,7 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'totalCount': 1,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'chrome_net', 'score': closeTo(0.45, 0.01)},
{'package': 'chrome_net', 'score': closeTo(0.08, 0.01)},
],
});
});
Expand All @@ -360,8 +360,8 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'totalCount': 2,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'http', 'score': closeTo(0.96, 0.01)},
{'package': 'chrome_net', 'score': closeTo(0.45, 0.01)},
{'package': 'http', 'score': closeTo(0.92, 0.01)},
{'package': 'chrome_net', 'score': closeTo(0.08, 0.01)},
],
});

Expand Down Expand Up @@ -392,7 +392,7 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'totalCount': 1,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'http', 'score': closeTo(0.96, 0.01)},
{'package': 'http', 'score': closeTo(0.92, 0.01)},
],
});
});
Expand All @@ -416,7 +416,7 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'totalCount': 1,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'async', 'score': closeTo(0.65, 0.01)},
{'package': 'async', 'score': closeTo(0.41, 0.01)},
],
});

Expand Down
2 changes: 1 addition & 1 deletion app/test/search/result_combiner_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void main() {
'totalCount': 1,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'stringutils', 'score': closeTo(0.91, 0.01)},
{'package': 'stringutils', 'score': closeTo(0.85, 0.01)},
],
});
});
Expand Down

0 comments on commit 60c114d

Please sign in to comment.