optimizations
This commit is contained in:
@@ -14,15 +14,14 @@ use Illuminate\Support\Facades\Log;
|
||||
* Calculates and persists deterministic trending scores for artworks.
|
||||
*
|
||||
* Formula (Phase 1):
|
||||
* score = (award_score * 5)
|
||||
* + (favorites_count * 3)
|
||||
* + (reactions_count * 2)
|
||||
* + (downloads_count * 1)
|
||||
* + (views * 2)
|
||||
* score = (favorites_velocity * wf)
|
||||
* + (comments_velocity * wc)
|
||||
* + (shares_velocity * ws)
|
||||
* + (downloads_velocity * wd)
|
||||
* + (views_velocity * wv)
|
||||
* - (hours_since_published * 0.1)
|
||||
*
|
||||
* The score is stored in artworks.trending_score_24h (artworks ≤ 7 days old)
|
||||
* and artworks.trending_score_7d (artworks ≤ 30 days old).
|
||||
* The score is stored in artworks.trending_score_1h / 24h / 7d.
|
||||
*
|
||||
* Both columns are updated every run; use `--period` to limit computation.
|
||||
*/
|
||||
@@ -39,14 +38,16 @@ final class TrendingService
|
||||
/**
|
||||
* Recalculate trending scores for artworks published within the look-back window.
|
||||
*
|
||||
* @param string $period '24h' targets trending_score_24h (7-day window)
|
||||
* '7d' targets trending_score_7d (30-day window)
|
||||
* @param string $period '1h' targets trending_score_1h (3-day window)
|
||||
* '24h' targets trending_score_24h (7-day window)
|
||||
* '7d' targets trending_score_7d (30-day window)
|
||||
* @param int $chunkSize Number of IDs per DB UPDATE batch
|
||||
* @return int Number of artworks updated
|
||||
*/
|
||||
public function recalculate(string $period = '7d', int $chunkSize = 1000): int
|
||||
{
|
||||
[$column, $windowDays] = match ($period) {
|
||||
'1h' => ['trending_score_1h', 3],
|
||||
'24h' => ['trending_score_24h', 7],
|
||||
default => ['trending_score_7d', 30],
|
||||
};
|
||||
@@ -54,10 +55,23 @@ final class TrendingService
|
||||
// Use the windowed counters: views_24h/views_7d and downloads_24h/downloads_7d
|
||||
// instead of all-time totals so trending reflects recent activity.
|
||||
[$viewCol, $dlCol] = match ($period) {
|
||||
'1h' => ['views_1h', 'downloads_1h'],
|
||||
'24h' => ['views_24h', 'downloads_24h'],
|
||||
default => ['views_7d', 'downloads_7d'],
|
||||
};
|
||||
|
||||
[$favCol, $commentCol, $shareCol] = match ($period) {
|
||||
'1h' => ['favourites_1h', 'comments_1h', 'shares_1h'],
|
||||
'24h' => ['favourites_24h', 'comments_24h', 'shares_24h'],
|
||||
default => ['favorites', 'comments_count', 'shares_count'],
|
||||
};
|
||||
|
||||
$weights = (array) config('discovery.v2.trending.velocity_weights', []);
|
||||
$wView = (float) ($weights['views'] ?? self::W_VIEW);
|
||||
$wFavorite = (float) ($weights['favorites'] ?? self::W_FAVORITE);
|
||||
$wComment = (float) ($weights['comments'] ?? self::W_REACTION);
|
||||
$wShare = (float) ($weights['shares'] ?? self::W_DOWNLOAD);
|
||||
|
||||
$cutoff = now()->subDays($windowDays)->toDateTimeString();
|
||||
$updated = 0;
|
||||
|
||||
@@ -69,7 +83,7 @@ final class TrendingService
|
||||
->whereNotNull('published_at')
|
||||
->where('published_at', '>=', $cutoff)
|
||||
->orderBy('id')
|
||||
->chunkById($chunkSize, function ($artworks) use ($column, $viewCol, $dlCol, &$updated): void {
|
||||
->chunkById($chunkSize, function ($artworks) use ($column, $viewCol, $dlCol, $favCol, $commentCol, $shareCol, $wFavorite, $wComment, $wShare, $wView, &$updated): void {
|
||||
$ids = $artworks->pluck('id')->toArray();
|
||||
$inClause = implode(',', array_fill(0, count($ids), '?'));
|
||||
|
||||
@@ -81,17 +95,17 @@ final class TrendingService
|
||||
"UPDATE artworks
|
||||
SET
|
||||
{$column} = GREATEST(
|
||||
COALESCE((SELECT score_total FROM artwork_award_stats WHERE artwork_award_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT favorites FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT COUNT(*) FROM artwork_reactions WHERE artwork_reactions.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT {$dlCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT {$viewCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
COALESCE((SELECT {$favCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT {$commentCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT {$shareCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT {$dlCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
+ COALESCE((SELECT {$viewCol} FROM artwork_stats WHERE artwork_stats.artwork_id = artworks.id), 0) * ?
|
||||
- (TIMESTAMPDIFF(HOUR, artworks.published_at, NOW()) * ?)
|
||||
, 0),
|
||||
last_trending_calculated_at = NOW()
|
||||
WHERE id IN ({$inClause})",
|
||||
array_merge(
|
||||
[self::W_AWARD, self::W_FAVORITE, self::W_REACTION, self::W_DOWNLOAD, self::W_VIEW, self::DECAY_RATE],
|
||||
[$wFavorite, $wComment, $wShare, self::W_DOWNLOAD, $wView, self::DECAY_RATE],
|
||||
$ids
|
||||
)
|
||||
);
|
||||
@@ -114,7 +128,11 @@ final class TrendingService
|
||||
*/
|
||||
public function syncToSearchIndex(string $period = '7d', int $chunkSize = 500): void
|
||||
{
|
||||
$windowDays = $period === '24h' ? 7 : 30;
|
||||
$windowDays = match ($period) {
|
||||
'1h' => 3,
|
||||
'24h' => 7,
|
||||
default => 30,
|
||||
};
|
||||
$cutoff = now()->subDays($windowDays)->toDateTimeString();
|
||||
|
||||
Artwork::query()
|
||||
|
||||
Reference in New Issue
Block a user