Как реализовать полнотекстовый поиск в Django?

Я хотел бы реализовать поисковую функцию в django ведущее блог приложение. Статус-кво - то, что у меня есть список строк, предоставленных пользователем, и queryset сужен каждой строкой для включения только тех объектов, которые соответствуют строке.

См.:

if request.method == "POST":
    form = SearchForm(request.POST)
    if form.is_valid():
        posts = Post.objects.all()
        for string in form.cleaned_data['query'].split():
            posts = posts.filter(
                    Q(title__icontains=string) | 
                    Q(text__icontains=string) |
                    Q(tags__name__exact=string)
                    )
        return archive_index(request, queryset=posts, date_field='date')

Теперь, что, если я не хотел, действительно связывает каждое слово, которое разыскивается логическим И но с логическим ИЛИ? Как я сделал бы это? Существует ли способ сделать это с собственными методами Queryset Django, или нужно отступить к необработанным SQL-запросам?

В целом, это надлежащее решение сделать полнотекстовый поиск как это или было бы Вы рекомендовать использовать поисковую систему как Solr, Whoosh или Xapian. Каковы их преимущества?

9
задан Sнаđошƒаӽ 2 April 2016 в 17:40
поделиться

6 ответов

Я предлагаю вам использовать поисковую систему.

Мы использовали Haystack search , модульное поисковое приложение для django, поддерживающее многие поисковые системы (Solr, Xapian, Whoosh и т. Д.)

Преимущества:

  • Быстрее
  • выполнять поисковые запросы даже без обращения к базе данных.
  • Выделение искомых терминов
  • Функциональность «Еще как это»
  • Предложения по правописанию
  • Лучшее ранжирование
  • и т. Д.

Недостатки:

  • Индексы поиска могут быстро увеличиваться в размере
  • Одна из лучших поисковых систем (Solr) работает как сервлет Java (Xapian не работает)

Мы очень довольны этим решением, и его довольно легко реализовать.

16
ответ дан 4 December 2019 в 06:56
поделиться

Ответьте на ваш общий вопрос: определенно используйте для этого подходящее приложение.

В запросе вы всегда проверяете все содержимое полей (заголовок, текст, теги). Вы не получаете никакой выгоды от индексов и т. Д.

При правильной системе полнотекстового поиска (или как вы ее называете) текст (слова) индексируются каждый раз, когда вы вставляете новые записи. Таким образом, запросы будут выполняться намного быстрее, особенно когда ваша база данных растет.

4
ответ дан 4 December 2019 в 06:56
поделиться

Я думаю, что полнотекстовый поиск на уровне приложения больше зависит от того, что у вас есть и как вы ожидаете его масштабирования. Если у вас небольшой сайт с низкой посещаемостью, я думаю, что было бы более доступным потратить некоторое время на создание настраиваемого полнотекстового поиска, а не на установку приложения, которое будет выполнять поиск за вас. И приложение создало бы больше зависимостей, обслуживания и дополнительных усилий при хранении данных. Сделав поиск самостоятельно, вы сможете встроить приятные пользовательские функции. Например, если ваш текст точно соответствует одному заголовку, вы можете направить пользователя на эту страницу вместо отображения результатов. Другой вариант - разрешить префиксы title: или author: к ключевым словам.

Вот метод, который я использовал для создания релевантных результатов поиска по веб-запросу.

import shlex

class WeightedGroup:
    def __init__(self):  
        # using a dictionary will make the results not paginate
        # but it will be a lot faster when storing data          
        self.data = {}

    def list(self, max_len=0):
        # returns a sorted list of the items with heaviest weight first
        res = []
        while len(self.data) != 0:
            nominated_weight = 0                      
            for item, weight in self.data.iteritems():
                if weight > nominated_weight:
                    nominated = item
                    nominated_weight = weight
            self.data.pop(nominated)
            res.append(nominated)
            if len(res) == max_len:
                return res
        return res

    def append(self, weight, item):
        if item in self.data:
            self.data[item] += weight
        else:
            self.data[item] = weight


def search(searchtext):
    candidates = WeightedGroup()

    for arg in shlex.split(searchtext): # shlex understand quotes

        # Search TITLE
        # order by date so we get most recent posts
        query = Post.objects.filter_by(title__icontains=arg).order_by('-date')
        arg_hits = query.count() # count is cheap

        if arg_hits > 1000:
            continue # skip keywords which has too many hits

        # Each of these are expensive as it would transfer data
        #  from the db and build a python object, 
        for post in query[:50]: # so we limit it to 50 for example                
            # more hits a keyword has the lesser it's relevant
            candidates.append(100.0 / arg_hits, post.post_id)

        # TODO add searchs for other areas
        # Weight might also be adjusted with number of hits within the text
        #  or perhaps you can find other metrics to value an post higher,
        #  like number of views

    # candidates can contain a lot of stuff now, show most relevant only
    sorted_result = Post.objects.filter_by(post_id__in=candidates.list(20))
2
ответ дан 4 December 2019 в 06:56
поделиться

SOLR очень легко настроить и интегрировать с Django. Стог сена делает это еще проще.

4
ответ дан 4 December 2019 в 06:56
поделиться

Для полнотекстового поиска в Python см. PyLucene .Это позволяет выполнять очень сложные запросы. Основная проблема здесь в том, что вы должны найти способ сообщить своей поисковой системе, какие страницы изменились, и в конечном итоге обновить индекс.

Кроме того, вы можете использовать Google Sitemaps , чтобы сообщить Google, что нужно быстрее индексировать ваш сайт, а затем встроить настраиваемое поле запроса на ваш сайт. Преимущество здесь в том, что вам просто нужно сообщить Google об измененных страницах, и Google сделает всю тяжелую работу (индексирование, анализ запросов и т. Д.). Вдобавок ко всему, большинство людей привыкли использовать Google для поиска, и это также будет поддерживать ваш сайт в глобальном поиске Google.

2
ответ дан 4 December 2019 в 06:56
поделиться

На самом деле, в запросе, который вы опубликовали does, используется OR, а не AND - вы используете \ для разделения объектов Q. AND будет &.

В целом, я бы настоятельно рекомендовал использовать подходящую поисковую систему. У нас был хороший успех с Haystack поверх Solr - Haystack управляет всей конфигурацией Solr и предоставляет хороший API, очень похожий на собственный ORM Django.

5
ответ дан 4 December 2019 в 06:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: