Increase people recommendation diversityUnverified
59d6bbb parent: be4aec4 modified
internal/cluster/scoring.go +22 -3 | @@ -68,13 +68,32 @@ func (e *Engine) GetFeedRecommendations(ctx context.Context, userDID string, lim | ||
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | // GetPeopleRecommendations returns similar users based on subscription overlap, |
| 71 | -// like co-occurrence, tag overlap, and follow relationships. Scores are min-max | |
| 72 | -// normalized on the Jaccard field. | |
| 71 | +// like co-occurrence, tag overlap, and follow relationships. Up to half the | |
| 72 | +// limit come from the user's network (followed) and half from outside. When | |
| 73 | +// outside-network candidates are scarce, in-network fills the remaining slots. | |
| 73 | 74 | func (e *Engine) GetPeopleRecommendations(ctx context.Context, userDID string, limit int) ([]*PersonRecommendation, error) { |
| 74 | - recs, err := e.ComputePeopleRecommendationsOnDemand(ctx, userDID, limit) | |
| 75 | + recs, err := e.ComputePeopleRecommendationsOnDemand(ctx, userDID, limit*2) | |
| 75 | 76 | if err != nil { |
| 76 | 77 | return nil, err |
| 77 | 78 | } |
| 79 | + | |
| 80 | + half := max(limit/2, 1) | |
| 81 | + | |
| 82 | + var inNet, outNet []*PersonRecommendation | |
| 83 | + for _, r := range recs { | |
| 84 | + if r.IsFollowed { | |
| 85 | + inNet = append(inNet, r) | |
| 86 | + } else { | |
| 87 | + outNet = append(outNet, r) | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + outTake := min(half, len(outNet)) | |
| 92 | + inTake := min(limit-outTake, len(inNet)) | |
| 93 | + recs = recs[:0] | |
| 94 | + recs = append(recs, inNet[:inTake]...) | |
| 95 | + recs = append(recs, outNet[:outTake]...) | |
| 96 | + | |
| 78 | 97 | normalizePersonScores(recs) |
| 79 | 98 | return recs, nil |
| 80 | 99 | } |
| @@ -68,13 +68,32 @@ func (e *Engine) GetFeedRecommendations(ctx context.Context, userDID string, lim | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | // GetPeopleRecommendations returns similar users based on subscription overlap, | 70 | // GetPeopleRecommendations returns similar users based on subscription overlap, |
| 71 | -// like co-occurrence, tag overlap, and follow relationships. Scores are min-max | 71 | +// like co-occurrence, tag overlap, and follow relationships. Up to half the |
| 72 | -// normalized on the Jaccard field. | 72 | +// limit come from the user's network (followed) and half from outside. When |
| 73 | +// outside-network candidates are scarce, in-network fills the remaining slots. | ||
| 73 | func (e *Engine) GetPeopleRecommendations(ctx context.Context, userDID string, limit int) ([]*PersonRecommendation, error) { | 74 | func (e *Engine) GetPeopleRecommendations(ctx context.Context, userDID string, limit int) ([]*PersonRecommendation, error) { |
| 74 | - recs, err := e.ComputePeopleRecommendationsOnDemand(ctx, userDID, limit) | 75 | + recs, err := e.ComputePeopleRecommendationsOnDemand(ctx, userDID, limit*2) |
| 75 | if err != nil { | 76 | if err != nil { |
| 76 | return nil, err | 77 | return nil, err |
| 77 | } | 78 | } |
| 79 | + | ||
| 80 | + half := max(limit/2, 1) | ||
| 81 | + | ||
| 82 | + var inNet, outNet []*PersonRecommendation | ||
| 83 | + for _, r := range recs { | ||
| 84 | + if r.IsFollowed { | ||
| 85 | + inNet = append(inNet, r) | ||
| 86 | + } else { | ||
| 87 | + outNet = append(outNet, r) | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + outTake := min(half, len(outNet)) | ||
| 92 | + inTake := min(limit-outTake, len(inNet)) | ||
| 93 | + recs = recs[:0] | ||
| 94 | + recs = append(recs, inNet[:inTake]...) | ||
| 95 | + recs = append(recs, outNet[:outTake]...) | ||
| 96 | + | ||
| 78 | normalizePersonScores(recs) | 97 | normalizePersonScores(recs) |
| 79 | return recs, nil | 98 | return recs, nil |
| 80 | } | 99 | } |