Interest ranking

Interest weights help customize the ranking to users' interests. If you want to create a ranking expression that relies on interest weights, use interest type ranking.

feeds.createFeedGroup(CreateFeedGroupRequest.builder()
    .id("myid")
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("following").build()))
    .ranking(RankingConfig.builder()
        .type("interest")
        .score("interest_score * popularity")
        .build())
    .build()).execute();

interest_score is computed by combining activity topics and the specific user's interests. Each of the activity's interest_tags that matches one of the user's interests adds half of that interest's weight, and the total is clamped to between -1 and 1. A single matching tag with weight 1.0 gives 0.5, and tags with a weight of 0 or below pull the score down. The score is 0 when the activity has no interest_tags or none of them match. interest_score is only computed with interest type ranking; with expression ranking it is always 0.

Activity topics

The topic of an activity can be computed automatically using activity processors or by setting the interest_tags field via the Stream API.

User interests

A user's interests are computed automatically by the Stream API from the interest_tags on activities the user has reacted to, directly or through a comment. Recent reactions count more: each reaction's contribution halves every 30 days. The user's strongest computed tag has weight 1.0, and the other computed tags get a proportional weight between 0 and 1. When ranking with interest type, the top five tags with a positive weight are used, plus every tag with a weight of 0 or below as a penalty. You can also seed and manage a user's interests yourself, see the User interests guide.

You can also pass interest_weights when reading the feed. These weights are merged with the user's stored interests (computed and manual) rather than replacing them:

  • Tags that appear only in the stored interests or only in interest_weights both contribute to interest_score.
  • If the same tag appears in both, the value from interest_weights is used (an explicit override for that tag).
  • If you omit interest_weights or pass an empty map, ranking uses only the user's stored interests.
  • Set overwrite_interest_weights: true to replace the stored interests with interest_weights for that request instead of merging. The flag has no effect when interest_weights is empty.
Feed timeline = new Feed("timeline", "john", feeds);

timeline.getOrCreate(GetOrCreateFeedRequest.builder()
    .userID("john")
    .interestWeights(Map.of("travel", 1.0, "food", 0.5, "exercise", -1.0))
    .build());

Use interest weights between -1 and 1, where 1 means a user is very interested in a topic and -1 means they dislike it. Values outside this range are not rejected, but interest_score is still clamped to between -1 and 1.

Preference score

preference_score reflects how much an activity matches the user's preferences based on activity feedback (show more/less). For each of the activity's interest_tags, it counts the user's show-more votes minus show-less votes on that tag, divides the total by 3 and clamps it to between -1 and 1. It is 0 when the activity has no interest_tags or the user has given no feedback on them.

In the foryou feed group, activities whose interest_tags have collected strong negative feedback are also removed from the feed: at least 3 show-less votes on the activity's tags with more show-less than show-more votes, or a net of 3 or more show-less votes. Other feed groups don't remove activities based on show more/less feedback, but can still use preference_score.

You can use preference_score in your ranking expressions with both expression and interest type ranking to boost activities that match user preferences:

// Using preference_score with expression type
feeds.createFeedGroup(CreateFeedGroupRequest.builder()
    .id("myid")
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("following").build()))
    .ranking(RankingConfig.builder()
        .type("expression")
        .score("preference_score * popularity")
        .build())
    .build()).execute();

// Using preference_score with interest type
feeds.createFeedGroup(CreateFeedGroupRequest.builder()
    .id("myid_interest")
    .activitySelectors(List.of(
        ActivitySelectorConfig.builder().type("following").build()))
    .ranking(RankingConfig.builder()
        .type("interest")
        .score("preference_score * interest_score * popularity")
        .build())
    .build()).execute();

See Activity feedback for more information on how users can provide feedback that affects preference_score.