<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def parse_query(query_str):
 """ Drives the whole logic, by parsing, restructuring and finally, generating an ElasticSearch query. Args: query_str (six.text_types):
 the given query to be translated to an ElasticSearch query Returns: six.text_types: Return an ElasticSearch query. Notes: In case there's an error, an ElasticSearch `multi_match` query is generated with its `query` value, being the query_str argument. """

    def _generate_match_all_fields_query():
        # Strip colon character (special character for ES)
        stripped_query_str = ' '.join(query_str.replace(':', ' ').split())
        return {'multi_match': {'query': stripped_query_str, 'fields': ['_all'], 'zero_terms_query': 'all'}}

    if not isinstance(query_str, six.text_type):
        query_str = six.text_type(query_str.decode('utf-8'))

    logger.info('Parsing: "' + query_str + '\".')

    parser = StatefulParser()
    rst_visitor = RestructuringVisitor()
    es_visitor = ElasticSearchVisitor()

    try:
        unrecognized_text, parse_tree = parser.parse(query_str, Query)

        if unrecognized_text:  # Usually, should never happen.
            msg = 'Parser returned unrecognized text: "' + unrecognized_text + \
                  '" for query: "' + query_str + '".'

            if query_str == unrecognized_text and parse_tree is None:
                # Didn't recognize anything.
                logger.warn(msg)
                return _generate_match_all_fields_query()
            else:
                msg += 'Continuing with recognized parse tree.'
            logger.warn(msg)

    except SyntaxError as e:
        logger.warn('Parser syntax error (' + six.text_type(e) + ') with query: "' + query_str +
                    '". Continuing with a match_all with the given query.')
        return _generate_match_all_fields_query()

    # Try-Catch-all exceptions for visitors, so that search functionality never fails for the user.
    try:
        restructured_parse_tree = parse_tree.accept(rst_visitor)
        logger.debug('Parse tree: \n' + emit_tree_format(restructured_parse_tree))

    except Exception as e:
        logger.exception(
            RestructuringVisitor.__name__ + " crashed" + (": " + six.text_type(e) + ".") if six.text_type(e) else '.'
        )
        return _generate_match_all_fields_query()

    try:
        es_query = restructured_parse_tree.accept(es_visitor)
    except Exception as e:
        logger.exception(
            ElasticSearchVisitor.__name__ + " crashed" + (": " + six.text_type(e) + ".") if six.text_type(e) else '.'
        )
        return _generate_match_all_fields_query()

    if not es_query:
        # Case where an empty query was generated (i.e. date query with malformed date, e.g. "d < 200").
        return _generate_match_all_fields_query()

    return es_query