def build_query(self, sketch_id, query_string, query_filter, query_dsl=None, aggregations=None, timeline_ids=None):
    'Build Elasticsearch DSL query.\n\n        Args:\n            sketch_id: Integer of sketch primary key\n            query_string: Query string\n            query_filter: Dictionary containing filters to apply\n            query_dsl: Dictionary containing Elasticsearch DSL query\n            aggregations: Dict of Elasticsearch aggregations\n            timeline_ids: Optional list of IDs of Timeline objects that should\n                be queried as part of the search.\n\n        Returns:\n            Elasticsearch DSL query as a dictionary\n        '
    if query_dsl:
        if (not isinstance(query_dsl, dict)):
            query_dsl = json.loads(query_dsl)
        if (not query_dsl):
            query_dsl = {}
        return self._build_query_dsl(query_dsl, timeline_ids)
    if query_filter.get('events', None):
        events = query_filter['events']
        return self._build_events_query(events)
    query_dsl = {'query': {'bool': {'must': [], 'must_not': [], 'filter': []}}}
    if query_string:
        query_dsl['query']['bool']['must'].append({'query_string': {'query': query_string}})
    if query_filter.get('chips', None):
        labels = []
        must_filters = query_dsl['query']['bool']['must']
        must_not_filters = query_dsl['query']['bool']['must_not']
        datetime_ranges = {'bool': {'should': [], 'minimum_should_match': 1}}
        for chip in query_filter['chips']:
            if (not chip.get('active', True)):
                continue
            METRICS['search_filter_type'].labels(type=chip['type']).inc()
            if (chip['type'] == 'label'):
                labels.append(chip['value'])
            elif (chip['type'] == 'term'):
                term_filter = {'match_phrase': {'{}'.format(chip['field']): {'query': '{}'.format(chip['value'])}}}
                if (chip['operator'] == 'must'):
                    must_filters.append(term_filter)
                elif (chip['operator'] == 'must_not'):
                    must_not_filters.append(term_filter)
            elif chip['type'].startswith('datetime'):
                range_filter = (lambda start, end: {'range': {'datetime': {'gte': start, 'lte': end}}})
                if (chip['type'] == 'datetime_range'):
                    (start, end) = chip['value'].split(',')
                elif (chip['type'] == 'datetime_interval'):
                    (start, end) = self._convert_to_time_range(chip['value'])
                else:
                    continue
                datetime_ranges['bool']['should'].append(range_filter(start, end))
        label_filter = self._build_labels_query(sketch_id, labels)
        must_filters.append(label_filter)
        must_filters.append(datetime_ranges)
    if query_filter.get('from', None):
        query_dsl['from'] = query_filter['from']
    if query_filter.get('size', None):
        query_dsl['size'] = query_filter['size']
    if (not query_dsl.get('sort', None)):
        query_dsl['sort'] = {'datetime': query_filter.get('order', 'asc')}
    if aggregations:
        if query_dsl.get('post_filter', None):
            query_dsl['query']['bool']['filter'] = query_dsl['post_filter']
            query_dsl.pop('post_filter', None)
        query_dsl['aggregations'] = aggregations
    if (timeline_ids and isinstance(timeline_ids, (list, tuple))):
        must_filters_pre = copy.copy(query_dsl['query']['bool']['must'])
        must_not_filters_pre = copy.copy(query_dsl['query']['bool']['must_not'])
        must_filters_post = copy.copy(query_dsl['query']['bool']['must'])
        must_not_filters_post = copy.copy(query_dsl['query']['bool']['must_not'])
        must_not_filters_pre.append({'exists': {'field': '__ts_timeline_id'}})
        must_filters_post.append({'terms': {'__ts_timeline_id': timeline_ids}})
        query_dsl['query'] = {'bool': {'must': [], 'should': [{'bool': {'must': must_filters_pre, 'must_not': must_not_filters_pre}}, {'bool': {'must': must_filters_post, 'must_not': must_not_filters_post, 'filter': [{'exists': {'field': '__ts_timeline_id'}}]}}], 'must_not': [], 'filter': []}}
    return query_dsl
Build Elasticsearch DSL query.

Args:
    sketch_id: Integer of sketch primary key
    query_string: Query string
    query_filter: Dictionary containing filters to apply
    query_dsl: Dictionary containing Elasticsearch DSL query
    aggregations: Dict of Elasticsearch aggregations
    timeline_ids: Optional list of IDs of Timeline objects that should
        be queried as part of the search.

Returns:
    Elasticsearch DSL query as a dictionary
def build_query(self, sketch_id, query_string, query_filter, query_dsl=None, aggregations=None, timeline_ids=None):
    'Build Elasticsearch DSL query.\n\n        Args:\n            sketch_id: Integer of sketch primary key\n            query_string: Query string\n            query_filter: Dictionary containing filters to apply\n            query_dsl: Dictionary containing Elasticsearch DSL query\n            aggregations: Dict of Elasticsearch aggregations\n            timeline_ids: Optional list of IDs of Timeline objects that should\n                be queried as part of the search.\n\n        Returns:\n            Elasticsearch DSL query as a dictionary\n        '
    if query_dsl:
        if (not isinstance(query_dsl, dict)):
            query_dsl = json.loads(query_dsl)
        if (not query_dsl):
            query_dsl = {}
        return self._build_query_dsl(query_dsl, timeline_ids)
    if query_filter.get('events', None):
        events = query_filter['events']
        return self._build_events_query(events)
    query_dsl = {'query': {'bool': {'must': [], 'must_not': [], 'filter': []}}}
    if query_string:
        query_dsl['query']['bool']['must'].append({'query_string': {'query': query_string}})
    if query_filter.get('chips', None):
        labels = []
        must_filters = query_dsl['query']['bool']['must']
        must_not_filters = query_dsl['query']['bool']['must_not']
        datetime_ranges = {'bool': {'should': [], 'minimum_should_match': 1}}
        for chip in query_filter['chips']:
            if (not chip.get('active', True)):
                continue
            METRICS['search_filter_type'].labels(type=chip['type']).inc()
            if (chip['type'] == 'label'):
                labels.append(chip['value'])
            elif (chip['type'] == 'term'):
                term_filter = {'match_phrase': {'{}'.format(chip['field']): {'query': '{}'.format(chip['value'])}}}
                if (chip['operator'] == 'must'):
                    must_filters.append(term_filter)
                elif (chip['operator'] == 'must_not'):
                    must_not_filters.append(term_filter)
            elif chip['type'].startswith('datetime'):
                range_filter = (lambda start, end: {'range': {'datetime': {'gte': start, 'lte': end}}})
                if (chip['type'] == 'datetime_range'):
                    (start, end) = chip['value'].split(',')
                elif (chip['type'] == 'datetime_interval'):
                    (start, end) = self._convert_to_time_range(chip['value'])
                else:
                    continue
                datetime_ranges['bool']['should'].append(range_filter(start, end))
        label_filter = self._build_labels_query(sketch_id, labels)
        must_filters.append(label_filter)
        must_filters.append(datetime_ranges)
    if query_filter.get('from', None):
        query_dsl['from'] = query_filter['from']
    if query_filter.get('size', None):
        query_dsl['size'] = query_filter['size']
    if (not query_dsl.get('sort', None)):
        query_dsl['sort'] = {'datetime': query_filter.get('order', 'asc')}
    if aggregations:
        if query_dsl.get('post_filter', None):
            query_dsl['query']['bool']['filter'] = query_dsl['post_filter']
            query_dsl.pop('post_filter', None)
        query_dsl['aggregations'] = aggregations
    if (timeline_ids and isinstance(timeline_ids, (list, tuple))):
        must_filters_pre = copy.copy(query_dsl['query']['bool']['must'])
        must_not_filters_pre = copy.copy(query_dsl['query']['bool']['must_not'])
        must_filters_post = copy.copy(query_dsl['query']['bool']['must'])
        must_not_filters_post = copy.copy(query_dsl['query']['bool']['must_not'])
        must_not_filters_pre.append({'exists': {'field': '__ts_timeline_id'}})
        must_filters_post.append({'terms': {'__ts_timeline_id': timeline_ids}})
        query_dsl['query'] = {'bool': {'must': [], 'should': [{'bool': {'must': must_filters_pre, 'must_not': must_not_filters_pre}}, {'bool': {'must': must_filters_post, 'must_not': must_not_filters_post, 'filter': [{'exists': {'field': '__ts_timeline_id'}}]}}], 'must_not': [], 'filter': []}}
    return query_dsl