def search_suggestions(request, lang, version, per_page=20):
    """
    The endpoint for the OpenSearch browser integration.

    This will do a simple prefix match against the title to catch
    documents with a meaningful title.

    The link list contains redirect URLs so that IE will correctly
    redirect to those documents.
    """
    try:
        release = DocumentRelease.objects.get_by_version_and_lang(
            version, lang)
    except DocumentRelease.DoesNotExist:
        raise Http404

    form = DocSearchForm(request.GET or None, release=release)
    suggestions = []

    if form.is_valid():
        q = form.cleaned_data.get('q')
        if q:
            search = DocumentDocType.search()
            search = (search.query(
                query.SimpleQueryString(
                    fields=['title^10', 'content'],
                    query=q,
                    analyzer='stop',
                    default_operator='and')).filter(
                        'term', release__lang=release.lang).filter(
                            'term', release__version=release.version).source(
                                includes=['title']))

            suggestions.append(q)
            titles = []
            links = []
            content_type = ContentType.objects.get_for_model(Document)
            results = search[0:per_page].execute()
            for result in results:
                titles.append(result.title)
                kwargs = {
                    'content_type_id': content_type.pk,
                    'object_id': result.meta.id,
                }
                links.append(reverse('contenttypes-shortcut', kwargs=kwargs))
            suggestions.append(titles)
            suggestions.append([])
            suggestions.append(links)

    return JsonResponse(suggestions, safe=False)
def search_results(request, lang, version, per_page=10, orphans=3):
    """
    Search view to handle language and version specific queries.
    The old search view is being redirected here.
    """
    try:
        release = DocumentRelease.objects.get_by_version_and_lang(
            version, lang)
    except DocumentRelease.DoesNotExist:
        raise Http404
    form = DocSearchForm(request.GET or None, release=release)

    context = {
        'form': form,
        'lang': release.lang,
        'version': release.version,
        'release': release,
        'searchparams': request.GET.urlencode(),
    }

    if form.is_valid():
        q = form.cleaned_data.get('q')

        if q:
            # catch queries that are coming from browser search bars
            exact = (DocumentDocType.index_queryset().filter(release=release,
                                                             title=q).first())
            if exact is not None:
                return redirect(exact)

            # let's just use simple queries since they allow some
            # neat syntaxes for exclusion etc. For more info see
            # http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
            should = [
                query.Common(_all={
                    'query': q,
                    'cutoff_frequency': 0.001
                }),
                query.SimpleQueryString(fields=['title', '_all'],
                                        query=q,
                                        default_operator='and'),
            ]

            # then apply the queries and filter out anything not matching
            # the wanted version and language, also highlight the content
            # and order the highlighted snippets by score so that the most
            # fitting result is used
            results = (DocumentDocType.search().query(
                query.Bool(should=should)).filter(
                    'term', release__lang=release.lang).filter(
                        'term',
                        release__version=release.version).highlight_options(
                            order='score').highlight('content_raw').extra(
                                min_score=.01))

            page_number = request.GET.get('page') or 1
            paginator = SearchPaginator(results,
                                        per_page=per_page,
                                        orphans=orphans)

            try:
                page_number = int(page_number)
            except ValueError:
                if page_number == 'last':
                    page_number = paginator.num_pages
                else:
                    raise Http404(
                        _("Page is not 'last', "
                          "nor can it be converted to an int."))

            try:
                page = paginator.page(page_number)
            except InvalidPage as e:
                raise Http404(
                    _('Invalid page (%(page_number)s): %(message)s') % {
                        'page_number': page_number,
                        'message': str(e)
                    })

            context.update({
                'query': q,
                'page': page,
                'paginator': paginator,
            })

    if release.lang != 'en':
        activate(release.lang)

    return render(request, 'docs/search_results.html', context)
Example #3
0
def search_results(request, lang, version, per_page=10, orphans=3):
    """
    Search view to handle language and version specific queries.
    The old search view is being redirected here.
    """
    release = get_object_or_404(DocumentRelease, version=version, lang=lang)
    form = DocSearchForm(request.GET or None, release=release)

    context = {
        'form': form,
        'lang': release.lang,
        'version': release.version,
        'release': release,
        'searchparams': request.GET.urlencode(),
        'version_is_dev': version == 'dev',
        'version_is_unsupported': version_is_unsupported(version),
    }

    if form.is_valid():
        q = form.cleaned_data.get('q')

        if q:
            # catch queries that are coming from browser search bars
            exact = (DocumentDocType.index_queryset()
                                    .filter(release=release, title=q)
                                    .first())
            if exact is not None:
                return redirect(exact)

            should = []
            if any(operator in q for operator in SIMPLE_SEARCH_OPERATORS):
                should.append(query.SimpleQueryString(fields=['title',
                                                              'content^5'],
                                                      query=q,
                                                      analyzer='stop',
                                                      default_operator='and'))
            else:
                # let's just use simple queries since they allow some
                # neat syntaxes for exclusion etc. For more info see
                # http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html
                should = [query.MultiMatch(fields=['title^10', 'content'],
                                           query=q,
                                           type='phrase_prefix'),
                          query.Match(query=q),
                          query.MultiMatch(fields=['title^5', 'content'],
                                           query=q,
                                           fuzziness=1)]

            # then apply the queries and filter out anything not matching
            # the wanted version and language, also highlight the content
            # and order the highlighted snippets by score so that the most
            # fitting result is used
            results = (DocumentDocType.search()
                                      .query(query.Bool(should=should))
                                      .filter('term', release__lang=release.lang)
                                      .filter('term', release__version=release.version)
                                      .highlight_options(order='score')
                                      .highlight('content'))

            page_number = request.GET.get('page') or 1
            paginator = SearchPaginator(results, per_page=per_page, orphans=orphans)

            try:
                page_number = int(page_number)
            except ValueError:
                if page_number == 'last':
                    page_number = paginator.num_pages
                else:
                    raise Http404(_("Page is not 'last', "
                                    "nor can it be converted to an int."))

            try:
                page = paginator.page(page_number)
            except InvalidPage as e:
                raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
                    'page_number': page_number,
                    'message': str(e)
                })

            context.update({
                'query': q,
                'page': page,
                'paginator': paginator,
            })

    if release.lang != 'en':
        activate(release.lang)

    return render(request, 'docs/search_results.html', context)