From 3d62575e4e16d9db9e71ed418009181613f91169 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Tue, 2 Sep 2014 17:13:59 +0200 Subject: [PATCH 1/2] Added minimum_should_match support to terms query. --- docs/searching.rst | 6 +++++- elasticutils/__init__.py | 33 +++++++++++++++++++++++++++----- elasticutils/tests/test_query.py | 11 +++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/docs/searching.rst b/docs/searching.rst index a54ee37..602782c 100644 --- a/docs/searching.rst +++ b/docs/searching.rst @@ -307,7 +307,7 @@ field action Elasticsearch query type ====================== ================================ (no action specified) Term query term Term query -terms Terms query +terms Terms query [5]_ in Terms query text Text query (`DEPRECATED`) match Match query [1]_ @@ -336,6 +336,10 @@ query_string Querystring query [3]_ the range at once. The range is inclusive on both sides and accepts a tuple with the lower value first and upper value second. +.. [5] The ``terms`` field action support also the ``minimum_should_match`` + parameter. If you pass a two elements list and the first element + is a list, the second element is treated as minimum_should_match. + .. seealso:: diff --git a/elasticutils/__init__.py b/elasticutils/__init__.py index e049e30..a0c1657 100644 --- a/elasticutils/__init__.py +++ b/elasticutils/__init__.py @@ -41,7 +41,6 @@ None: 'term', # Default to term 'in': 'in', 'term': 'term', - 'terms': 'terms', 'prefix': 'prefix', 'match': 'match', 'match_phrase': 'match_phrase', @@ -393,15 +392,20 @@ def __eq__(self, other): and sorted(self.must_not_q) == sorted(other.must_not_q)) -def _boosted_value(name, action, key, value, boost): +def _boosted_value(name, action, key, value, boost, extra={}): """Boost a value if we should in _process_queries""" if boost is not None: # Note: Most queries use 'value' for the key name except # Match queries which use 'query'. So we have to do some # switcheroo for that. value_key = 'query' if action in MATCH_ACTIONS else 'value' - return {name: {'boost': boost, value_key: value}} - return {name: value} + q = {name: {'boost': boost, value_key: value}} + else: + q = {name: value} + + q.update(extra) + + return q class PythonMixin(object): @@ -1343,7 +1347,26 @@ def _process_query(self, query): return { 'range': {field_name: _boosted_value( field_action, field_action, key, val, boost)} - } + } + + elif field_action == 'terms': + minimum_should_match = 1 + + if len(val) == 2 and isinstance(val[0], (tuple, list)): + minimum_should_match = val[1] + val = val[0] + + value = { + 'terms': _boosted_value( + field_name, field_action, key, val, boost + ) + } + + if minimum_should_match > 1: + value['terms']['minimum_should_match'] = minimum_should_match + + return value + elif field_action == 'range': lower, upper = val diff --git a/elasticutils/tests/test_query.py b/elasticutils/tests/test_query.py index 23e4347..0524464 100644 --- a/elasticutils/tests/test_query.py +++ b/elasticutils/tests/test_query.py @@ -190,6 +190,7 @@ class QueryTest(ESTestCase): 'id': 1, 'foo': 'bar', 'tag': 'awesome', + 'attributes': ['awesome', 'boring'], 'width': '2', 'height': 7 }, @@ -197,6 +198,7 @@ class QueryTest(ESTestCase): 'id': 2, 'foo': 'bart', 'tag': 'boring', + 'attributes': ['awesome', 'car'], 'width': '7', 'height': 11 }, @@ -204,6 +206,7 @@ class QueryTest(ESTestCase): 'id': 3, 'foo': 'car', 'tag': 'awesome', + 'attributes': ['awesome', 'duck'], 'width': '5', 'height': 5 }, @@ -211,6 +214,7 @@ class QueryTest(ESTestCase): 'id': 4, 'foo': 'duck', 'tag': 'boat', + 'attributes': ['train', 'boat'], 'width': '11', 'height': 7 }, @@ -218,6 +222,7 @@ class QueryTest(ESTestCase): 'id': 5, 'foo': 'train car', 'tag': 'awesome', + 'attributes': ['car', 'boring'], 'width': '7', 'height': 2 } @@ -245,6 +250,12 @@ def test_q_terms(self): eq_(len(self.get_s().query(Q(foo__terms=['car', 'duck']))), 3) + # minumum should match support + + eq_(len(self.get_s().query(attributes__terms=(['awesome', 'boring'], 2))), 1) + + eq_(len(self.get_s().query(Q(attributes__terms=(['awesome', 'boring'], 2)))), 1) + def test_q_in(self): eq_(len(self.get_s().query(foo__in=['car', 'bar'])), 3) From a65442987695bfd736075f192c96807377fc0c47 Mon Sep 17 00:00:00 2001 From: Patrick Arminio Date: Tue, 2 Sep 2014 17:31:34 +0200 Subject: [PATCH 2/2] Removed unused changes. --- elasticutils/__init__.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/elasticutils/__init__.py b/elasticutils/__init__.py index a0c1657..9318b85 100644 --- a/elasticutils/__init__.py +++ b/elasticutils/__init__.py @@ -392,20 +392,15 @@ def __eq__(self, other): and sorted(self.must_not_q) == sorted(other.must_not_q)) -def _boosted_value(name, action, key, value, boost, extra={}): +def _boosted_value(name, action, key, value, boost): """Boost a value if we should in _process_queries""" if boost is not None: # Note: Most queries use 'value' for the key name except # Match queries which use 'query'. So we have to do some # switcheroo for that. value_key = 'query' if action in MATCH_ACTIONS else 'value' - q = {name: {'boost': boost, value_key: value}} - else: - q = {name: value} - - q.update(extra) - - return q + return {name: {'boost': boost, value_key: value}} + return {name: value} class PythonMixin(object):