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.

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