code: def search(self, phrase, limit=None, boosts=None, chunk_size=1000):
          
          cleaned = self.tokenize_title(phrase, stopwords=False)
          if not cleaned:
              return
  
          all_boosts = self._load_saved_boosts()
          if PY3 and boosts:
              for key in boosts:
                  all_boosts[encode(key)] = boosts[key]
          elif boosts:
              all_boosts.update(boosts)
  
          if len(cleaned) == 1 and not all_boosts:
              result_key = self.word_key(cleaned[0])
          else:
              result_key = self.get_cache_key(cleaned, all_boosts)
              if result_key not in self.database:
                  self.database.zinterstore(
                      result_key,
                      list(map(self.word_key, cleaned)))
              self.database.expire(result_key, self._cache_timeout)
  
          results = self.database.ZSet(result_key)
          if all_boosts:
              for raw_id, score in results[0:0, True]:
                  orig_score = score
                  for identifier in raw_id.split(encode('\x01'), 1):
                      if identifier and identifier in all_boosts:
                          score *= 1 / all_boosts[identifier]
  
                  if orig_score != score:
                      results[raw_id] = score
  
          for result in self._load_objects(results, limit, chunk_size):
              yield result
docs: Perform a search for the given phrase. Objects whose title
          matches the search will be returned. The values returned
          will be whatever you specified as the ``data`` parameter
          when you called :py:meth:`~Autocomplete.store`.
  
          :param phrase: One or more words or substrings.
          :param int limit: Limit size of the result set.
          :param dict boosts: A mapping of object id/object type to
              floating point multipliers.
          :returns: A list containing the object data for objects
              matching the search phrase.