def name_query(q): """ Returns a boolean should query `elasticsearch_dsl.query.Bool` given a query string. """ should = [] rules = { query.Match: { 'query': q, 'boost': 3, 'analyzer': 'standard' }, query.Match: { 'query': q, 'boost': 4, 'type': 'phrase', 'slop': 1 }, query.Prefix: { 'value': q, 'boost': 1.5 } } # Only add fuzzy queries if q is a single word. It doesn't make sense to do # a fuzzy query for multi-word queries. if ' ' not in q: rules[query.Fuzzy] = {'value': q, 'boost': 2, 'prefix_length': 1} for k, v in rules.iteritems(): for field in ('name', 'app_slug', 'author'): should.append(k(**{field: v})) # Exact matches need to be queried against a non-analyzed field. Let's do a # term query on `name_sort` for an exact match against the app name and # give it a good boost since this is likely what the user wants. should.append(query.Term(name_sort={'value': q, 'boost': 10})) analyzer = _get_locale_analyzer() if analyzer: should.append( query.Match(**{'name_%s' % analyzer: { 'query': q, 'boost': 2.5 }})) # Add searches on the description field. should.append( query.Match(description={ 'query': q, 'boost': 0.8, 'type': 'phrase' })) analyzer = _get_locale_analyzer() if analyzer: should.append( query.Match( **{ 'description_%s' % analyzer: { 'query': q, 'boost': 0.6, 'type': 'phrase', 'analyzer': get_custom_analyzer(analyzer) } })) # Add searches on tag field. should.append(query.Match(tags={'query': q})) if ' ' not in q: should.append(query.Fuzzy(tags={'value': q, 'prefix_length': 1})) return query.Bool(should=should)
def test_fuzzy_to_dict(): assert {"fuzzy": {"f": "value"}} == query.Fuzzy(f='value').to_dict()
def filter_queryset(self, request, queryset, view): q = request.GET.get('q', '').lower() lang = translation.get_language() analyzer = self._get_locale_analyzer(lang) if not q: return queryset should = [] rules = [ (query.Match, { 'query': q, 'boost': 3, 'analyzer': 'standard' }), (query.Match, { 'query': q, 'boost': 4, 'type': 'phrase', 'slop': 1 }), (query.Prefix, { 'value': q, 'boost': 1.5 }), ] # Only add fuzzy queries if q is a single word. It doesn't make sense # to do a fuzzy query for multi-word queries. if ' ' not in q: rules.append((query.Fuzzy, { 'value': q, 'boost': 2, 'prefix_length': 1 })) # 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 ('app_slug', 'author', 'name', 'short_name', 'slug', 'title', 'url_tokenized'): should.append(k(**{field: v})) # 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 item # name and give it a good boost since this is likely what the user # wants. # FIXME: we should also do that on translations and slug/app_slug, but # we don't store a raw version for them at the moment. should.append(query.Term(**{'name.raw': {'value': q, 'boost': 10}})) # Do the same for GUID searches. should.append(query.Term(**{'guid': {'value': q, 'boost': 10}})) # If query is numeric, check if it is an ID. if q.isnumeric(): should.append(query.Term(**{'id': {'value': q, 'boost': 10}})) if analyzer: should.append( query.Match( **{'name_l10n_%s' % analyzer: { 'query': q, 'boost': 2.5 }})) should.append( query.Match(**{ 'short_name_l10n_%s' % analyzer: { 'query': q, 'boost': 2.5 } })) # Add searches on the description field. should.append( query.Match(description={ 'query': q, 'boost': 0.8, 'type': 'phrase' })) if analyzer: desc_field = 'description_l10n_%s' % analyzer desc_analyzer = ('%s_analyzer' % analyzer if analyzer in mkt.STEMMER_MAP else analyzer) should.append( query.Match( **{ desc_field: { 'query': q, 'boost': 0.6, 'type': 'phrase', 'analyzer': desc_analyzer } })) # Add searches on tag field. should.append(query.Term(tags={'value': q})) if ' ' not in q: should.append(query.Fuzzy(tags={'value': q, 'prefix_length': 1})) # The list of functions applied to our `function_score` query. functions = [ query.SF('field_value_factor', field='boost'), ] # Add a boost for the preferred region, if it exists. region = get_region_from_request(request) if region: functions.append({ 'filter': { 'term': { 'preferred_regions': region.id } }, # TODO: When we upgrade to Elasticsearch 1.4, change this # to 'weight'. 'boost_factor': 4, }) return queryset.query('function_score', query=query.Bool(should=should), functions=functions)