def test_q_basic_add(self): """Adding one Q to another Q combines them.""" q = Q(foo__text='abc') + Q(bar__text='def') eq_(sorted(q.should_q), []) eq_(sorted(q.must_q), [('bar__text', 'def'), ('foo__text', 'abc')]) eq_(sorted(q.must_not_q), [])
def test_q_fuzzy(self): # Mispelled word gets no results with text query. eq_(len(self.get_s().query(foo__text='tran')), 0) eq_(len(self.get_s().query(Q(foo__text='tran'))), 0) # Mispelled word gets one result with fuzzy query. eq_(len(self.get_s().query(foo__fuzzy='tran')), 1) eq_(len(self.get_s().query(Q(foo__fuzzy='tran'))), 1)
def test_q_range(self): eq_(len(self.get_s().query(height__gt=10)), 1) eq_(len(self.get_s().query(height__gte=7)), 3) eq_(len(self.get_s().query(height__lt=10)), 4) eq_(len(self.get_s().query(height__lte=7)), 4) eq_(len(self.get_s().query(Q(height__gt=10))), 1) eq_(len(self.get_s().query(Q(height__gte=7))), 3) eq_(len(self.get_s().query(Q(height__lt=10))), 4) eq_(len(self.get_s().query(Q(height__lte=7))), 4)
def test_q_query_string(self): eq_(len(self.get_s().query(foo__query_string='car AND train')), 1) eq_(len(self.get_s().query(foo__query_string='car OR duck')), 3) eq_(len(self.get_s().query(Q(foo__query_string='car AND train'))), 1) eq_(len(self.get_s().query(Q(foo__query_string='car OR duck'))), 3) # You can query against different fields with the query_string. eq_(len(self.get_s().query(foo__query_string='tag:boat OR car')), 3) eq_(len(self.get_s().query(Q(foo__query_string='tag:boat OR car'))), 3)
def test_q_range_action(self): eq_(len(self.get_s().query(height__range=(10, 20))), 1) eq_(len(self.get_s().query(height__range=(0, 7))), 4) eq_(len(self.get_s().query(height__range=(5, 7))), 3) eq_(len(self.get_s().query(Q(height__range=(10, 20)))), 1) eq_(len(self.get_s().query(Q(height__range=(0, 7)))), 4) eq_(len(self.get_s().query(Q(height__range=(5, 7)))), 3) # Try a boosted query to verify it still works. eq_(len(self.get_s().query(height__range=(5, 7)) .boost(height__range=100)), 3)
def test_q_mixed(self): q1 = Q(foo__text='should', bar__text='should', should=True) q2 = Q(baz='must') q3 = Q(bat='must_not', must_not=True) q4 = Q(ban='must', must=True) q5 = Q(bam='must', must=True) q_all = q1 + q2 + q3 + q4 + q5 eq_(sorted(q_all.should_q), [('bar__text', 'should'), ('foo__text', 'should')]) eq_(sorted(q_all.must_q), [('bam', 'must'), ('ban', 'must'), ('baz', 'must')]) eq_(sorted(q_all.must_not_q), [('bat', 'must_not')])
def test_q_match_phrase(self): # Doing a match query for the two words in either order kicks up # two results. eq_(len(self.get_s().query(foo__match='train car')), 2) eq_(len(self.get_s().query(foo__match='car train')), 2) eq_(len(self.get_s().query(Q(foo__match='train car'))), 2) eq_(len(self.get_s().query(Q(foo__match='car train'))), 2) # Doing a match_phrase query for the two words in the right # order kicks up one result. eq_(len(self.get_s().query(foo__match_phrase='train car')), 1) eq_(len(self.get_s().query(Q(foo__match_phrase='train car'))), 1) # Doing a match_phrase query for the two words in the wrong # order kicks up no results. eq_(len(self.get_s().query(foo__match_phrase='car train')), 0) eq_(len(self.get_s().query(Q(foo__match_phrase='car train'))), 0)
def test_q_order(self): q1 = Q(foo__text='abc') + Q(bar__text='def') q2 = Q(bar__text='def') + Q(foo__text='abc') eq_(q1, q2) q2 = Q(bar__text='def') q2 += Q(foo__text='abc') eq_(q1, q2) q2 = Q(foo__text='abc') q2 += Q(bar__text='def') eq_(q1, q2)
def test_q_demote(self): s = self.get_s().query(foo__text='car') scores = [(sr['id'], sr._score) for sr in s.values_dict('id')] s = s.demote(0.5, width__term='5') demoted_scores = [(sr['id'], sr._score) for sr in s.values_dict('id')] # These are both sorted by scores. We're demoting one result # so the top result in each list is different. assert scores[0] != demoted_scores # Now we do the whole thing again with Qs. s = self.get_s().query(Q(foo__text='car')) scores = [(sr['id'], sr._score) for sr in s.values_dict('id')] s = s.demote(0.5, Q(width__term='5')) demoted_scores = [(sr['id'], sr._score) for sr in s.values_dict('id')] # These are both sorted by scores. We're demoting one result # so the top result in each list is different. assert scores[0] != demoted_scores
def filter_queryset(self, request, queryset, view): search_param = request.QUERY_PARAMS.get(self.search_param, None) if search_param: queries = {} boosts = {} for operation, boost in self.search_operations: queries[operation] = search_param boosts[operation] = boost queryset = (queryset.query(Q(should=True, **queries)).boost(**boosts)) if flag_is_active(request, 'search_explanation'): queryset = queryset.explain() # adds scoring explaination return queryset
def filter_queryset(self, request, queryset, view): queries = {} boosts = {} for name in self.search_params: search_param = request.QUERY_PARAMS.get(name, None) if not search_param: continue for operation_tmpl, boost in self.search_operations: operation = operation_tmpl % name queries[operation] = search_param.lower() boosts[operation] = boost queryset = (queryset.query(Q(should=True, **queries)).boost(**boosts)) return queryset
def test_boost(self): """Boosted queries shouldn't raise a SearchPhaseExecutionException.""" q1 = (self.get_s() .boost(foo=4.0) .query(foo='car', foo__text='car', foo__text_phrase='car')) # Make sure the query executes without throwing an exception. list(q1) # Verify it's producing the correct query. eq_(q1._build_query(), { 'query': { 'bool': { 'must': [ {'text_phrase': {'foo': {'query': 'car', 'boost': 4.0}}}, {'term': {'foo': {'value': 'car', 'boost': 4.0}}}, {'text': {'foo': {'query': 'car', 'boost': 4.0}}} ] } } }) # Do the same thing with Qs. q1 = (self.get_s() .boost(foo=4.0) .query(Q(foo='car', foo__text='car', foo__text_phrase='car'))) # Make sure the query executes without throwing an exception. list(q1) # Verify it's producing the correct query. eq_(q1._build_query(), { 'query': { 'bool': { 'must': [ {'text_phrase': {'foo': {'query': 'car', 'boost': 4.0}}}, {'term': {'foo': {'value': 'car', 'boost': 4.0}}}, {'text': {'foo': {'query': 'car', 'boost': 4.0}}} ] } } })
def test_q_must_should(self): with self.assertRaises(InvalidFlagsError): Q(foo__text='abc', must=True, should=True)
def test_q_must_not(self): q = Q(foo__text='abc', bar__text='def', must_not=True) eq_(sorted(q.should_q), []) eq_(sorted(q.must_q), []) eq_(sorted(q.must_not_q), [('bar__text', 'def'), ('foo__text', 'abc')])
def test_boolean_query_compled(self): """Verify that should/must/must_not collapses right""" s = self.get_s() eq_((s.query(Q(foo='should', should=True), bar='must') ._build_query()), { 'query': { 'bool': { 'should': [ {'term': {'foo': 'should'}} ], 'must': [ {'term': {'bar': 'must'}} ] } } }) eq_((s.query(Q(foo='should', should=True), bar='must_not', must_not=True) ._build_query()), { 'query': { 'bool': { 'should': [ {'term': {'foo': 'should'}} ], 'must_not': [ {'term': {'bar': 'must_not'}} ] } } }) eq_((s.query(Q(foo='should', should=True), bar='must_not', must_not=True) .query(Q(baz='must')) ._build_query()), { 'query': { 'bool': { 'should': [ {'term': {'foo': 'should'}}, ], 'must_not': [ {'term': {'bar': 'must_not'}} ], 'must': [ {'term': {'baz': 'must'}} ] } } }) # This is a pathological case. The should=True applies to the # foo term query and the must=True doesn't apply to # anything--it shouldn't override the should=True in the Q. eq_((s.query(Q(foo='should', should=True), must=True) ._build_query()), { 'query': { 'bool': { 'should': [ {'term': {'foo': 'should'}} ] } } })
def test_q_bad_field_action(self): with self.assertRaises(InvalidFieldActionError): len(self.get_s().query(foo__foo='awesome')) with self.assertRaises(InvalidFieldActionError): len(self.get_s().query(Q(foo__foo='awesome')))
def test_q_terms(self): eq_(len(self.get_s().query(foo__terms=['car', 'duck'])), 3) eq_(len(self.get_s().query(Q(foo__terms=['car', 'duck']))), 3)
def test_q_wildcard(self): eq_(len(self.get_s().query(foo__wildcard='tra*n')), 1) eq_(len(self.get_s().query(foo__wildcard='tra?n')), 1) eq_(len(self.get_s().query(Q(foo__wildcard='tra*n'))), 1) eq_(len(self.get_s().query(Q(foo__wildcard='tra?n'))), 1)
def test_q(self): eq_(len(self.get_s().query(foo='bar')), 1) eq_(len(self.get_s().query(foo='car')), 2) eq_(len(self.get_s().query(Q(foo='bar'))), 1) eq_(len(self.get_s().query(Q(foo='car'))), 2)
def cookbooth_search(cls, search_str, fields=None, hide_for_sale=False): search_str = search_str.lower() if search_str else "" fields = fields or [] q = Q() if hide_for_sale: q += Q(forSale=False) if not fields or ('recipe' in fields and 'chef' in fields and 'book' in fields and 'ingredient' in fields): q += Q(name__query_string=search_str, should=True) q += Q(tagNames__query_string=search_str, should=True) q += Q(chefName__query_string=search_str, should=True) q += Q(bookNames__query_string=search_str, should=True) q += Q(ingredientNames__query_string=search_str, should=True) else: if 'recipe' in fields: q += Q(name__query_string=search_str, should=True) q += Q(tagNames__query_string=search_str, should=True) if 'chef' in fields: q += Q(chefName__query_string=search_str, should=True) if 'book' in fields: q += Q(bookNames__query_string=search_str, should=True) q += Q(tagNames__query_string=search_str, should=True) if 'ingredient' in fields: q += Q(ingredientNames__query_string=search_str, should=True) q += Q(tagNames__query_string=search_str, should=True) searcher = cls.search() searcher = searcher.boost(name=8.0, chefName=4.0, ingredientNames=6.0) qry = searcher.query(q)[:240] return qry
def test_q_prefix(self): eq_(len(self.get_s().query(foo__prefix='ca')), 2) eq_(len(self.get_s().query(foo__startswith='ca')), 2) eq_(len(self.get_s().query(Q(foo__prefix='ca'))), 2) eq_(len(self.get_s().query(Q(foo__startswith='ca'))), 2)
def test_q_match(self): eq_(len(self.get_s().query(foo__match='car')), 2) eq_(len(self.get_s().query(Q(foo__match='car'))), 2)
def test_q_text(self): eq_(len(self.get_s().query(foo__text='car')), 2) eq_(len(self.get_s().query(Q(foo__text='car'))), 2)
def cookbooth_search(cls, search_str): search_str = '*%s*' % search_str q = Q(_all__query_string=search_str, should=True) searcher = cls.search() return searcher.query(q)
def test_q_in(self): eq_(len(self.get_s().query(foo__in=['car', 'bar'])), 3) eq_(len(self.get_s().query(Q(foo__in=['car', 'bar']))), 3)