def test_query_clone(): bool = query.Bool(must=[query.Match(x=42)], should=[query.Match(g="v2")], must_not=[query.Match(title='value')]) bool_clone = bool._clone() assert bool == bool_clone assert bool is not bool_clone assert bool.must[0] is not bool_clone.must[0]
def test_two_queries_make_a_bool(): q1 = query.Match(f='value1') q2 = query.Match(message={"query": "this is a test", "opeartor": "and"}) q = q1 & q2 assert isinstance(q, query.Bool) assert [q1, q2] == q.must
def test_query_and_query_creates_bool(): q1 = query.Match(f=42) q2 = query.Match(g=47) q = q1 & q2 assert isinstance(q, query.Bool) assert q.must == [q1, q2]
def test_or_bool_doesnt_loop_infinitely_issue_96(): q = ~query.Match(f=42) | ~query.Match(f=47) assert q == query.Bool(should=[ query.Bool(must_not=[query.Match(f=42)]), query.Bool(must_not=[query.Match(f=47)]) ])
def secondary_should_rules(self, search_query, analyzer): """Return "secondary" should rules for the query. These are the ones using the weakest boosts, they are applied to fields containing more text like description, summary and tags. """ should = [ query.Match(summary={'query': search_query, 'boost': 0.8, 'type': 'phrase'}), query.Match(description={'query': search_query, 'boost': 0.3, 'type': 'phrase'}), query.Match(tags={'query': search_query.split(), 'boost': 0.1}), ] # For description and summary, also search in translated field with the # right language and analyzer. if analyzer: should.extend([ query.Match(**{'summary_%s' % analyzer: { 'query': search_query, 'boost': 0.6, 'type': 'phrase', 'analyzer': analyzer}}), query.Match(**{'description_%s' % analyzer: { 'query': search_query, 'boost': 0.6, 'type': 'phrase', 'analyzer': analyzer}}) ]) return should
def test_current_locale_results(self): self.refresh() results = (WikiDocumentType.search().query( query.Match(title='article') | query.Match(content='article')).filter('term', locale='en-US')) for doc in results.execute(): eq_('en-US', doc.locale)
def test_bool_query_gets_inverted_internally(): q = query.Bool(must_not=[query.Match(f=42)], must=[query.Match(g='v')]) assert ~q == query.Bool(should=[ # negating must query.Bool(must_not=[query.Match(g='v')]), # negating must_not query.Match(f=42), ])
def test_current_locale_results(self): self.refresh() results = ( WikiDocumentType.search() .query(query.Match(title="article") | query.Match(content="article")) .filter("term", locale="en-US") ) for doc in results.execute(): assert "en-US" == doc.locale
def test_bool_will_append_another_query_with_or(): qb = query.Bool(should=[ query.Match(f='v'), query.Match(f='v2'), ]) q = query.Match(g=42) assert (q | qb) == query.Bool( should=[query.Match(f='v'), query.Match(f='v2'), q])
def test_search_query_combines_query(): s = search.Search() s2 = s.query('match', f=42) assert s2.query._proxied == query.Match(f=42) assert s.query._proxied is None s3 = s2.query('match', f=43) assert s2.query._proxied == query.Match(f=42) assert s3.query._proxied == query.Bool(must=[query.Match(f=42), query.Match(f=43)])
def test_bool_and_bool(): qt1, qt2, qt3 = query.Match(f=1), query.Match(f=2), query.Match(f=3) q1 = query.Bool(must=[qt1], should=[qt2]) q2 = query.Bool(must_not=[qt3]) assert q1 & q2 == query.Bool(must=[qt1], must_not=[qt3], should=[qt2]) q1 = query.Bool(must=[qt1], should=[qt1, qt2]) q2 = query.Bool(should=[qt3]) assert q1 & q2 == query.Bool(must=[qt1], should=[query.Bool(should=[qt1, qt2]), qt3])
def test_two_bools_are_combined(): q1 = query.Bool(must=[query.MatchAll(), query.Match(f=42)], should=[query.Match(g="v")]) q2 = query.Bool(must=[query.Match(x=42)], should=[query.Match(g="v2")], must_not=[query.Match(title='value')]) q = q1 + q2 assert isinstance(q, query.Bool) assert q.must == [query.MatchAll(), query.Match(f=42), query.Match(x=42)] assert q.should == [query.Match(g="v"), query.Match(g="v2")] assert q.must_not == [query.Match(title='value')]
def test_bool_queries_with_only_should_get_concatenated(): q1 = query.Bool(should=[query.Match(f=1), query.Match(f=2)]) q2 = query.Bool(should=[query.Match(f=3), query.Match(f=4)]) assert (q1 | q2) == query.Bool( should=[query.Match(f=1), query.Match(f=2), query.Match(f=3), query.Match(f=4)] )
def departments_query(search_term: str) -> Q.Query: """ Returns the ONS departments query :param search_term: :return: """ return Q.Match(**{"terms": {"query": search_term, "type": "boolean"}})
def test_other_and_bool_appends_other_to_must(): q1 = query.Match(f='value1') qb = query.Bool() q = q1 & qb assert q is not qb assert q.must[0] == q1
def test_match_to_dict_extra(): assert { "match": { "f": "value", "boost": 2 } } == query.Match(f='value', boost=2).to_dict()
def test_bool_and_other_appends_other_to_must(): q1 = query.Match(f="value1") qb = query.Bool() q = qb & q1 assert q is not qb assert q.must[0] == q1
def primary_should_rules(self, search_query, analyzer): """Return "primary" should rules for the query. These are the ones using the strongest boosts, so they are only applied to a specific set of fields like the name, the slug and authors. Applied rules: * Prefer phrase matches that allows swapped terms (boost=4) * Then text matches, using the standard text analyzer (boost=3) * Then text matches, using a language specific analyzer (boost=2.5) * Then try fuzzy matches ("fire bug" => firebug) (boost=2) * Then look for the query as a prefix of a name (boost=1.5) """ should = [] rules = [ (query.MatchPhrase, { 'query': search_query, 'boost': 4, 'slop': 1}), (query.Match, { 'query': search_query, 'boost': 3, 'analyzer': 'standard'}), (query.Match, { 'query': search_query, 'boost': 2, 'prefix_length': 4, 'fuzziness': 'AUTO'}), (query.Prefix, { 'value': search_query, 'boost': 1.5}), ] # Apply rules to search on few base fields. Some might not be present # in every document type / indexes. for query_cls, opts in rules: for field in ('name', 'slug', 'listed_authors.name'): should.append(query_cls(**{field: opts})) # Exact matches need to be queried against a non-analyzed field. Let's # do a term query on `name.raw` for an exact match against the add-on # name and boost it since this is likely what the user wants. # Use a super-high boost to avoid `description` or `summary` # getting in our way. should.append(query.Term(**{ 'name.raw': { 'value': search_query, 'boost': 100 } })) # For name, also search in translated field with the right language # and analyzer. if analyzer: should.append( query.Match(**{ 'name_l10n_%s' % analyzer: { 'query': search_query, 'boost': 2.5, 'analyzer': analyzer } }) ) return should
def test_bool_and_other_appends_other_to_must(): q1 = query.Match(f='value1') qb = query.Bool() q = qb & q1 print(repr(q)) assert q is not qb assert q.must[0] == q1
def search_author(request): """ returns a list of authors depending on the search query request needs to have 'query':str field """ query = request.query_params.get('query', None) if query is None: return http.HttpResponseBadRequest('no query supplied.') pagesize = request.query_params.get('pagesize', '40') if not pagesize.isnumeric() or int(pagesize) < 1: return http.HttpResponseBadRequest('invalid page size.') pagesize = int(pagesize) name_query = dsl_query.Match(name={'query': query}) result = AuthorDocument.search().query(name_query) search_result = Author.objects.filter(name__icontains=query) count = result.count() if count <= 0: return http.JsonResponse( { 'data': PaperSerializer([], many=True).data, 'max_pages': 0, 'count': 0 }, safe=False) max_pages = min((count - 1) // pagesize + 1, (SEARCH_CAP - 1) // pagesize + 1) count = min(count, SEARCH_CAP) # Limit as elasticsearch has a limit on slices. This can be extended in the future # Example for error: # - Remove max(...,SEARCH_CAP) in expression above # - Search for Gao in Authors # - All Results above result 10.0000 should fail to load page = request.query_params.get('page', '1') if not page.isnumeric() or int(page) > max_pages: return http.HttpResponseBadRequest('invalid page number.') page = int(page) return http.JsonResponse( { 'data': AuthorSerializer(result[pagesize * (page - 1):pagesize * page].to_queryset(), many=True).data, 'max_pages': max_pages, 'count': count, }, safe=False)
def primary_should_rules(self, search_query, analyzer): """Return "primary" should rules for the query. These are the ones using the strongest boosts, so they are only applied to a specific set of fields like the name, the slug and authors. Applied rules: * Prefer phrase matches that allows swapped terms (boost=4) * Then text matches, using the standard text analyzer (boost=3) * Then text matches, using a language specific analyzer (boost=2.5) * Then try fuzzy matches ("fire bug" => firebug) (boost=2) * Then look for the query as a prefix of a name (boost=1.5) """ should = [] rules = [ (query.MatchPhrase, { 'query': search_query, 'boost': 4, 'slop': 1 }), (query.Match, { 'query': search_query, 'boost': 3, 'analyzer': 'standard' }), (query.Fuzzy, { 'value': search_query, 'boost': 2, 'prefix_length': 4 }), (query.Prefix, { 'value': search_query, 'boost': 1.5 }), ] # Apply rules to search on few base fields. Some might not be present # in every document type / indexes. for k, v in rules: for field in ('name', 'slug', 'listed_authors.name'): should.append(k(**{field: v})) # For name, also search in translated field with the right language # and analyzer. if analyzer: should.append( query.Match( **{ 'name_l10n_%s' % analyzer: { 'query': search_query, 'boost': 2.5, 'analyzer': analyzer } })) return should
def test_bool_from_dict_issue_318(): d = { "bool": { "must_not": {"match": {"field": "value"}} } } q = query.Q(d) assert q == ~query.Match(field='value')
def match_by_uri(uri: str) -> Q.Query: """ Match a document by its uri :param uri: :return: """ if not uri.startswith("/"): uri = "/" + uri return Q.Match(_id=uri)
def secondary_should_rules(self, search_query, analyzer): """Return "secondary" should rules for the query. These are the ones using the weakest boosts, they are applied to fields containing more text like description, summary and tags. Applied rules: * Look for phrase matches inside the summary (boost=0.8) * Look for phrase matches inside the summary using language specific analyzer (boost=0.6) * Look for phrase matches inside the description (boost=0.3). * Look for phrase matches inside the description using language specific analyzer (boost=0.1). * Look for matches inside tags (boost=0.1). """ should = [ query.MatchPhrase(summary={ 'query': search_query, 'boost': 0.8 }), query.MatchPhrase(description={ 'query': search_query, 'boost': 0.3 }), ] # Append a separate 'match' query for every word to boost tag matches for tag in search_query.split(): should.append(query.Match(tags={'query': tag, 'boost': 0.1})) # For description and summary, also search in translated field with the # right language and analyzer. if analyzer: should.extend([ query.MatchPhrase( **{ 'summary_l10n_%s' % analyzer: { 'query': search_query, 'boost': 0.6, 'analyzer': analyzer } }), query.MatchPhrase( **{ 'description_l10n_%s' % analyzer: { 'query': search_query, 'boost': 0.6, 'analyzer': analyzer } }) ]) return should
def primary_should_rules(self, search_query, analyzer): """Return "primary" should rules for the query. These are the ones using the strongest boosts, so they are only applied to a specific set of fields like the name, the slug and authors. """ should = [] rules = [ (query.Match, { 'query': search_query, 'boost': 3, 'analyzer': 'standard' }), (query.Match, { 'query': search_query, 'boost': 4, 'type': 'phrase', 'slop': 1 }), (query.Prefix, { 'value': search_query, 'boost': 1.5 }), ] # Only add fuzzy queries if the search query is a single word. # It doesn't make sense to do a fuzzy query for multi-word queries. if ' ' not in search_query: rules.append((query.Fuzzy, { 'value': search_query, 'boost': 2, 'prefix_length': 4 })) # Apply rules to search on few base fields. Some might not be present # in every document type / indexes. for k, v in rules: for field in ('name', 'slug', 'authors'): should.append(k(**{field: v})) # For name, also search in translated field with the right language # and analyzer. if analyzer: should.append( query.Match( **{ 'name_%s' % analyzer: { 'query': search_query, 'boost': 2.5, 'analyzer': analyzer } })) return should
def test_Q_constructs_compound_query_from_dict(): q = query.Q({"bool": { "must": [ { 'match': { 'f': 'value' } }, ] }}) assert q == query.Bool(must=[query.Match(f='value')])
def match(field, search_term, **kwargs): field_name = _get_field_name(field) query_dict = { field_name: { "query": search_term, } } for item in kwargs: query_dict[field_name][item] = kwargs[item] q = query.Match(**query_dict) return q
def build_match_query(key: str, term: str, fuzziness: str, boost_factor: int = 1) -> query.Query: return query.Match( **{ key: { 'query': term, 'operator': 'or', "fuzziness": fuzziness, "minimum_should_match": "3<75%", 'boost': boost_factor } })
def test_allow_multiple_queries_for_constant_score_issue_599(): # Construct a number of ConstantScore queries each with different # combinations of queries and filters. q1 = query.ConstantScore(query=[query.Match(f=1), query.Match(f=2)]) q2 = query.ConstantScore(filter=[query.Match(f=1), query.Match(f=2)]) q3 = query.ConstantScore(query=query.Match(f=1)) q4 = query.ConstantScore(filter=query.Match(f=1)) for q in [q1, q2, q3, q4]: assert isinstance(q.to_dict(), dict)
def test_two_bool_queries_append_one_to_should_if_possible(): q1 = query.Bool(should=[query.Match(f='v')]) q2 = query.Bool(must=[query.Match(f='v')]) assert (q1 | q2) == query.Bool( should=[query.Match( f='v'), query.Bool(must=[query.Match(f='v')])]) assert (q2 | q1) == query.Bool( should=[query.Match( f='v'), query.Bool(must=[query.Match(f='v')])])