<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def search(self, *arg, **kw):
 """A full search function. This allows you to search expression using the following arguments. Arg: query (str):
 The search string expression. Optional Args: - include_entity (bool):
 include in each result the entity values associated of the fields stored. - add_wildcards (bool):
 set it if you want to consider matches that have prefix or suffixes the query. - something (bool):
 set `add_willcards` in case of none results for the query. - fields (list):
 specified the fields names that you want to consider. - except_fields (list):
 specified the fields names to not consider in the search. - models (list):
 a list of name of model to search or even the models from the database. Returns: (dict):
 A python dictionary with the results. """

    output = {
        'cant_results'  : 0
      , 'matched_terms' : defaultdict(set)
      , 'results'       : {}
      , 'runtime'       : 0
    }

    indexes = self.indexes()

    models = kw.get('models', list(self._entities.values()))
    if sys.version_info[0] < 3:
      models = [self._entities.get(model, None) if isinstance(model, str)
        or isinstance(model, unicode) else model for model in models]
      models = filter(lambda x: x is not None, models)
    else:
      models = [self._entities.get(model, None) if isinstance(model, str)
        or isinstance(model, str) else model for model in models]
      models = [x for x in models if x is not None]


    if models == [] or not models:
      models = list(self._entities.values())

    if self.debug:
      print("SEARCHING ON MODELS -> ", models)

    indexes = [m._pw_index_ for m in models if hasattr(m, '_pw_index_')]

    if indexes == []:
      return output

    runtime, cant = 0, 0
    ma            = defaultdict(set)

    for index in indexes:
      res     = index.search(*arg, **kw)
      runtime += res['runtime']
      cant    += res['cant_results']
      if res['cant_results'] > 0:
        output['results'][index._name] = {
            'items'         : res['results']
          , 'matched_terms' : res['matched_terms']
        }
        for k, ts in list(res['matched_terms'].items()):
          for t in ts:
            ma[k].add(t)

    output['cant_results']  = cant
    output['matched_terms'] = {k: list(v) for k, v in list(ma.items())}
    output['runtime']       = runtime
    return output