optimizations

This commit is contained in:
2026-03-28 19:15:39 +01:00
parent 0b25d9570a
commit cab4fbd83e
509 changed files with 1016804 additions and 1605 deletions

View File

@@ -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()