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
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
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)
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 __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
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
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
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