Skip to content

Commit d8c91e2

Browse files
authored
GENAI-2415 Add support for new inferred experiment. Adjust topic restrictions for personalization (#1172)
* Add support for new experiment. Adjust clamping for personalization * fix name
1 parent c87e485 commit d8c91e2

File tree

5 files changed

+39
-2
lines changed

5 files changed

+39
-2
lines changed

merino/curated_recommendations/ml_backends/static_local_model.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from merino.curated_recommendations.protocol import ExperimentName
1313

1414
INFERRED_LOCAL_EXPERIMENT_NAME = ExperimentName.INFERRED_LOCAL_EXPERIMENT.value
15+
INFERRED_LOCAL_EXPERIMENT_NAME_V2 = ExperimentName.INFERRED_LOCAL_EXPERIMENT_V2.value
1516
LOCAL_AND_SERVER_V1 = "local-and-server"
1617
LOCAL_ONLY_V1 = "local-only"
1718
LOCAL_ONLY_BRANCH_NAME = LOCAL_ONLY_V1
@@ -292,6 +293,8 @@ def get(
292293
if (
293294
experiment_name == INFERRED_LOCAL_EXPERIMENT_NAME
294295
or experiment_name == f"optin-{INFERRED_LOCAL_EXPERIMENT_NAME}"
296+
or experiment_name == INFERRED_LOCAL_EXPERIMENT_NAME_V2
297+
or experiment_name == f"optin-{INFERRED_LOCAL_EXPERIMENT_NAME_V2}"
295298
):
296299
## switch on branch name
297300
if experiment_branch == LOCAL_AND_SERVER_BRANCH_NAME:

merino/curated_recommendations/protocol.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ class ExperimentName(str, Enum):
103103
NEW_TAB_CUSTOM_SECTIONS_EXPERIMENT = "new-tab-custom-sections"
104104
# Experiment for doing local reranking of popular today via inferred interests
105105
INFERRED_LOCAL_EXPERIMENT = "new-tab-automated-personalization-local-ranking"
106+
INFERRED_LOCAL_EXPERIMENT_V2 = "new-tab-automated-personalization-local-ranking-2"
106107

107108

108109
@unique

merino/curated_recommendations/sections.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ def get_top_story_list(
561561
extra_count: int = 0,
562562
extra_source_depth: int = 10,
563563
rescaler: ExperimentRescaler | None = None,
564+
relax_constraints_for_personalization=False,
564565
) -> list[CuratedRecommendation]:
565566
"""Build a top story list of top_count items from a full list. Adds some extra items from further down
566567
in the list of recs with some care to not use the same topic more than once.
@@ -576,6 +577,8 @@ def get_top_story_list(
576577
rescaler: Optional rescaler associated with the experiment or surface
577578
Returns: A list of top stories
578579
"""
580+
constraint_scale = 2.0 if relax_constraints_for_personalization else 1.0
581+
579582
fresh_story_prob = rescaler.fresh_items_top_stories_max_percentage if rescaler else 0
580583
total_story_count = top_count + extra_count
581584

@@ -588,7 +591,7 @@ def get_top_story_list(
588591
)
589592
non_throttled = items[len(items_throttled_fresh) + len(unused_fresh) :]
590593

591-
balancer: ArticleBalancer = ArticleBalancer(top_count)
594+
balancer: ArticleBalancer = ArticleBalancer(round(top_count * constraint_scale))
592595
topic_limited_stories, remaining_stories = balancer.add_stories(
593596
items_throttled_fresh, top_count
594597
)
@@ -597,7 +600,7 @@ def get_top_story_list(
597600
if len(second_pass_candidates) > extra_source_depth * 2:
598601
second_pass_candidates = second_pass_candidates[extra_source_depth:]
599602

600-
balancer.set_limits_for_expected_articles(total_story_count)
603+
balancer.set_limits_for_expected_articles(round(total_story_count * constraint_scale))
601604
topic_limited_stories, remaining_stories = balancer.add_stories(
602605
second_pass_candidates, total_story_count
603606
)
@@ -711,6 +714,7 @@ async def get_sections(
711714
top_stories_count,
712715
TOP_STORIES_SECTION_EXTRA_COUNT,
713716
rescaler=rescaler,
717+
relax_constraints_for_personalization=personal_interests is not None,
714718
)
715719

716720
# Get the story ids in top_stories section

tests/unit/curated_recommendations/ml_backends/test_static_local_model.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from merino.curated_recommendations.protocol import ExperimentName
3232

3333
INFERRED_LOCAL_EXPERIMENT_NAME = ExperimentName.INFERRED_LOCAL_EXPERIMENT.value
34+
INFERRED_LOCAL_EXPERIMENT_NAME_V2 = ExperimentName.INFERRED_LOCAL_EXPERIMENT_V2.value
3435

3536
TEST_SURFACE = "test_surface"
3637

@@ -516,7 +517,14 @@ def test_process_passthrough_when_values_missing_even_with_matching_model(
516517
"experiment,branch,model_id,expect_private_nonempty",
517518
[
518519
(INFERRED_LOCAL_EXPERIMENT_NAME, LOCAL_AND_SERVER_BRANCH_NAME, LOCAL_AND_SERVER_V1, True),
520+
(
521+
INFERRED_LOCAL_EXPERIMENT_NAME_V2,
522+
LOCAL_AND_SERVER_BRANCH_NAME,
523+
LOCAL_AND_SERVER_V1,
524+
True,
525+
),
519526
(INFERRED_LOCAL_EXPERIMENT_NAME, LOCAL_ONLY_BRANCH_NAME, LOCAL_ONLY_V1, False),
527+
(INFERRED_LOCAL_EXPERIMENT_NAME_V2, LOCAL_ONLY_BRANCH_NAME, LOCAL_ONLY_V1, False),
520528
(
521529
"optin-" + INFERRED_LOCAL_EXPERIMENT_NAME,
522530
LOCAL_AND_SERVER_BRANCH_NAME,
@@ -536,7 +544,9 @@ def test_process_passthrough_when_values_missing_even_with_matching_model(
536544
],
537545
ids=[
538546
"local_and_server_branch",
547+
"local_and_server_branch_v2",
539548
"local_only_branch",
549+
"local_only_branch_v2",
540550
"optin-local_and_server_branch",
541551
"optin-local_only_branch",
542552
"local_and_server_branch__no_model",

tests/unit/curated_recommendations/test_sections.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,25 @@ def test_basic_topic_limiting(self):
865865
for ix, item in enumerate(result):
866866
assert item.receivedRank == ix
867867

868+
def test_basic_topic_limiting_with_personalization(self):
869+
"""Extra items should be chosen without repeating topics from top_count items."""
870+
items = generate_recommendations(
871+
item_ids=["a", "b", "c", "d", "e", "f"],
872+
topics=["arts", "arts", "arts", "arts", "food", "government"],
873+
)
874+
result = get_top_story_list(
875+
items,
876+
top_count=6,
877+
extra_count=0,
878+
extra_source_depth=0,
879+
relax_constraints_for_personalization=True,
880+
)
881+
top_ids = [i.corpusItemId for i in result]
882+
assert len(result) == 6
883+
top_ids[2] == "c"
884+
for ix, item in enumerate(result):
885+
assert item.receivedRank == ix
886+
868887
def test_includes_extra_items_topic_limiting(self):
869888
"""Extra items should be chosen without repeating topics from top_count items."""
870889
items = generate_recommendations(

0 commit comments

Comments
 (0)