feat(trending): switch trending endpoints to Ranking V2 ranking_score\n\n- discoverTrending() now sorts by ranking_score:desc + engagement_velocity:desc\n- HomepageService::getTrending() now sorts by ranking_score:desc + velocity\n- DB fallback joins artwork_stats for ranking_score sort\n- Both trending endpoints filter to last 30 days (spec §6)\n- Add created_at to Meilisearch filterableAttributes for date filtering\n- Synced index settings"
This commit is contained in:
@@ -249,17 +249,21 @@ final class ArtworkSearchService
|
||||
// ── Discover section helpers ───────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Trending: sorted by pre-computed trending_score_24h (recalculated every 30 min).
|
||||
* Falls back to views:desc if the column is not yet populated.
|
||||
* Trending: sorted by Ranking Engine V2 `ranking_score` (recalculated every 30 min).
|
||||
*
|
||||
* Spec §6: Uses ranking_score, limits to last 30 days,
|
||||
* highlights high-velocity artworks via engagement_velocity tiebreaker.
|
||||
*/
|
||||
public function discoverTrending(int $perPage = 24): LengthAwarePaginator
|
||||
{
|
||||
$page = (int) request()->get('page', 1);
|
||||
return Cache::remember("discover.trending.{$page}", self::CACHE_TTL, function () use ($perPage) {
|
||||
$page = (int) request()->get('page', 1);
|
||||
$cutoff = now()->subDays(30)->toDateString();
|
||||
|
||||
return Cache::remember("discover.trending.{$page}", self::CACHE_TTL, function () use ($perPage, $cutoff) {
|
||||
return Artwork::search('')
|
||||
->options([
|
||||
'filter' => self::BASE_FILTER,
|
||||
'sort' => ['trending_score_24h:desc', 'trending_score_7d:desc', 'views:desc', 'created_at:desc'],
|
||||
'filter' => self::BASE_FILTER . ' AND created_at >= "' . $cutoff . '"',
|
||||
'sort' => ['ranking_score:desc', 'engagement_velocity:desc', 'views:desc'],
|
||||
])
|
||||
->paginate($perPage);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user