def test_mock_client_ids(test_ctx):
    with mock_install_mock_ensemble_data(test_ctx):

        EXPECTED_RESULTS = [
            ("*****@*****.**", 0.17),
            ("@contain-facebook", 0.25),
            ("@testpilot-containers", 0.72),
            ("*****@*****.**", 0.37),
            ("*****@*****.**", 0.32),
        ]

        factory = MockRecommenderFactory()
        test_ctx["recommender_factory"] = factory

        test_ctx["recommender_map"] = {
            "collaborative": factory.create("collaborative"),
            "similarity": factory.create("similarity"),
            "locale": factory.create("locale"),
        }
        r = EnsembleRecommender(test_ctx)

        # 'hij' should be excluded from the suggestions list
        # The other two addon GUIDs 'def' and 'jkl' will never be
        # recommended anyway and should have no impact on results
        client = {"client_id": "11111"}

        recommendation_list = r.recommend(client, 5)
        assert isinstance(recommendation_list, list)
        assert recommendation_list == EXPECTED_RESULTS
def test_preinstalled_guids(test_ctx):
    ctx = install_mock_ensemble_data(test_ctx)

    EXPECTED_RESULTS = [('ghi', 3430.0),
                        ('ijk', 3200.0),
                        ('lmn', 420.0),
                        ('klm', 409.99999999999994),
                        ('abc', 23.0)]

    factory = MockRecommenderFactory()
    ctx['recommender_factory'] = factory

    ctx['recommender_map'] = {'collaborative': factory.create('collaborative'),
                              'similarity': factory.create('similarity'),
                              'locale': factory.create('locale')}
    r = EnsembleRecommender(ctx.child())

    # 'hij' should be excluded from the suggestions list
    # The other two addon GUIDs 'def' and 'jkl' will never be
    # recommended anyway and should have no impact on results
    client = {'client_id': '12345',
              'installed_addons': ['def', 'hij', 'jkl']}

    recommendation_list = r.recommend(client, 5)
    print(recommendation_list)
    assert isinstance(recommendation_list, list)
    assert recommendation_list == EXPECTED_RESULTS
def test_recommendations(test_ctx):
    with MetricsMock() as mm:
        with mock_install_mock_ensemble_data(test_ctx):
            EXPECTED_RESULTS = [
                ("ghi", 3430.0),
                ("def", 3320.0),
                ("ijk", 3200.0),
                ("hij", 3100.0),
                ("lmn", 420.0),
            ]

            factory = MockRecommenderFactory()
            test_ctx["recommender_factory"] = factory

            test_ctx["recommender_map"] = {
                "collaborative": factory.create("collaborative"),
                "similarity": factory.create("similarity"),
                "locale": factory.create("locale"),
            }
            r = EnsembleRecommender(test_ctx)
            client = {"client_id": "12345"}  # Anything will work here

            recommendation_list = r.recommend(client, 5)
            assert isinstance(recommendation_list, list)
            assert recommendation_list == EXPECTED_RESULTS

            assert mm.has_record(TIMING, "taar.ensemble_recommend")
            assert mm.has_record(TIMING, "taar.collaborative_recommend")
            assert mm.has_record(TIMING, "taar.locale_recommend")
            assert mm.has_record(TIMING, "taar.similarity_recommend")
def test_preinstalled_guids(test_ctx):
    with mock_install_mock_ensemble_data(test_ctx):
        EXPECTED_RESULTS = [
            ("ghi", 3430.0),
            ("ijk", 3200.0),
            ("lmn", 420.0),
            ("klm", 409.99999999999994),
            ("abc", 23.0),
        ]

        factory = MockRecommenderFactory()
        test_ctx["recommender_factory"] = factory

        test_ctx["recommender_map"] = {
            "collaborative": factory.create("collaborative"),
            "similarity": factory.create("similarity"),
            "locale": factory.create("locale"),
        }
        r = EnsembleRecommender(test_ctx)

        # 'hij' should be excluded from the suggestions list
        # The other two addon GUIDs 'def' and 'jkl' will never be
        # recommended anyway and should have no impact on results
        client = {
            "client_id": "12345",
            "installed_addons": ["def", "hij", "jkl"]
        }

        recommendation_list = r.recommend(client, 5)
        print(recommendation_list)
        assert isinstance(recommendation_list, list)
        assert recommendation_list == EXPECTED_RESULTS
def test_recommendations(test_ctx):
    ctx = install_mock_ensemble_data(test_ctx)

    EXPECTED_RESULTS = [
        ("ghi", 3430.0),
        ("def", 3320.0),
        ("ijk", 3200.0),
        ("hij", 3100.0),
        ("lmn", 420.0),
    ]

    factory = MockRecommenderFactory()
    ctx["recommender_factory"] = factory

    ctx["recommender_map"] = {
        "collaborative": factory.create("collaborative"),
        "similarity": factory.create("similarity"),
        "locale": factory.create("locale"),
    }
    r = EnsembleRecommender(ctx.child())
    client = {"client_id": "12345"}  # Anything will work here

    recommendation_list = r.recommend(client, 5)
    assert isinstance(recommendation_list, list)
    assert recommendation_list == EXPECTED_RESULTS
Beispiel #6
0
class RecommendationManager:
    """This class determines which of the set of recommendation
    engines will actually be used to generate recommendations."""
    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx
        self.logger = self._ctx[IMozLogging].get_logger("taar")

        assert "profile_fetcher" in self._ctx

        self.profile_fetcher = ctx["profile_fetcher"]

        self._ensemble_recommender = EnsembleRecommender(self._ctx.child())

        # The whitelist data is only used for test client IDs

        self._whitelist_data = LazyJSONLoader(self._ctx, TAAR_WHITELIST_BUCKET,
                                              TAAR_WHITELIST_KEY)

        self._experiment_prob = ctx.get("TAAR_EXPERIMENT_PROB",
                                        TAAR_EXPERIMENT_PROB)

    def recommend(self, client_id, limit, extra_data={}):
        """Return recommendations for the given client.

        The recommendation logic will go through each recommender and
        pick the first one that "can_recommend".

        :param client_id: the client unique id.
        :param limit: the maximum number of recommendations to return.
        :param extra_data: a dictionary with extra client data.
        """

        results = None
        whitelist = self._whitelist_data.get()[0]

        client_info = self.profile_fetcher.get(client_id)
        if client_info is None:
            self.logger.info(
                "Defaulting to empty results.  No client info fetched from dynamo."
            )
            results = []

        if in_experiment(client_id, self._experiment_prob):
            if results is None:
                # Fetch back all possible whitelisted addons for this
                # client
                extra_data['guid_randomization'] = True
                results = self._ensemble_recommender.recommend(
                    client_info, len(whitelist), extra_data)
            results = reorder_guids(results, limit)
        else:
            if results is None:
                results = self._ensemble_recommender.recommend(
                    client_info, limit, extra_data)

        return results
def test_weight_cache(test_ctx):
    with mock_install_mock_ensemble_data(test_ctx):
        factory = MockRecommenderFactory()
        test_ctx["recommender_factory"] = factory

        test_ctx["recommender_map"] = {
            "collaborative": factory.create("collaborative"),
            "similarity": factory.create("similarity"),
            "locale": factory.create("locale"),
        }

        r = EnsembleRecommender(test_ctx)
        actual = r.getWeights()
        assert EXPECTED == actual
Beispiel #8
0
    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx
        self.logger = self._ctx[IMozLogging].get_logger("taar") if self._ctx[IMozLogging] else None

        assert "profile_fetcher" in self._ctx

        self.profile_fetcher = ctx["profile_fetcher"]

        self._ensemble_recommender = EnsembleRecommender(self._ctx.child())

        # The whitelist data is only used for test client IDs

        self._cache = self._ctx[ITAARCache]
    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx
        self.logger = self._ctx[IMozLogging].get_logger('taar')

        assert 'profile_fetcher' in self._ctx

        self.profile_fetcher = ctx['profile_fetcher']
        self._recommender_map = {}

        self.logger.info("Initializing recommenders")
        self._recommender_map[INTERVENTION_A] = EnsembleRecommender(
            self._ctx.child())

        hybrid_ctx = self._ctx.child()
        hybrid_ctx['ensemble_recommender'] = self._recommender_map[
            INTERVENTION_A]
        self._recommender_map[INTERVENTION_B] = HybridRecommender(hybrid_ctx)

        # The whitelist data is only used for test client IDs
        WHITELIST_S3_BUCKET = 'telemetry-parquet'
        WHITELIST_S3_KEY = 'telemetry-ml/addon_recommender/only_guids_top_200.json'
        self._whitelist_data = LazyJSONLoader(self._ctx, WHITELIST_S3_BUCKET,
                                              WHITELIST_S3_KEY)
Beispiel #10
0
    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx
        self.logger = self._ctx[IMozLogging].get_logger("taar")

        assert "profile_fetcher" in self._ctx

        self.profile_fetcher = ctx["profile_fetcher"]

        self._ensemble_recommender = EnsembleRecommender(self._ctx.child())

        # The whitelist data is only used for test client IDs

        self._whitelist_data = LazyJSONLoader(self._ctx, TAAR_WHITELIST_BUCKET,
                                              TAAR_WHITELIST_KEY)
Beispiel #11
0
    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx

        assert 'recommender_factory' in self._ctx
        assert 'profile_fetcher' in self._ctx

        recommender_factory = ctx['recommender_factory']
        profile_fetcher = ctx['profile_fetcher']

        self.profile_fetcher = profile_fetcher
        self.linear_recommenders = []
        self._recommender_map = {}

        logger.info("Initializing recommenders")
        for rkey in self.LINEAR_RECOMMENDER_ORDER:
            recommender = recommender_factory.create(rkey)

            self.linear_recommenders.append(recommender)
            self._recommender_map[rkey] = recommender

        # Install the recommender_map to the context and instantiate
        # the EnsembleRecommender
        self._ctx['recommender_map'] = self._recommender_map
        self._recommender_map['ensemble'] = EnsembleRecommender(
            self._ctx.child())
def install_ensemble_fixtures(ctx):
    ctx = install_mock_ensemble_data(ctx)

    factory = MockRecommenderFactory()
    ctx['recommender_factory'] = factory

    ctx['recommender_map'] = {'collaborative': factory.create('collaborative'),
                              'similarity': factory.create('similarity'),
                              'locale': factory.create('locale')}
    ctx['ensemble_recommender'] = EnsembleRecommender(ctx.child())
    return ctx
def test_recommendations(test_ctx):
    ctx = install_mock_ensemble_data(test_ctx)

    EXPECTED_RESULTS = [('ghi', 3430.0),
                        ('def', 3320.0),
                        ('ijk', 3200.0),
                        ('hij', 3100.0),
                        ('lmn', 420.0)]

    factory = MockRecommenderFactory()
    ctx['recommender_factory'] = factory

    ctx['recommender_map'] = {'collaborative': factory.create('collaborative'),
                              'similarity': factory.create('similarity'),
                              'locale': factory.create('locale')}
    r = EnsembleRecommender(ctx.child())
    client = {'client_id': '12345'}  # Anything will work here

    recommendation_list = r.recommend(client, 5)
    assert isinstance(recommendation_list, list)
    assert recommendation_list == EXPECTED_RESULTS
Beispiel #14
0
class RecommendationManager:
    """This class determines which of the set of recommendation
    engines will actually be used to generate recommendations."""
    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx
        self.logger = self._ctx[IMozLogging].get_logger("taar")

        assert "profile_fetcher" in self._ctx

        self.profile_fetcher = ctx["profile_fetcher"]

        self._ensemble_recommender = EnsembleRecommender(self._ctx.child())

        # The whitelist data is only used for test client IDs

        self._whitelist_data = LazyJSONLoader(self._ctx, TAAR_WHITELIST_BUCKET,
                                              TAAR_WHITELIST_KEY)

    def recommend(self, client_id, limit, extra_data={}):
        """Return recommendations for the given client.

        The recommendation logic will go through each recommender and
        pick the first one that "can_recommend".

        :param client_id: the client unique id.
        :param limit: the maximum number of recommendations to return.
        :param extra_data: a dictionary with extra client data.
        """

        if client_id in TEST_CLIENT_IDS:
            data = self._whitelist_data.get()[0]
            random.shuffle(data)
            samples = data[:limit]
            self.logger.info("Test ID detected [{}]".format(client_id))
            return [(s, 1.1) for s in samples]

        if client_id in EMPTY_TEST_CLIENT_IDS:
            self.logger.info("Empty Test ID detected [{}]".format(client_id))
            return []

        client_info = self.profile_fetcher.get(client_id)
        if client_info is None:
            self.logger.info(
                "Defaulting to empty results.  No client info fetched from dynamo."
            )
            return []

        results = self._ensemble_recommender.recommend(client_info, limit,
                                                       extra_data)

        return results
Beispiel #15
0
def install_ensemble_fixtures(ctx):
    ctx = install_mock_ensemble_data(ctx)

    factory = MockRecommenderFactory()
    ctx["recommender_factory"] = factory

    ctx["recommender_map"] = {
        "collaborative": factory.create("collaborative"),
        "similarity": factory.create("similarity"),
        "locale": factory.create("locale"),
    }
    ctx["ensemble_recommender"] = EnsembleRecommender(ctx.child())
    return ctx
Beispiel #16
0
class RecommendationManager:
    """This class determines which of the set of recommendation
    engines will actually be used to generate recommendations."""

    def __init__(self, ctx):
        """Initialize the user profile fetcher and the recommenders.
        """
        self._ctx = ctx
        self.logger = self._ctx[IMozLogging].get_logger("taar") if self._ctx[IMozLogging] else None

        assert "profile_fetcher" in self._ctx

        self.profile_fetcher = ctx["profile_fetcher"]

        self._ensemble_recommender = EnsembleRecommender(self._ctx.child())

        # The whitelist data is only used for test client IDs

        self._cache = self._ctx[ITAARCache]

    @metrics.timer_decorator("profile_recommendation")
    def recommend(self, client_id, limit, extra_data={}):
        """Return recommendations for the given client.

        The recommendation logic will go through each recommender and
        pick the first one that "can_recommend".

        :param client_id: the client unique id.
        :param limit: the maximum number of recommendations to return.
        :param extra_data: a dictionary with extra client data.
        """

        with log_timer_debug("recommmend executed", self.logger):
            # Read everything from redis now
            with log_timer_debug("redis read", self.logger):
                extra_data["cache"] = self._cache.cache_context()

            if is_test_client(client_id):
                # Just create a stub client_info blob
                client_info = {
                    "client_id": client_id,
                }
            else:
                with log_timer_debug("bigtable fetched data", self.logger):
                    client_info = self.profile_fetcher.get(client_id)

                if client_info is None:
                    self.logger.warning(
                        "Defaulting to empty results.  No client info fetched from storage backend."
                    )
                    return []

            # Fetch back all possible whitelisted addons for this
            # client
            extra_data["guid_randomization"] = True
            whitelist = extra_data["cache"]["whitelist"]
            results = self._ensemble_recommender.recommend(
                client_info, len(whitelist), extra_data
            )

            results = reorder_guids(results, limit)

            self.logger.info(
                f"Client recommendations results",
                extra={'client_id': client_id, 'recs': [r[0] for r in results]}
            )

            return results