Commit 8a5b273cbe0b6b86390d5f40b92e867e1bfcb54d
1 parent
842edc0b
Exists in
master
and in
1 other branch
Added ranking to RecommendationResults and small fixes for strategies.
Showing
2 changed files
with
85 additions
and
21 deletions
Show diff stats
src/recommender.py
| @@ -28,12 +28,14 @@ class RecommendationResult: | @@ -28,12 +28,14 @@ class RecommendationResult: | ||
| 28 | """ | 28 | """ |
| 29 | Class designed to describe a recommendation result: items and scores. | 29 | Class designed to describe a recommendation result: items and scores. |
| 30 | """ | 30 | """ |
| 31 | - def __init__(self,item_score): | 31 | + def __init__(self,item_score,ranking=0): |
| 32 | """ | 32 | """ |
| 33 | Set initial parameters. | 33 | Set initial parameters. |
| 34 | """ | 34 | """ |
| 35 | self.item_score = item_score | 35 | self.item_score = item_score |
| 36 | self.size = len(item_score) | 36 | self.size = len(item_score) |
| 37 | + if ranking: | ||
| 38 | + self.ranking = ranking | ||
| 37 | 39 | ||
| 38 | def __str__(self): | 40 | def __str__(self): |
| 39 | """ | 41 | """ |
| @@ -64,13 +66,13 @@ class Recommender: | @@ -64,13 +66,13 @@ class Recommender: | ||
| 64 | """ | 66 | """ |
| 65 | Set initial parameters. | 67 | Set initial parameters. |
| 66 | """ | 68 | """ |
| 69 | + self.cfg = cfg | ||
| 67 | self.items_repository = xapian.Database(cfg.axi) | 70 | self.items_repository = xapian.Database(cfg.axi) |
| 68 | self.set_strategy(cfg.strategy) | 71 | self.set_strategy(cfg.strategy) |
| 69 | if cfg.weight == "bm25": | 72 | if cfg.weight == "bm25": |
| 70 | self.weight = xapian.BM25Weight() | 73 | self.weight = xapian.BM25Weight() |
| 71 | else: | 74 | else: |
| 72 | self.weight = xapian.TradWeight() | 75 | self.weight = xapian.TradWeight() |
| 73 | - self.cfg = cfg | ||
| 74 | 76 | ||
| 75 | def set_strategy(self,strategy_str): | 77 | def set_strategy(self,strategy_str): |
| 76 | """ | 78 | """ |
| @@ -83,10 +85,10 @@ class Recommender: | @@ -83,10 +85,10 @@ class Recommender: | ||
| 83 | if strategy_str == "cbd": | 85 | if strategy_str == "cbd": |
| 84 | self.strategy = strategy.ContentBasedStrategy("desc") | 86 | self.strategy = strategy.ContentBasedStrategy("desc") |
| 85 | if strategy_str == "col": | 87 | if strategy_str == "col": |
| 86 | - self.strategy = strategy.CollaborativeStrategy(20) | ||
| 87 | self.users_repository = data.PopconXapianIndex(self.cfg) | 88 | self.users_repository = data.PopconXapianIndex(self.cfg) |
| 89 | + self.strategy = strategy.CollaborativeStrategy(20) | ||
| 88 | 90 | ||
| 89 | - def get_recommendation(self,user,result_size=20): | 91 | + def get_recommendation(self,user,result_size=100): |
| 90 | """ | 92 | """ |
| 91 | Produces recommendation using previously loaded strategy. | 93 | Produces recommendation using previously loaded strategy. |
| 92 | """ | 94 | """ |
src/strategy.py
| @@ -42,6 +42,26 @@ class PkgMatchDecider(xapian.MatchDecider): | @@ -42,6 +42,26 @@ class PkgMatchDecider(xapian.MatchDecider): | ||
| 42 | """ | 42 | """ |
| 43 | return doc.get_data() not in self.pkgs_list | 43 | return doc.get_data() not in self.pkgs_list |
| 44 | 44 | ||
| 45 | +class AppMatchDecider(xapian.MatchDecider): | ||
| 46 | + """ | ||
| 47 | + Extend xapian.MatchDecider to not consider only applications packages. | ||
| 48 | + """ | ||
| 49 | + def __init__(self, pkgs_list, axi): | ||
| 50 | + """ | ||
| 51 | + Set initial parameters. | ||
| 52 | + """ | ||
| 53 | + xapian.MatchDecider.__init__(self) | ||
| 54 | + self.pkgs_list = pkgs_list | ||
| 55 | + self.axi = axi | ||
| 56 | + | ||
| 57 | + def __call__(self, doc): | ||
| 58 | + """ | ||
| 59 | + True if the package is not already installed. | ||
| 60 | + """ | ||
| 61 | + tags = axi_search_pkg_tags(self.axi,doc.get_data()) | ||
| 62 | + return (("XTrole::program" in tags) and | ||
| 63 | + (doc.get_data() not in self.pkgs_list)) | ||
| 64 | + | ||
| 45 | class UserMatchDecider(xapian.MatchDecider): | 65 | class UserMatchDecider(xapian.MatchDecider): |
| 46 | """ | 66 | """ |
| 47 | Extend xapian.MatchDecider to match similar profiles. | 67 | Extend xapian.MatchDecider to match similar profiles. |
| @@ -73,7 +93,32 @@ class PkgExpandDecider(xapian.ExpandDecider): | @@ -73,7 +93,32 @@ class PkgExpandDecider(xapian.ExpandDecider): | ||
| 73 | True if the term is a package. | 93 | True if the term is a package. |
| 74 | """ | 94 | """ |
| 75 | # [FIXME] return term.startswith("XP") | 95 | # [FIXME] return term.startswith("XP") |
| 76 | - return not term.startswith("XT") | 96 | + #return not term.startswith("XT") |
| 97 | + return term.startswith("XP") | ||
| 98 | + | ||
| 99 | +class AppExpandDecider(xapian.ExpandDecider): | ||
| 100 | + """ | ||
| 101 | + Extend xapian.ExpandDecider to consider applications only. | ||
| 102 | + """ | ||
| 103 | + def __init__(self,axi): | ||
| 104 | + xapian.ExpandDecider.__init__(self) | ||
| 105 | + self.axi = axi | ||
| 106 | + | ||
| 107 | + def __call__(self, term): | ||
| 108 | + """ | ||
| 109 | + True if the term is a package. | ||
| 110 | + """ | ||
| 111 | + if not term.startswith("XT"): | ||
| 112 | + package = term.lstrip("XP") | ||
| 113 | + print package | ||
| 114 | + tags = axi_search_pkg_tags(self.axi,package) | ||
| 115 | + if "XTrole::program" in tags: | ||
| 116 | + print tags | ||
| 117 | + return True | ||
| 118 | + else: | ||
| 119 | + return False | ||
| 120 | + else: | ||
| 121 | + return False | ||
| 77 | 122 | ||
| 78 | class TagExpandDecider(xapian.ExpandDecider): | 123 | class TagExpandDecider(xapian.ExpandDecider): |
| 79 | """ | 124 | """ |
| @@ -100,7 +145,7 @@ class ContentBasedStrategy(RecommendationStrategy): | @@ -100,7 +145,7 @@ class ContentBasedStrategy(RecommendationStrategy): | ||
| 100 | self.content = content | 145 | self.content = content |
| 101 | self.profile_size = profile_size | 146 | self.profile_size = profile_size |
| 102 | 147 | ||
| 103 | - def run(self,rec,user,limit): | 148 | + def run(self,rec,user,recommendation_size): |
| 104 | """ | 149 | """ |
| 105 | Perform recommendation strategy. | 150 | Perform recommendation strategy. |
| 106 | """ | 151 | """ |
| @@ -113,35 +158,40 @@ class ContentBasedStrategy(RecommendationStrategy): | @@ -113,35 +158,40 @@ class ContentBasedStrategy(RecommendationStrategy): | ||
| 113 | enquire.set_query(query) | 158 | enquire.set_query(query) |
| 114 | try: | 159 | try: |
| 115 | # retrieve matching packages | 160 | # retrieve matching packages |
| 116 | - mset = enquire.get_mset(0, limit, None, PkgMatchDecider(user.items())) | 161 | + mset = enquire.get_mset(0, recommendation_size, None, |
| 162 | + PkgMatchDecider(user.items())) | ||
| 163 | + #AppMatchDecider(user.items(), | ||
| 164 | + # rec.items_repository)) | ||
| 117 | except xapian.DatabaseError as error: | 165 | except xapian.DatabaseError as error: |
| 118 | logging.critical("Content-based strategy: "+error.get_msg()) | 166 | logging.critical("Content-based strategy: "+error.get_msg()) |
| 119 | # compose result dictionary | 167 | # compose result dictionary |
| 120 | item_score = {} | 168 | item_score = {} |
| 169 | + ranking = [] | ||
| 121 | for m in mset: | 170 | for m in mset: |
| 171 | + #[FIXME] set this constraint somehow | ||
| 172 | + #tags = axi_search_pkg_tags(rec.items_repository,m.document.get_data()) | ||
| 173 | + #if "XTrole::program" in tags: | ||
| 122 | item_score[m.document.get_data()] = m.weight | 174 | item_score[m.document.get_data()] = m.weight |
| 123 | - return recommender.RecommendationResult(item_score) | 175 | + ranking.append(m.document.get_data()) |
| 176 | + | ||
| 177 | + return recommender.RecommendationResult(item_score,ranking) | ||
| 124 | 178 | ||
| 125 | class CollaborativeStrategy(RecommendationStrategy): | 179 | class CollaborativeStrategy(RecommendationStrategy): |
| 126 | """ | 180 | """ |
| 127 | Colaborative recommendation strategy. | 181 | Colaborative recommendation strategy. |
| 128 | """ | 182 | """ |
| 129 | - def __init__(self,k,clustering=1): | 183 | + def __init__(self,k): |
| 130 | self.description = "Collaborative" | 184 | self.description = "Collaborative" |
| 131 | - self.clustering = clustering | ||
| 132 | self.neighbours = k | 185 | self.neighbours = k |
| 133 | 186 | ||
| 134 | - def run(self,rec,user,result_size): | 187 | + def run(self,rec,user,recommendation_size): |
| 135 | """ | 188 | """ |
| 136 | Perform recommendation strategy. | 189 | Perform recommendation strategy. |
| 137 | """ | 190 | """ |
| 138 | - profile = user.pkg_profile | 191 | + profile = ["XP"+package for package in user.pkg_profile] |
| 139 | # prepair index for querying user profile | 192 | # prepair index for querying user profile |
| 140 | query = xapian.Query(xapian.Query.OP_OR,profile) | 193 | query = xapian.Query(xapian.Query.OP_OR,profile) |
| 141 | - if self.clustering: | ||
| 142 | - enquire = xapian.Enquire(rec.clustered_users_repository) | ||
| 143 | - else: | ||
| 144 | - enquire = xapian.Enquire(rec.users_repository) | 194 | + enquire = xapian.Enquire(rec.users_repository) |
| 145 | enquire.set_weighting_scheme(rec.weight) | 195 | enquire.set_weighting_scheme(rec.weight) |
| 146 | enquire.set_query(query) | 196 | enquire.set_query(query) |
| 147 | try: | 197 | try: |
| @@ -155,27 +205,39 @@ class CollaborativeStrategy(RecommendationStrategy): | @@ -155,27 +205,39 @@ class CollaborativeStrategy(RecommendationStrategy): | ||
| 155 | rset.add_document(m.document.get_docid()) | 205 | rset.add_document(m.document.get_docid()) |
| 156 | logging.debug(m.document.get_data()) | 206 | logging.debug(m.document.get_data()) |
| 157 | # retrieve most relevant packages | 207 | # retrieve most relevant packages |
| 158 | - eset = enquire.get_eset(result_size,rset,PkgExpandDecider()) | 208 | + #eset = enquire.get_eset(recommendation_size,rset, |
| 209 | + # AppExpandDecider(rec.items_repository)) | ||
| 210 | + eset = enquire.get_eset(recommendation_size,rset,PkgExpandDecider()) | ||
| 159 | # compose result dictionary | 211 | # compose result dictionary |
| 160 | item_score = {} | 212 | item_score = {} |
| 161 | - for package in eset: | ||
| 162 | - item_score[package.term.lstrip("XP")] = package.weight | 213 | + for e in eset: |
| 214 | + package = e.term.lstrip("XP") | ||
| 215 | + tags = axi_search_pkg_tags(rec.items_repository,package) | ||
| 216 | + #[FIXME] set this constraint somehow | ||
| 217 | + #if "XTrole::program" in tags: | ||
| 218 | + item_score[package] = e.weight | ||
| 163 | return recommender.RecommendationResult(item_score) | 219 | return recommender.RecommendationResult(item_score) |
| 164 | 220 | ||
| 165 | class DemographicStrategy(RecommendationStrategy): | 221 | class DemographicStrategy(RecommendationStrategy): |
| 166 | """ | 222 | """ |
| 167 | Recommendation strategy based on demographic data. | 223 | Recommendation strategy based on demographic data. |
| 168 | """ | 224 | """ |
| 225 | + #def __init__(self, result): | ||
| 226 | + #self.result = result | ||
| 169 | def __init__(self): | 227 | def __init__(self): |
| 170 | self.description = "Demographic" | 228 | self.description = "Demographic" |
| 171 | logging.debug("Demographic recommendation not yet implemented.") | 229 | logging.debug("Demographic recommendation not yet implemented.") |
| 172 | raise Error | 230 | raise Error |
| 173 | 231 | ||
| 174 | - def run(self,user,items_repository): | 232 | + def run(self,rec,user,recommendation_size): |
| 175 | """ | 233 | """ |
| 176 | Perform recommendation strategy. | 234 | Perform recommendation strategy. |
| 177 | """ | 235 | """ |
| 178 | - pass | 236 | + ordered_result = self.result.get_prediction() |
| 237 | + | ||
| 238 | + for item,weight in ordered_result: | ||
| 239 | + pass | ||
| 240 | + | ||
| 179 | 241 | ||
| 180 | class KnowledgeBasedStrategy(RecommendationStrategy): | 242 | class KnowledgeBasedStrategy(RecommendationStrategy): |
| 181 | """ | 243 | """ |