def test_user_genres_in_recommendation_size_25(self): """ [recommendation.api.GetRecommendation] At least 19 of the top genres in the size 25 recommendation """ get_cache("default").clear() LogEntry.objects.all().delete() size = 25 response = \ self.client.get("/api/v2/recommend/%d/" "00b65a359307654a7deee7c71a7563d2816d6b7e522377a66aaefe8848da5961/" % size) user_id = User.get_user_id_by_external_id("00b65a359307654a7deee7c71a7563d2816d6b7e522377a66aaefe8848da5961") user_genres = sorted(ItemGenre.genre_in( Item.get_item_by_id(item_id) for item_id in User.get_user_items(user_id) ).items(), key=lambda x: x[1], reverse=True) recommendation_genres = ItemGenre.genre_in( Item.get_item_by_external_id(item_eid) for item_eid in json.loads(response.content)["recommendations"] ) measure = [] for no, (genre, _) in enumerate(user_genres[:int(size)], start=1): if genre not in recommendation_genres: measure.append(no) assert len(measure) < 6, "Major genres failing by index: %s." \ "\nUser %s" \ "\nRecommendation %s" % ( measure, user_genres, [ItemGenre.genre_in([Item.get_item_by_external_id(item)]) for item in json.loads(response.content)["recommendations"]])
def test_owned_items(self): """ [recommendation.models.User] Test owned items """ for u in USERS: user = User.get_user_by_external_id(u["external_id"]) for i in u["items"]: ivent = Inventory.objects.get(item=user.all_items[Item.get_item_by_external_id(i).pk], user=user) ivent.is_dropped = True ivent.save() assert Item.get_item_by_external_id(i).pk not in user.owned_items, \ "Item %s is in user %s owned items" % (i, user.external_id) ivent = Inventory.objects.get(item=user.all_items[Item.get_item_by_external_id(i).pk], user=user) ivent.is_dropped = False ivent.save()
def test_recommendation_update_user(self): """ [recommendation.api.GetUserItems] Test update user items """ response = self.client.put( "/api/v2/user-items/00504e6196ab5fa37ae7450dad99d031a80c50ef4b762c15151a2e4e92c64e0b/", '{"user_items": ["504343", "413346"]}', content_type="application/json" ) sleep(0.8) user = User.get_user_by_external_id("00504e6196ab5fa37ae7450dad99d031a80c50ef4b762c15151a2e4e92c64e0b") assert response.status_code == 200, "Request failed. Status code %d." % response.status_code assert len(user.owned_items) == 2, "Owned items should be 3(%d)" % len(user.owned_items) assert Item.get_item_by_external_id("504343").pk in user.owned_items, "New item not in owned items" assert Item.get_item_by_external_id("413346").pk in user.owned_items, "New item not in owned items"
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for language in LANGUAGES: Locale.objects.create(**language) for app in ITEMS: item = Item.objects.create(id=app["id"], name=app["name"], external_id=app["external_id"]) for language in app["languages"]: l = Locale.objects.get(country_code=language) ItemLocale.objects.create(locale=l, item=item) for u in USERS: user = User.objects.create(id=u["id"], external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) for language in u["languages"]: l = Locale.objects.get(country_code=language) UserLocale.objects.create(locale=l, user=user) Item.load_to_cache() User.load_to_cache() Locale.load_to_cache()
def test_diversity_on_recommendation_25(self): """ [recommendation.api.GetRecommendation] Test diversity for size 25 recommendation (at least 2/3 of user genres) """ size = 25 response = \ self.client.get("/api/v2/recommend/%d/" "00b65a359307654a7deee7c71a7563d2816d6b7e522377a66aaefe8848da5961/" % size) user_id = User.get_user_id_by_external_id("00b65a359307654a7deee7c71a7563d2816d6b7e522377a66aaefe8848da5961") user_genres = ItemGenre.genre_in( Item.get_item_by_id(item_id) for item_id in User.get_user_items(user_id) ) recommendation_genres = ItemGenre.genre_in( Item.get_item_by_external_id(item_eid) for item_eid in json.loads(response.content)["recommendations"] ) less, more = (user_genres, recommendation_genres) if len(user_genres) < len(recommendation_genres) else \ (recommendation_genres, user_genres) measure = 0 for genre in less: if genre in more: measure += 1 assert measure > len(less)*2./3., \ "Not sufficient genres in recommendation" \ "(user: %d, recommendation: %d, similarity: %d)" % (len(user_genres), len(recommendation_genres), measure)
def setup_class(cls, *args, **kwargs): """ Put elements in db """ logger = LogEvent(LogEvent.RECOMMEND) for app in ITEMS: Item.objects.create(**app) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) for _ in range(3): recommendation = [Item.get_item_by_external_id(i).pk for i in ("10001", "10002", "10003", "10004", "98766")] shuffle(recommendation) logger(lambda user: recommendation)(user=user) time.sleep(1.)
def test_user_items(self): """ [recommendation.models.User] Test user items """ for u in USERS: user = User.get_user_by_external_id(u["external_id"]) for i in u["items"]: assert Item.get_item_by_external_id(i).pk in user.all_items, \ "Item %s is not in user %s" % (i, user.external_id)
def test_get_item_by_external_id(self): """ [recommendation.models.Item] Test queries by external id made by getting items and check integrity of that items """ with self.assertNumQueries(0): for app in ITEMS: item = Item.get_item_by_external_id(app["external_id"]) assert isinstance(item, Item), "Cached item is not instance of Item." assert item.name == app["name"], "Name of the app is not correct"
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for app in ITEMS: Item.objects.create(**app) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i))
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for app in ITEMS: Item.objects.create(**app) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i))
def setup_class(cls, *args, **kwargs): """ Put elements in db """ logger = LogEvent(LogEvent.RECOMMEND) for app in ITEMS: Item.objects.create(**app) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) for _ in range(3): recommendation = [ Item.get_item_by_external_id(i).pk for i in ("10001", "10002", "10003", "10004", "98766") ] shuffle(recommendation) logger(lambda user: recommendation)(user=user) time.sleep(1.)
def setup_class(cls, *args, **kwargs): """ Put elements in db """ cls.df = pd.read_csv(resource_filename(testfm.__name__, "data/movielenshead.dat"), sep="::", header=None, names=["user", "item", "rating", "date", "title"]) for i, app in enumerate(ITEMS, start=1): Item.objects.create(pk=(i*2), **app) for i, u in enumerate(USERS, start=1): user = User.objects.create(pk=(i*2), external_id=u["external_id"]) for item in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(item))
def test_click_logging(self): """ [recommendation.decorator.SimpleLogger] Test if a clicked item is logged """ logger = LogEvent(LogEvent.CLICK) user = User.get_user_by_external_id("joaonrb") logger(lambda uid, iid: None)(user, Item.get_item_by_external_id("10004")) time.sleep(1.) logs = list(LogEntry.objects.filter(user=user, type=logger.CLICK)) assert len(logs) == 1, "Number of register is not correct %s" % logs assert "10004" == logs[0].item.external_id, \ "The item in log is incorrect(1004 != %s)" % logs[0].item.external_id
def test_acquire_logging(self): """ [recommendation.decorator.SimpleLogger] Test if a acquired item is logged """ logger = LogEvent(LogEvent.ACQUIRE) user = User.get_user_by_external_id("joaonrb") logger(lambda uid, iid: None)(user, Item.get_item_by_external_id("10004")) time.sleep(1.) logs = list(LogEntry.objects.filter(user=user, type=logger.ACQUIRE)) assert len(logs) == 1, "Number of register is not correct %s" % logs assert "10004" == logs[0].item.external_id, \ "The item in log is incorrect(1004 != %s)" % logs[0].item.external_id
def test_reranker_diversity(self): """ [recommendation.diversity.ReRanker] Test a diversity re-ranker on recommendation """ diversity = SimpleDiversityReRanker() recommendation = [Item.get_item_by_external_id(i).pk for i in ("10001", "10002", "10003", "10004", "98766")] shuffle(recommendation) for u in USERS: user = User.get_user_by_external_id(u["external_id"]) with self.assertNumQueries(0): result = diversity(user=user, recommendation=recommendation[:], size=5) new_rec = [aid+1 for aid, _ in sorted(enumerate(result), key=lambda x: x[1], reverse=True)] assert len(result) == len(ITEMS), "Recommendation size changed (%d != %s)" % (len(new_rec), len(ITEMS))
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for app in ITEMS: Item.objects.create(**app) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) TensorCoFi.train_from_db() Popularity.train_from_db() TensorCoFi.load_to_cache() Popularity.load_to_cache()
def test_recommendation_acquire_new_item(self): """ [recommendation.api.GetUserItems] Test acquire new item """ user = User.get_user_by_external_id("00504e6196ab5fa37ae7450dad99d031a80c50ef4b762c15151a2e4e92c64e0b") items = user.owned_items response = self.client.post( "/api/v2/user-items/00504e6196ab5fa37ae7450dad99d031a80c50ef4b762c15151a2e4e92c64e0b/", {"item_to_acquire": "504343"} ) sleep(0.8) assert response.status_code == 200, "Request failed. Status code %d." % response.status_code assert len(user.owned_items) == len(items)+1, "Owned items should be %d(%d)" % (len(items)+1, len(user.owned_items)) assert Item.get_item_by_external_id("504343").pk in user.owned_items.keys(), "New item not in owned items"
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for genre in GENRES: Genre.objects.create(**genre) for app in ITEMS: item = Item.objects.create(name=app["name"], external_id=app["external_id"]) for genre in app["genres"]: g = Genre.objects.get(name=genre) ItemGenre.objects.create(item=item, type=g) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) Genre.load_to_cache() ItemGenre.load_to_cache()
def test_recommendation_logging(self): """ [recommendation.decorator.SimpleLogger] Test if a recommendation is logged """ logger = LogEvent(LogEvent.RECOMMEND) user = User.get_user_by_external_id("joaonrb") recommendation = [Item.get_item_by_external_id(i).pk for i in ("10001", "10002", "10003", "10004", "98766")] recommendation = logger(lambda user: recommendation)(user=user) time.sleep(1.) logs = list(LogEntry.objects.filter(user=user, type=logger.RECOMMEND).order_by("value")) assert len(logs) == 5, "Number of register is not correct %s" % logs logs_iter = iter(logs) for i, item in enumerate(recommendation, start=1): log = logs_iter.next() assert item == log.item.pk, "The item in position %d is not the same that in recommendation " \ "(%s != %s)" % (i, item, log.item.external_id) assert i == log.value, "The item in position %d do not have the right value. (%d)" % (i, log.value)
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for region in REGIONS: Region.objects.create(**region) for app in ITEMS: item = Item.objects.create(id=app["id"], name=app["name"], external_id=app["external_id"]) for region in app["regions"]: ItemRegion.objects.create(region=Region.objects.get(slug=region), item=item) for u in USERS: user = User.objects.create(id=u["id"], external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) UserRegion.objects.create(region=Region.objects.get(slug=u["region"]), user=user) Item.load_to_cache() User.load_to_cache() Region.load_to_cache()
def delete(self, request, user_external_id): """ removes an old item in the user installed apps. It should have a special POST parameter (besides the csrf token or other token needed to the connection) that is item_to_acquire. The ´´item_to_remove´´ is the item external id that is supposed to be removed in the user inventory. :param request: The HTTP request. :param user_external_id: The user external id that are making the request. :return: A success response if the input was successful =p """ try: item_id = request.DATA["item_to_remove"] except KeyError: return self.format_response(PARAMETERS_IN_MISS, status=FORMAT_ERROR) self.remove_item(User.get_user_by_external_id(user_external_id), Item.get_item_by_external_id(item_id)) return self.format_response(SUCCESS_MESSAGE)
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for genre in GENRES: Genre.objects.create(**genre) for app in ITEMS: item = Item.objects.create(name=app["name"], external_id=app["external_id"]) for genre in app["genres"]: g = Genre.objects.get(name=genre) ItemGenre.objects.create(item=item, type=g) for u in USERS: user = User.objects.create(external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) Genre.load_to_cache() ItemGenre.load_to_cache()
def post(self, request, user_external_id): """ Inserts a new item in the user owned items. It should have a special POST parameter (besides the csrf token or other token needed to the connection - to development and presentation purposes the csrf was disabled) that is item_to_acquire. The ´´item_to_acquire´´ is the item external id that is supposed to be in the user inventory. :param request: The HTTP request. :param user_external_id: The user external id that are making the request. :return: A success response if the input was successful =p """ try: item_id = request.POST["item_to_acquire"] except KeyError: return self.format_response(PARAMETERS_IN_MISS, status=FORMAT_ERROR) self.insert_acquisition(User.get_user_by_external_id(user_external_id), Item.get_item_by_external_id(item_id)) return self.format_response(SUCCESS_MESSAGE)
def delete(self, request, user_external_id): """ removes an old item in the user installed apps. It should have a special POST parameter (besides the csrf token or other token needed to the connection) that is item_to_acquire. The ´´item_to_remove´´ is the item external id that is supposed to be removed in the user inventory. :param request: The HTTP request. :param user_external_id: The user external id that are making the request. :return: A success response if the input was successful =p """ try: item_id = request.DATA["item_to_remove"] except KeyError: return self.format_response(PARAMETERS_IN_MISS, status=FORMAT_ERROR) self.remove_item(User.get_user_by_external_id(user_external_id), Item.get_item_by_external_id(item_id)) return self.format_response(SUCCESS_MESSAGE)
def post(self, request, user_external_id): """ Inserts a new item in the user owned items. It should have a special POST parameter (besides the csrf token or other token needed to the connection - to development and presentation purposes the csrf was disabled) that is item_to_acquire. The ´´item_to_acquire´´ is the item external id that is supposed to be in the user inventory. :param request: The HTTP request. :param user_external_id: The user external id that are making the request. :return: A success response if the input was successful =p """ try: item_id = request.POST["item_to_acquire"] except KeyError: return self.format_response(PARAMETERS_IN_MISS, status=FORMAT_ERROR) self.insert_acquisition(User.get_user_by_external_id(user_external_id), Item.get_item_by_external_id(item_id)) return self.format_response(SUCCESS_MESSAGE)
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for language in LANGUAGES: Locale.objects.create(**language) for app in ITEMS: item = Item.objects.create(id=app["id"], name=app["name"], external_id=app["external_id"]) for language in app["languages"]: l = Locale.objects.get(country_code=language) ItemLocale.objects.create(locale=l, item=item) for u in USERS: user = User.objects.create(id=u["id"], external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) for language in u["languages"]: l = Locale.objects.get(country_code=language) UserLocale.objects.create(locale=l, user=user) Item.load_to_cache() User.load_to_cache() Locale.load_to_cache()
def put(self, request, user_external_id): """ Replaces all the user items with the list of given items. It should have a PUT body parameter items_to_acquire (besides the csrf token or other token needed to the connection - to development and presentation purposes the csrf was disabled) that is. The ´´items_to_acquire´´ is the list of items external ids that will become a new user inventory. :param request: The HTTP request. :param user_external_id: The user external id that are making the request. :return: A success response if the input was successful =p """ try: items_ids = request.DATA["user_items"] except KeyError: return self.format_response(PARAMETERS_IN_MISS, status=FORMAT_ERROR) try: user = User.get_user_by_external_id(user_external_id) except User.DoesNotExist: user = User.objects.create(external_id=user_external_id) items = [Item.get_item_by_external_id(iid) for iid in items_ids] self.update_user_items(user, items) return self.format_response(SUCCESS_MESSAGE)
def test_recommendation_logging(self): """ [recommendation.decorator.SimpleLogger] Test if a recommendation is logged """ logger = LogEvent(LogEvent.RECOMMEND) user = User.get_user_by_external_id("joaonrb") recommendation = [ Item.get_item_by_external_id(i).pk for i in ("10001", "10002", "10003", "10004", "98766") ] recommendation = logger(lambda user: recommendation)(user=user) time.sleep(1.) logs = list( LogEntry.objects.filter(user=user, type=logger.RECOMMEND).order_by("value")) assert len(logs) == 5, "Number of register is not correct %s" % logs logs_iter = iter(logs) for i, item in enumerate(recommendation, start=1): log = logs_iter.next() assert item == log.item.pk, "The item in position %d is not the same that in recommendation " \ "(%s != %s)" % (i, item, log.item.external_id) assert i == log.value, "The item in position %d do not have the right value. (%d)" % ( i, log.value)
def test_reranker_diversity_no_redundancy(self): """ [recommendation.diversity.ReRanker] Test a diversity re-ranker on recommendation for non redundancy and loss """ diversity = SimpleDiversityReRanker() recommendation = [ Item.get_item_by_external_id(i).pk for i in ("10001", "10002", "10003", "10004", "98766") ] shuffle(recommendation) for u in USERS: user = User.get_user_by_external_id(u["external_id"]) with self.assertNumQueries(0): result = diversity(user=user, recommendation=recommendation[:], size=5) new_rec = [ aid + 1 for aid, _ in sorted( enumerate(result), key=lambda x: x[1], reverse=True) ] assert len(set(result)) == len( ITEMS), "Recommendation size changed (%d != %s)" % ( len(new_rec), len(ITEMS))
def setup_class(cls, *args, **kwargs): """ Put elements in db """ for region in REGIONS: Region.objects.create(**region) for app in ITEMS: item = Item.objects.create(id=app["id"], name=app["name"], external_id=app["external_id"]) for region in app["regions"]: ItemRegion.objects.create( region=Region.objects.get(slug=region), item=item) for u in USERS: user = User.objects.create(id=u["id"], external_id=u["external_id"]) for i in u["items"]: Inventory.objects.create(user=user, item=Item.get_item_by_external_id(i)) UserRegion.objects.create( region=Region.objects.get(slug=u["region"]), user=user) Item.load_to_cache() User.load_to_cache() Region.load_to_cache()
def put(self, request, user_external_id): """ Replaces all the user items with the list of given items. It should have a PUT body parameter items_to_acquire (besides the csrf token or other token needed to the connection - to development and presentation purposes the csrf was disabled) that is. The ´´items_to_acquire´´ is the list of items external ids that will become a new user inventory. :param request: The HTTP request. :param user_external_id: The user external id that are making the request. :return: A success response if the input was successful =p """ try: items_ids = request.DATA["user_items"] except KeyError: return self.format_response(PARAMETERS_IN_MISS, status=FORMAT_ERROR) try: user = User.get_user_by_external_id(user_external_id) except User.DoesNotExist: user = User.objects.create(external_id=user_external_id) items = [Item.get_item_by_external_id(iid) for iid in items_ids] self.update_user_items(user, items) return self.format_response(SUCCESS_MESSAGE)