Esempio n. 1
0
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)
Esempio n. 2
0
def test_fuzzy_to_dict():
    assert {"fuzzy": {"f": "value"}} == query.Fuzzy(f='value').to_dict()
Esempio n. 3
0
    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)