def recommendations_from_seed(database, rule_index, seed_song): # Find rules, that affect this seed_song: associated = list(rule_index.lookup(seed_song)) # No rules? Just use the seed_song as starting point... # One day, we will have rules. Shortcut for now. if not associated: bfs = sorted_breadth_first_search(seed_song) # Throw away first song: next(bfs) for recom in bfs: yield recom else: # Create an iterator for each seed_song, in each associated rule: breadth_first_iters = deque() # Now populate the list of breadth first iterators: for left, right, *_ in associated: # The maximum number that a single seed_song in this rule may # deliver (at least 1 - himself, therefore the ceil) bulk = right if seed_song in left else left # We take the songs in the opposite set of the rule: for bulk_song in bulk: breadth_first = sorted_breadth_first_search(bulk_song) breadth_first_iters.append(breadth_first) # The result set will be build by half base_half = sorted_breadth_first_search(seed_song) try: next(base_half) except StopIteration: pass # Yield the base half first: songs_set = set([seed_song]) # Now build the final result set by filling one half original songs, # and one half songs that were pointed to by rules. for recom in roundrobin(base_half, roundrobin(*breadth_first_iters)): # We have this already in the result set: if recom in songs_set: continue else: songs_set.add(recom) yield recom
def recommendations_from_attributes(subset, database, rule_index, max_seeds=10, max_numeric_offset=None): chosen_songs = list( islice(database.find_matching_attributes(subset, max_numeric_offset), max_seeds)) if not chosen_songs: return [] seed_iterables = [ recommendations_from_seed(database, rule_index, song) for song in chosen_songs ] return chain(chosen_songs, roundrobin(*seed_iterables))
def recommendations_from_attributes( subset, database, rule_index, max_seeds=10, max_numeric_offset=None ): chosen_songs = list(islice( database.find_matching_attributes(subset, max_numeric_offset), max_seeds )) if not chosen_songs: return [] seed_iterables = [ recommendations_from_seed(database, rule_index, song) for song in chosen_songs ] return chain( chosen_songs, roundrobin(*seed_iterables) )