2018-08-07 18:21:20 +03:00
|
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
"""
|
|
|
|
Test cases for the TAAR Hybrid recommender
|
|
|
|
"""
|
|
|
|
|
|
|
|
from taar.recommenders.hybrid_recommender import CuratedRecommender
|
2018-08-08 18:29:04 +03:00
|
|
|
from taar.recommenders.hybrid_recommender import HybridRecommender
|
|
|
|
from taar.recommenders.ensemble_recommender import EnsembleRecommender
|
2018-08-08 05:36:03 +03:00
|
|
|
|
2018-11-27 20:36:09 +03:00
|
|
|
from taar.recommenders.s3config import TAAR_WHITELIST_BUCKET, TAAR_WHITELIST_KEY
|
2018-11-27 19:42:18 +03:00
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
# from taar.recommenders.hybrid_recommender import ENSEMBLE_WEIGHTS
|
2018-08-08 18:29:04 +03:00
|
|
|
from .test_ensemblerecommender import install_mock_ensemble_data
|
|
|
|
from .mocks import MockRecommenderFactory
|
2018-08-08 05:36:03 +03:00
|
|
|
|
|
|
|
import json
|
|
|
|
from moto import mock_s3
|
|
|
|
import boto3
|
2018-08-07 18:21:20 +03:00
|
|
|
|
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
def install_no_curated_data(ctx):
|
2018-08-07 18:21:20 +03:00
|
|
|
ctx = ctx.child()
|
2018-11-27 19:42:18 +03:00
|
|
|
conn = boto3.resource("s3", region_name="us-west-2")
|
2018-08-08 05:36:03 +03:00
|
|
|
|
2018-11-27 20:36:09 +03:00
|
|
|
conn.create_bucket(Bucket=TAAR_WHITELIST_BUCKET)
|
|
|
|
conn.Object(TAAR_WHITELIST_BUCKET, TAAR_WHITELIST_KEY).put(Body="")
|
2018-08-07 18:21:20 +03:00
|
|
|
|
|
|
|
return ctx
|
|
|
|
|
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
def install_mock_curated_data(ctx):
|
|
|
|
mock_data = []
|
|
|
|
for i in range(20):
|
2018-08-17 06:19:06 +03:00
|
|
|
mock_data.append(str(i) * 16)
|
2018-08-07 18:21:20 +03:00
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
ctx = ctx.child()
|
2018-11-27 19:42:18 +03:00
|
|
|
conn = boto3.resource("s3", region_name="us-west-2")
|
2018-08-07 18:21:20 +03:00
|
|
|
|
2018-11-27 20:36:09 +03:00
|
|
|
conn.create_bucket(Bucket=TAAR_WHITELIST_BUCKET)
|
|
|
|
conn.Object(TAAR_WHITELIST_BUCKET, TAAR_WHITELIST_KEY).put(
|
|
|
|
Body=json.dumps(mock_data)
|
|
|
|
)
|
2018-08-07 18:21:20 +03:00
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
return ctx
|
|
|
|
|
|
|
|
|
2018-08-08 18:29:04 +03:00
|
|
|
def install_ensemble_fixtures(ctx):
|
|
|
|
ctx = install_mock_ensemble_data(ctx)
|
|
|
|
|
|
|
|
factory = MockRecommenderFactory()
|
2018-11-27 19:42:18 +03:00
|
|
|
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())
|
2018-08-08 18:29:04 +03:00
|
|
|
return ctx
|
|
|
|
|
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
@mock_s3
|
|
|
|
def test_curated_can_recommend(test_ctx):
|
|
|
|
ctx = install_no_curated_data(test_ctx)
|
2018-08-07 18:21:20 +03:00
|
|
|
r = CuratedRecommender(ctx)
|
|
|
|
|
|
|
|
# CuratedRecommender will always recommend something no matter
|
|
|
|
# what
|
2018-08-08 05:36:03 +03:00
|
|
|
assert r.can_recommend({})
|
|
|
|
assert r.can_recommend({"installed_addons": []})
|
2018-08-07 18:21:20 +03:00
|
|
|
|
2018-08-07 19:56:24 +03:00
|
|
|
|
2018-08-08 05:36:03 +03:00
|
|
|
@mock_s3
|
2018-08-07 19:56:24 +03:00
|
|
|
def test_curated_recommendations(test_ctx):
|
2018-08-08 05:36:03 +03:00
|
|
|
ctx = install_mock_curated_data(test_ctx)
|
2018-08-07 19:56:24 +03:00
|
|
|
r = CuratedRecommender(ctx)
|
|
|
|
|
|
|
|
# CuratedRecommender will always recommend something no matter
|
|
|
|
# what
|
|
|
|
|
|
|
|
for LIMIT in range(1, 5):
|
2018-11-27 19:42:18 +03:00
|
|
|
guid_list = r.recommend({"client_id": "000000"}, limit=LIMIT)
|
2018-08-07 19:56:24 +03:00
|
|
|
# The curated recommendations should always return with some kind
|
|
|
|
# of recommendations
|
|
|
|
assert len(guid_list) == LIMIT
|
|
|
|
|
|
|
|
|
2018-08-08 18:29:04 +03:00
|
|
|
@mock_s3
|
2018-08-07 19:56:24 +03:00
|
|
|
def test_hybrid_recommendations(test_ctx):
|
2018-08-08 18:29:04 +03:00
|
|
|
# verify that the recommendations mix the curated and
|
|
|
|
# ensemble results
|
|
|
|
ctx = install_mock_curated_data(test_ctx)
|
|
|
|
ctx = install_ensemble_fixtures(ctx)
|
|
|
|
|
|
|
|
r = HybridRecommender(ctx)
|
|
|
|
|
|
|
|
# Test that we can generate lists of results
|
|
|
|
for LIMIT in range(4, 8):
|
2018-11-27 19:42:18 +03:00
|
|
|
guid_list = r.recommend({"client_id": "000000"}, limit=LIMIT)
|
2018-08-08 18:29:04 +03:00
|
|
|
# The curated recommendations should always return with some kind
|
|
|
|
# of recommendations
|
|
|
|
assert len(guid_list) == LIMIT
|
|
|
|
|
|
|
|
# Test that the results are actually mixed
|
2018-11-27 19:42:18 +03:00
|
|
|
guid_list = r.recommend({"client_id": "000000"}, limit=4)
|
2018-08-08 18:29:04 +03:00
|
|
|
|
|
|
|
# A mixed list will have two recommendations with weight > 1.0
|
|
|
|
# (ensemble) and 2 with exactly weight 1.0 from the curated list
|
|
|
|
|
|
|
|
assert guid_list[0][1] > 1.0
|
|
|
|
assert guid_list[1][1] > 1.0
|
|
|
|
assert guid_list[2][1] == 1.0
|
|
|
|
assert guid_list[3][1] == 1.0
|