Skip to content

Commit

Permalink
Use download counts for ranking + fake download counts in tests. (#8340)
Browse files Browse the repository at this point in the history
  • Loading branch information
isoos committed Nov 29, 2024
1 parent 1cab970 commit 806b8de
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 29 deletions.
20 changes: 20 additions & 0 deletions app/lib/fake/backend/fake_popularity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

import 'dart:math' as math;

import 'package:clock/clock.dart';

import '../../package/models.dart';
import '../../service/download_counts/backend.dart';
import '../../shared/datastore.dart';
import '../../shared/popularity_storage.dart';

Expand All @@ -23,3 +26,20 @@ Future<void> generateFakePopularityValues() async {
// ignore: invalid_use_of_visible_for_testing_member
popularityStorage.updateValues(values, invalid: false);
}

/// Scans the datastore for packages and generates download count values with a
/// deterministic random seed.
Future<void> generateFakeDownloadCounts() async {
final query = dbService.query<Package>();
await for (final p in query.run()) {
final r = math.Random(p.name.hashCode.abs());
final count = (math.min(p.likes * p.likes, 50) + r.nextInt(50));
await downloadCountsBackend.updateDownloadCounts(
p.name!,
{
p.latestVersion!: count,
},
clock.now(),
);
}
}
1 change: 1 addition & 0 deletions app/lib/fake/server/fake_analyzer_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class FakeAnalyzerService {
storage: _storage,
cloudCompute: _cloudCompute,
fn: () async {
await generateFakeDownloadCounts();
await generateFakePopularityValues();

final handler = wrapHandler(_logger, analyzerServiceHandler);
Expand Down
1 change: 1 addition & 0 deletions app/lib/fake/server/fake_default_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class FakePubServer {
await watchForResourceChanges();
}

await generateFakeDownloadCounts();
await generateFakePopularityValues();
await generateFakeTopicValues();
await nameTracker.startTracking();
Expand Down
1 change: 1 addition & 0 deletions app/lib/fake/server/fake_search_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class FakeSearchService {
});
_logger.info('running on port $port');

await generateFakeDownloadCounts();
await generateFakePopularityValues();
// ignore: invalid_use_of_visible_for_testing_member
await indexUpdater.updateAllPackages();
Expand Down
10 changes: 3 additions & 7 deletions app/lib/search/backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,7 @@ class SearchBackend {
if (!claim.valid) {
return;
}
snapshot.updateLikeScores();
snapshot.updatePopularityScores();
snapshot.updateAllScores();

// first complete snapshot, uploading it
await _snapshotStorage.uploadDataAsJsonMap(snapshot.toJson());
Expand Down Expand Up @@ -205,11 +204,8 @@ class SearchBackend {
futures.clear();

if (claim.valid && lastUploadedSnapshotTimestamp != snapshot.updated) {
// Updates the normalized like score across all the packages.
snapshot.updateLikeScores();
// Updates all popularity values to the currently cached one, otherwise
// only updated package would have been on their new values.
snapshot.updatePopularityScores();
// Updates the normalized scores across all the packages.
snapshot.updateAllScores();

await _snapshotStorage.uploadDataAsJsonMap(snapshot.toJson());
lastUploadedSnapshotTimestamp = snapshot.updated!;
Expand Down
11 changes: 8 additions & 3 deletions app/lib/search/mem_index.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,14 @@ class InMemoryPackageIndex {
);
_apiSymbolIndex = TokenIndex(apiDocPageKeys, apiDocPageValues);

// update download scores only if they were not set (should happen on old runtime's snapshot and local tests)
if (_documents.any((e) => e.downloadScore == null)) {
_documents.updateDownloadScores();
}

// update like scores only if they were not set (should happen only in local tests)
if (_documentsByName.values.any((e) => e.likeScore == null)) {
_documentsByName.values.updateLikeScores();
if (_documents.any((e) => e.likeScore == null)) {
_documents.updateLikeScores();
}
_updateOverallScores();
_lastUpdated = clock.now().toUtc();
Expand Down Expand Up @@ -263,7 +268,7 @@ class InMemoryPackageIndex {
/// Update the overall score both on [PackageDocument] and in the [_adjustedOverallScores] map.
void _updateOverallScores() {
_adjustedOverallScores = _documents.map((doc) {
final downloadScore = doc.popularityScore ?? 0.0;
final downloadScore = doc.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);
Expand Down
36 changes: 28 additions & 8 deletions app/lib/search/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,22 @@ class SearchSnapshot {
documents!.remove(packageName);
}

/// Updates the PackageDocument.likeScore for each package in the snapshot.
/// The score is normalized into the range of [0.0 - 1.0] using the
/// ordered list of packages by like counts (same like count gets the same score).
void updateLikeScores() {
/// Updates the [PackageDocument] instance's scores for each package in the snapshot.
/// Sets `downloadScore`, `likeScore` and `popularityScore` fields, normalized into the
/// range of [0.0 - 1.0] using the ordered list of their specific counts.
void updateAllScores() {
/// Updates the PackageDocument.downloadScore for each package in the snapshot.
/// The score is normalized into the range of [0.0 - 1.0] using the
/// ordered list of packages by download counts (same download count gets the same score).
documents!.values.updateDownloadScores();

/// Updates the PackageDocument.likeScore for each package in the snapshot.
/// The score is normalized into the range of [0.0 - 1.0] using the
/// ordered list of packages by like counts (same like count gets the same score).
documents!.values.updateLikeScores();
}

/// Updates all popularity values to the currently cached one, otherwise
/// only updated package would have been on their new values.
void updatePopularityScores() {
/// Updates all popularity values to the currently cached one, otherwise
/// only updated package would have been on their new values.
for (final d in documents!.values) {
if (popularityStorage.isInvalid) {
d.popularityScore = d.likeScore;
Expand All @@ -56,6 +62,20 @@ class SearchSnapshot {
}

extension UpdateLikesExt on Iterable<PackageDocument> {
/// Updates the PackageDocument.downloadScore for each package in the snapshot.
/// The score is normalized into the range of [0.0 - 1.0] using the
/// ordered list of packages by download counts (same download count gets the same score).
void updateDownloadScores() {
final list = sorted((a, b) => a.downloadCount.compareTo(b.downloadCount));
for (var i = 0; i < list.length; i++) {
if (i > 0 && list[i - 1].downloadCount == list[i].downloadCount) {
list[i].downloadScore = list[i - 1].downloadScore;
} else {
list[i].downloadScore = (i + 1) / list.length;
}
}
}

/// Updates the PackageDocument.likeScore for each package in the snapshot.
/// The score is normalized into the range of [0.0 - 1.0] using the
/// ordered list of packages by like counts (same like count gets the same score).
Expand Down
5 changes: 5 additions & 0 deletions app/lib/search/search_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ class PackageDocument {
final List<String> tags;

final int downloadCount;

/// The normalized score between [0.0-1.0] (1.0 being the most downloaded package).
double? downloadScore;

final int likeCount;

/// The normalized score between [0.0-1.0] (1.0 being the most liked package).
Expand Down Expand Up @@ -107,6 +111,7 @@ class PackageDocument {
this.readme = '',
List<String>? tags,
int? downloadCount,
this.downloadScore,
int? likeCount,
this.likeScore,
this.popularityScore,
Expand Down
2 changes: 2 additions & 0 deletions app/lib/search/search_service.g.dart

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

4 changes: 2 additions & 2 deletions app/test/frontend/handlers/listing_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ void main() {
(i) => TestPackage(
name: 'pkg$i', versions: [TestVersion(version: '1.0.0')])),
), fn: () async {
final present = ['pkg5', 'pkg7', 'pkg11', 'pkg13', 'pkg14'];
final absent = ['pkg0', 'pkg2', 'pkg3', 'pkg4', 'pkg6', 'pkg9', 'pkg10'];
final present = ['pkg1', 'pkg4', 'pkg5', 'pkg12'];
final absent = ['pkg0', 'pkg3', 'pkg6', 'pkg9', 'pkg10'];
await expectHtmlResponse(
await issueGet('/packages?page=2'),
present: present.map((name) => '/packages/$name').toList(),
Expand Down
21 changes: 14 additions & 7 deletions app/test/search/mem_index_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ void main() {
],
likeCount: 10,
popularityScore: 0.7,
downloadScore: 0.7,
grantedPoints: 110,
maxPoints: 110,
dependencies: {'async': 'direct', 'test': 'dev', 'foo': 'transitive'},
Expand Down Expand Up @@ -64,6 +65,7 @@ The delegating wrapper classes allow users to easily add functionality on top of
maxPoints: 110,
dependencies: {'test': 'dev'},
popularityScore: 0.8,
downloadScore: 0.8,
),
PackageDocument(
package: 'chrome_net',
Expand All @@ -78,6 +80,7 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
dependencies: {'foo': 'direct'},
grantedPoints: 0,
maxPoints: 110,
downloadScore: 0.0,
),
];
lastPackageUpdated =
Expand Down Expand Up @@ -597,13 +600,17 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
maxPoints: 100,
grantedPoints: 0,
tags: ['sdk:dart', 'sdk:flutter'],
likeCount: 4,
downloadCount: 4,
),
PackageDocument(
package: 'def',
description: 'abc xyz',
maxPoints: 100,
grantedPoints: 100,
tags: ['sdk:dart'],
likeCount: 3,
downloadCount: 3,
),
]);

Expand All @@ -615,8 +622,8 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'totalCount': 2,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'def', 'score': closeTo(0.77, 0.01)},
{'package': 'abc', 'score': closeTo(0.47, 0.01)},
{'package': 'def', 'score': closeTo(0.85, 0.01)},
{'package': 'abc', 'score': closeTo(0.70, 0.01)},
]
},
);
Expand All @@ -629,8 +636,8 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'sdkLibraryHits': [],
'packageHits': [
// `abc` is at its natural place
{'package': 'def', 'score': closeTo(0.77, 0.01)},
{'package': 'abc', 'score': closeTo(0.48, 0.01)},
{'package': 'def', 'score': closeTo(0.85, 0.01)},
{'package': 'abc', 'score': closeTo(0.70, 0.01)},
]
});
// exact name match with tags
Expand All @@ -644,8 +651,8 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'sdkLibraryHits': [],
'packageHits': [
// `abc` is at its natural place
{'package': 'def', 'score': closeTo(0.77, 0.01)},
{'package': 'abc', 'score': closeTo(0.48, 0.01)},
{'package': 'def', 'score': closeTo(0.85, 0.01)},
{'package': 'abc', 'score': closeTo(0.70, 0.01)},
]
});
// absent exact name match with tags
Expand All @@ -659,7 +666,7 @@ server.dart adds a small, prescriptive server (PicoServer) that can be configure
'sdkLibraryHits': [],
'packageHits': [
// `abc` is not present in the package list
{'package': 'def', 'score': closeTo(0.77, 0.01)},
{'package': 'def', 'score': closeTo(0.85, 0.01)},
]
});
});
Expand Down
4 changes: 2 additions & 2 deletions app/test/search/result_combiner_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void main() {
'totalCount': 1,
'sdkLibraryHits': [],
'packageHits': [
{'package': 'stringutils', 'score': closeTo(0.85, 0.01)},
{'package': 'stringutils', 'score': closeTo(1.0, 0.01)},
],
});
});
Expand All @@ -124,7 +124,7 @@ void main() {
},
],
'packageHits': [
{'package': 'stringutils', 'score': closeTo(0.67, 0.01)}
{'package': 'stringutils', 'score': closeTo(0.73, 0.01)}
],
});
});
Expand Down
2 changes: 2 additions & 0 deletions app/test/shared/test_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class FakeAppengineEnv {
);
}
if (processJobsWithFakeRunners) {
await generateFakeDownloadCounts();
await processTasksWithFakePanaAndDartdoc();
}
await nameTracker.reloadFromDatastore();
Expand Down Expand Up @@ -192,6 +193,7 @@ void testWithFakeTime(
source: importSource ?? ImportSource.autoGenerated(),
);
await nameTracker.reloadFromDatastore();
await generateFakeDownloadCounts();
await generateFakePopularityValues();
await indexUpdater.updateAllPackages();
await asyncQueue.ongoingProcessing;
Expand Down

0 comments on commit 806b8de

Please sign in to comment.