fix: limit recommendation scoring
This commit is contained in:
@@ -6,6 +6,7 @@ const (
|
|||||||
maxSeeds = 8
|
maxSeeds = 8
|
||||||
maxRecommendations = 10
|
maxRecommendations = 10
|
||||||
candidateFetchLimit = 60
|
candidateFetchLimit = 60
|
||||||
|
candidateFetchBuffer = 6
|
||||||
TopPickLimit = 18
|
TopPickLimit = 18
|
||||||
TopPicksLimit = 60
|
TopPicksLimit = 60
|
||||||
profileSearchLimit = 8
|
profileSearchLimit = 8
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (e engine) getTopPicksForYou(ctx context.Context, userID string, resultLimi
|
|||||||
return domain.CatalogSectionData{Animes: []domain.Anime{}}, nil
|
return domain.CatalogSectionData{Animes: []domain.Anime{}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
candidates, err := e.scoreRankedCandidates(ctx, now, profile, ranked)
|
candidates, err := e.scoreRankedCandidates(ctx, now, profile, ranked, resultLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.CatalogSectionData{}, err
|
return domain.CatalogSectionData{}, err
|
||||||
}
|
}
|
||||||
@@ -191,8 +191,9 @@ func (e engine) scoreRankedCandidates(
|
|||||||
now time.Time,
|
now time.Time,
|
||||||
profile userTasteProfile,
|
profile userTasteProfile,
|
||||||
ranked []rankedCandidate,
|
ranked []rankedCandidate,
|
||||||
|
resultLimit int,
|
||||||
) ([]recommendationCandidate, error) {
|
) ([]recommendationCandidate, error) {
|
||||||
limit := min(len(ranked), candidateFetchLimit)
|
limit := min(len(ranked), candidateScoreLimit(resultLimit))
|
||||||
candidates := make([]recommendationCandidate, 0, limit)
|
candidates := make([]recommendationCandidate, 0, limit)
|
||||||
var candidatesMu sync.Mutex
|
var candidatesMu sync.Mutex
|
||||||
var g errgroup.Group
|
var g errgroup.Group
|
||||||
@@ -244,3 +245,11 @@ func (e engine) scoreRankedCandidates(
|
|||||||
|
|
||||||
return candidates, nil
|
return candidates, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func candidateScoreLimit(resultLimit int) int {
|
||||||
|
if resultLimit <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return min(candidateFetchLimit, resultLimit+candidateFetchBuffer)
|
||||||
|
}
|
||||||
|
|||||||
@@ -174,6 +174,18 @@ func TestRerankRecommendationCandidatesSpreadsRepeatedGenres(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCandidateScoreLimitTracksRequestedResultSize(t *testing.T) {
|
||||||
|
if got := candidateScoreLimit(TopPickLimit); got != TopPickLimit+candidateFetchBuffer {
|
||||||
|
t.Fatalf("expected top-pick scoring to fetch a small oversample, got %d", got)
|
||||||
|
}
|
||||||
|
if got := candidateScoreLimit(TopPicksLimit); got != candidateFetchLimit {
|
||||||
|
t.Fatalf("expected full top-picks scoring to keep existing cap, got %d", got)
|
||||||
|
}
|
||||||
|
if got := candidateScoreLimit(0); got != 0 {
|
||||||
|
t.Fatalf("expected zero result limit to skip scoring, got %d", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testRecommendationAnime(id int, genreID int) jikan.Anime {
|
func testRecommendationAnime(id int, genreID int) jikan.Anime {
|
||||||
return jikan.Anime{
|
return jikan.Anime{
|
||||||
MalID: id,
|
MalID: id,
|
||||||
|
|||||||
Reference in New Issue
Block a user