def name_has_prefix(name, prefix): prefixes = prefix.split() for name_part in search_namify(name).split(): check_prefixes = prefixes for prefix in check_prefixes: if name_part.startswith(prefix): prefixes.remove(prefix) if len(prefixes) == 0: return True break return False
def autocomplete(cls, prefix): prefix = prefix.lower().strip() # Go into memory and grab all (some?) of the caches for this # prefix and earlier cache_list = [SetQueryCache.fetch(cls.COMPLETE %prefix[:i+1]) for i in range(len(prefix))] best_data = set() for prelen, cached_query in enumerate(cache_list): if len(cached_query) > 0: best_data = cached_query.results else: best_data = set( filter(lambda an: ArtistName.name_has_prefix(an, prefix[:prelen+1]), best_data)) cached_query.set(best_data) cached_query.save() cached = cache_list.pop() # Get the cache for the relevant prefix if cached.need_fetch(cls.AC_FETCH_NUM): # We have to fetch some keys from the datastore if cached.cursor is None: cached.cursor = {'lower': None, 'search': None} # Prep the queries lower_query = RawArtistName.query().filter( ndb.AND(RawArtistName.lowercase_name >= prefix, RawArtistName.lowercase_name < (prefix + u"\ufffd"))) search_query = RawArtistName.query().filter( ndb.AND(RawArtistName.search_name >= prefix, RawArtistName.search_name < (prefix + u"\ufffd"))) try: # Try to continue an older query num = cls.AC_FETCH_NUM - len(cached) lower_raw_artists, lower_cursor, l_more = lower_query.fetch_page( num, start_cursor=cached.cursor['lower'], projection=[RawArtistName.artist_name]) search_raw_artists, search_cursor, s_more = search_query.fetch_page( num, start_cursor=cached.cursor['search'], projection=[RawArtistName.artist_name]) cache_results = cached.results except db.BadRequestError: # Unable to continue the older query. Run a new one. lower_raw_artists, lower_cursor, l_more = lower_query.fetch_page( num, projection=[RawArtistName.artist_name]) search_raw_artists, search_cursor, s_more = search_query.fetch_page( num, projection=[RawArtistName.artist_name]) cache_results = set() add_artists = (set(a.artist_name for a in search_raw_artists) | set(a.artist_name for a in lower_raw_artists)) artist_names = cached.results | add_artists # We've got a bunch of artistnames for this prefix, so let's # update all of our cached queries: this one, and all supqueries cached.extend_by(add_artists, {'lower': lower_cursor, 'search': search_cursor}, l_more or s_more) cached.save() for cached_query in reversed(cache_list): cached_query.extend(add_artists) cached_query.save() else: # We don't have to fetch anything! artist_names = cached.results return sorted(artist_names, key=lambda x: search_namify(x))