Skip to content
This repository has been archived by the owner on Feb 20, 2019. It is now read-only.

Raw search #264

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 89 additions & 60 deletions elasticutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1148,79 +1172,84 @@ def build_search(self):
else:
raise NotImplementedError(action)

qs = {}

# If there's a filters_raw, we use that.
if filters_raw:
qs['filter'] = filters_raw
if search_raw:
qs = search_raw
fields = set()
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

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 pq:
qs['query']['boosting']['positive'] = pq

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']
elif pq:
qs['query'] = pq

if facets_raw:
qs.setdefault('facets', {}).update(facets_raw)
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 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 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.search_type = search_type
return qs
Expand Down
5 changes: 5 additions & 0 deletions elasticutils/tests/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down