From c8be2ab38ccbb716d2f9edfa1191984972be3825 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Mon, 22 Sep 2014 00:49:05 +0200 Subject: [PATCH 1/4] Added search_raw. --- elasticutils/__init__.py | 27 +++++++++++++++++++++++++++ elasticutils/tests/test_query.py | 5 +++++ 2 files changed, 32 insertions(+) diff --git a/elasticutils/__init__.py b/elasticutils/__init__.py index d755b23..98271fd 100644 --- a/elasticutils/__init__.py +++ b/elasticutils/__init__.py @@ -778,6 +778,27 @@ def query_raw(self, query): """ return self._clone(next_step=('query_raw', query)) + def search_raw(self, search): + """ + Return a new S instance with a search_raw. + + :arg search: Python dict specifying the complete search to send + to Elasticsearch + + Example:: + + S().search_raw({'match': {'title': 'example'}}) + + + .. Note:: + + If there's a search_raw in your S, then that's your + search. All ``.search()``, ``.demote()``, ``.boost()`` and + anything else that affects the search clause is ignored. + + """ + return self._clone(next_step=('search_raw', search)) + def filter(self, *filters, **kw): """ Return a new S instance with filter args combined with @@ -1091,6 +1112,7 @@ def build_search(self): explain = False as_list = as_dict = False search_type = None + search_raw = None for action, value in self.steps: if action == 'order_by': @@ -1118,6 +1140,8 @@ def build_search(self): queries.append(value) elif action == 'query_raw': query_raw = value + elif action == 'search_raw': + search_raw = value elif action == 'demote': # value here is a tuple of (negative_boost, query) demote = value @@ -1148,6 +1172,9 @@ def build_search(self): else: raise NotImplementedError(action) + if search_raw: + return search_raw + qs = {} # If there's a filters_raw, we use that. diff --git a/elasticutils/tests/test_query.py b/elasticutils/tests/test_query.py index a28e64c..d68dabe 100644 --- a/elasticutils/tests/test_query.py +++ b/elasticutils/tests/test_query.py @@ -388,6 +388,11 @@ def test_query_raw(self): eq_(s.build_search(), {'query': {'match': {'title': 'example'}}}) + def test_search_raw(self): + s = self.get_s().search_raw({'query': {'match': {'title': 'example'}}}) + eq_(s.build_search(), + {'query': {'match': {'title': 'example'}}}) + def test_query_raw_overrides_everything(self): s = self.get_s().query_raw({'match': {'title': 'example'}}) s = s.query(foo__match='foo') From a42f34b3465b0ba8de0f04102572445946bbba08 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Mon, 22 Sep 2014 01:21:31 +0200 Subject: [PATCH 2/4] Fixed error with search_type. --- elasticutils/__init__.py | 135 ++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/elasticutils/__init__.py b/elasticutils/__init__.py index 98271fd..173da1d 100644 --- a/elasticutils/__init__.py +++ b/elasticutils/__init__.py @@ -1173,82 +1173,83 @@ def build_search(self): raise NotImplementedError(action) if search_raw: - return search_raw + qs = search_raw - qs = {} - - # If there's a filters_raw, we use that. - if filters_raw: - qs['filter'] = filters_raw else: - if len(filters) > 1: - qs['filter'] = {'and': filters} - elif filters: - qs['filter'] = filters[0] + qs = {} - # If there's a query_raw, we use that. Otherwise we use - # whatever we got from query and demote. - if query_raw: - qs['query'] = query_raw + # If there's a filters_raw, we use that. + if filters_raw: + qs['filter'] = filters_raw + else: + if len(filters) > 1: + qs['filter'] = {'and': filters} + elif filters: + qs['filter'] = filters[0] - else: - pq = self._process_queries(queries) + # If there's a query_raw, we use that. Otherwise we use + # whatever we got from query and demote. + if query_raw: + qs['query'] = query_raw - if demote is not None: - qs['query'] = { - 'boosting': { - 'negative': self._process_queries([demote[1]]), - 'negative_boost': demote[0] + else: + pq = self._process_queries(queries) + + if demote is not None: + qs['query'] = { + 'boosting': { + 'negative': self._process_queries([demote[1]]), + 'negative_boost': demote[0] + } } - } - if pq: - qs['query']['boosting']['positive'] = pq + if pq: + qs['query']['boosting']['positive'] = pq - elif pq: - qs['query'] = pq + elif pq: + qs['query'] = pq - if as_list: - fields = qs['fields'] = list(list_fields) if list_fields else ['*'] - elif as_dict: - fields = qs['fields'] = list(dict_fields) if dict_fields else ['*'] - else: - fields = set() - - if facets: - qs['facets'] = facets - # Hunt for `facet_filter` shells and update those. We use - # None as a shell, so if it's explicitly set to None, then - # we update it. - for facet in facets.values(): - if facet.get('facet_filter', 1) is None and 'filter' in qs: - facet['facet_filter'] = qs['filter'] - - if facets_raw: - qs.setdefault('facets', {}).update(facets_raw) - - if sort: - qs['sort'] = sort - if self.start: - qs['from'] = self.start - if self.stop is not None: - qs['size'] = self.stop - self.start - - if highlight_fields: - qs['highlight'] = self._build_highlight( - highlight_fields, highlight_options) - - if explain: - qs['explain'] = True - - for suggestion, (term, kwargs) in six.iteritems(suggestions): - qs.setdefault('suggest', {})[suggestion] = { - 'text': term, - 'term': { - 'field': kwargs.get('field', '_all'), - }, - } + if as_list: + fields = qs['fields'] = list(list_fields) if list_fields else ['*'] + elif as_dict: + fields = qs['fields'] = list(dict_fields) if dict_fields else ['*'] + else: + fields = set() + + if facets: + qs['facets'] = facets + # Hunt for `facet_filter` shells and update those. We use + # None as a shell, so if it's explicitly set to None, then + # we update it. + for facet in facets.values(): + if facet.get('facet_filter', 1) is None and 'filter' in qs: + facet['facet_filter'] = qs['filter'] + + if facets_raw: + qs.setdefault('facets', {}).update(facets_raw) + + if sort: + qs['sort'] = sort + if self.start: + qs['from'] = self.start + if self.stop is not None: + qs['size'] = self.stop - self.start + + if highlight_fields: + qs['highlight'] = self._build_highlight( + highlight_fields, highlight_options) + + if explain: + qs['explain'] = True + + for suggestion, (term, kwargs) in six.iteritems(suggestions): + qs.setdefault('suggest', {})[suggestion] = { + 'text': term, + 'term': { + 'field': kwargs.get('field', '_all'), + }, + } - self.fields, self.as_list, self.as_dict = fields, as_list, as_dict + self.fields, self.as_list, self.as_dict = fields, as_list, as_dict self.search_type = search_type return qs From 53edcd434e9a56795b8b3c50315643edcec7defe Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Mon, 22 Sep 2014 01:28:05 +0200 Subject: [PATCH 3/4] Fixed AttributeError: 'S' object has no attribute 'fields' --- elasticutils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elasticutils/__init__.py b/elasticutils/__init__.py index 173da1d..0c6d411 100644 --- a/elasticutils/__init__.py +++ b/elasticutils/__init__.py @@ -1174,7 +1174,7 @@ def build_search(self): if search_raw: qs = search_raw - + fields = set() else: qs = {} @@ -1249,7 +1249,7 @@ def build_search(self): }, } - self.fields, self.as_list, self.as_dict = fields, as_list, as_dict + self.fields, self.as_list, self.as_dict = fields, as_list, as_dict self.search_type = search_type return qs From d72775c8e0451e9c45142e2ab106ec7333bd2ed5 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Sun, 28 Sep 2014 00:59:44 +0200 Subject: [PATCH 4/4] Fixed slicing support. --- elasticutils/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/elasticutils/__init__.py b/elasticutils/__init__.py index 9f1676d..b7131db 100644 --- a/elasticutils/__init__.py +++ b/elasticutils/__init__.py @@ -1229,10 +1229,6 @@ def build_search(self): if sort: qs['sort'] = sort - if self.start: - qs['from'] = self.start - if self.stop is not None: - qs['size'] = self.stop - self.start if highlight_fields: qs['highlight'] = self._build_highlight( @@ -1249,6 +1245,11 @@ def build_search(self): }, } + if self.start: + qs['from'] = self.start + if self.stop is not None: + qs['size'] = self.stop - self.start + self.fields, self.as_list, self.as_dict = fields, as_list, as_dict self.search_type = search_type return qs