From 98501ca84f784e305a6a6e6772df5a356869bb91 Mon Sep 17 00:00:00 2001 From: Istvan Soos Date: Wed, 23 Oct 2024 13:21:53 +0200 Subject: [PATCH] Use donwload counts in search index and sort control. --- app/lib/fake/backend/fake_popularity.dart | 2 ++ app/lib/frontend/templates/_consts.dart | 6 ++++++ app/lib/search/backend.dart | 2 ++ app/lib/search/mem_index.dart | 12 ++++++++++++ app/lib/search/search_service.dart | 3 +++ app/lib/search/search_service.g.dart | 2 ++ pkg/_pub_shared/lib/search/search_form.dart | 3 +++ 7 files changed, 30 insertions(+) diff --git a/app/lib/fake/backend/fake_popularity.dart b/app/lib/fake/backend/fake_popularity.dart index 145d5737f5..cf2a55fb18 100644 --- a/app/lib/fake/backend/fake_popularity.dart +++ b/app/lib/fake/backend/fake_popularity.dart @@ -10,6 +10,8 @@ import '../../shared/popularity_storage.dart'; /// Scans the datastore for packages and generates popularity values with a /// deterministic random seed. +/// +/// TODO: generate similar values for download counts. Future generateFakePopularityValues() async { final values = {}; final query = dbService.query(); diff --git a/app/lib/frontend/templates/_consts.dart b/app/lib/frontend/templates/_consts.dart index 6b1e16dca6..d97736c58d 100644 --- a/app/lib/frontend/templates/_consts.dart +++ b/app/lib/frontend/templates/_consts.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:_pub_shared/search/tags.dart'; +import 'package:pub_dev/frontend/request_context.dart'; import '../dom/dom.dart' as d; @@ -124,5 +125,10 @@ List getSortDicts(bool isSearch) { final removeId = isSearch ? 'listing_relevance' : 'search_relevance'; return [ ..._sortDicts.where((d) => d.id != removeId), + if (requestContext.experimentalFlags.showDownloadCounts) + SortDict( + id: 'downloads', + label: 'downloads', + tooltip: 'Packages are sorted by their download counts.'), ]; } diff --git a/app/lib/search/backend.dart b/app/lib/search/backend.dart index 3c9b3d96b0..f7fd181e25 100644 --- a/app/lib/search/backend.dart +++ b/app/lib/search/backend.dart @@ -22,6 +22,7 @@ import 'package:pool/pool.dart'; import 'package:pub_dev/publisher/backend.dart'; import 'package:pub_dev/search/search_client.dart'; +import 'package:pub_dev/service/download_counts/backend.dart'; import 'package:pub_dev/shared/popularity_storage.dart'; import 'package:pub_dev/shared/redis_cache.dart'; import 'package:pub_dev/shared/utils.dart'; @@ -356,6 +357,7 @@ class SearchBackend { created: p.created!, updated: p.lastVersionPublished!, readme: compactReadme(readmeAsset?.textContent), + downloadCount: downloadCountsBackend.lookup30DaysTotalCounts(pv.package), likeCount: p.likes, popularityScore: popularityStorage.lookup(packageName), grantedPoints: scoreCard.grantedPubPoints, diff --git a/app/lib/search/mem_index.dart b/app/lib/search/mem_index.dart index 495925f796..a94cdec057 100644 --- a/app/lib/search/mem_index.dart +++ b/app/lib/search/mem_index.dart @@ -33,6 +33,7 @@ class InMemoryPackageIndex { late final List _createdOrderedHits; late final List _updatedOrderedHits; late final List _popularityOrderedHits; + late final List _downloadsOrderedHits; late final List _likesOrderedHits; late final List _pointsOrderedHits; @@ -81,6 +82,8 @@ class InMemoryPackageIndex { _updatedOrderedHits = _rankWithComparator(_compareUpdated); _popularityOrderedHits = _rankWithComparator(_comparePopularity, score: (doc) => doc.popularityScore ?? 0); + _downloadsOrderedHits = _rankWithComparator(_compareDownloads, + score: (doc) => doc.downloadCount.toDouble()); _likesOrderedHits = _rankWithComparator(_compareLikes, score: (doc) => doc.likeCount.toDouble()); _pointsOrderedHits = _rankWithComparator(_comparePoints, @@ -195,6 +198,9 @@ class InMemoryPackageIndex { case SearchOrder.popularity: packageHits = _popularityOrderedHits.whereInSet(packages); break; + case SearchOrder.downloads: + packageHits = _downloadsOrderedHits.whereInSet(packages); + break; case SearchOrder.like: packageHits = _likesOrderedHits.whereInSet(packages); break; @@ -414,6 +420,12 @@ class InMemoryPackageIndex { return _compareUpdated(a, b); } + int _compareDownloads(PackageDocument a, PackageDocument b) { + final x = -a.downloadCount.compareTo(b.downloadCount); + if (x != 0) return x; + return _compareUpdated(a, b); + } + int _compareLikes(PackageDocument a, PackageDocument b) { final x = -a.likeCount.compareTo(b.likeCount); if (x != 0) return x; diff --git a/app/lib/search/search_service.dart b/app/lib/search/search_service.dart index d2e471cb51..584c725d14 100644 --- a/app/lib/search/search_service.dart +++ b/app/lib/search/search_service.dart @@ -73,6 +73,7 @@ class PackageDocument { final List tags; + final int downloadCount; final int likeCount; /// The normalized score between [0.0-1.0] (1.0 being the most liked package). @@ -105,6 +106,7 @@ class PackageDocument { DateTime? updated, this.readme = '', List? tags, + int? downloadCount, int? likeCount, this.likeScore, this.popularityScore, @@ -116,6 +118,7 @@ class PackageDocument { this.sourceUpdated, }) : created = created ?? clock.now(), updated = updated ?? clock.now(), + downloadCount = downloadCount ?? 0, likeCount = likeCount ?? 0, grantedPoints = grantedPoints ?? 0, maxPoints = maxPoints ?? 0, diff --git a/app/lib/search/search_service.g.dart b/app/lib/search/search_service.g.dart index 3281e789f3..8925d4efa2 100644 --- a/app/lib/search/search_service.g.dart +++ b/app/lib/search/search_service.g.dart @@ -19,6 +19,7 @@ PackageDocument _$PackageDocumentFromJson(Map json) => : DateTime.parse(json['updated'] as String), readme: json['readme'] as String? ?? '', tags: (json['tags'] as List?)?.map((e) => e as String).toList(), + downloadCount: (json['downloadCount'] as num?)?.toInt(), likeCount: (json['likeCount'] as num?)?.toInt(), likeScore: (json['likeScore'] as num?)?.toDouble(), popularityScore: (json['popularityScore'] as num?)?.toDouble(), @@ -49,6 +50,7 @@ Map _$PackageDocumentToJson(PackageDocument instance) => 'updated': instance.updated.toIso8601String(), 'readme': instance.readme, 'tags': instance.tags, + 'downloadCount': instance.downloadCount, 'likeCount': instance.likeCount, 'likeScore': instance.likeScore, 'popularityScore': instance.popularityScore, diff --git a/pkg/_pub_shared/lib/search/search_form.dart b/pkg/_pub_shared/lib/search/search_form.dart index 4de5148def..a773152e35 100644 --- a/pkg/_pub_shared/lib/search/search_form.dart +++ b/pkg/_pub_shared/lib/search/search_form.dart @@ -52,6 +52,9 @@ enum SearchOrder { /// Search order should be in decreasing popularity score. popularity, + /// Search order should be in decreasing download counts. + downloads, + /// Search order should be in decreasing like count. like,