Как реализовать полнотекстовый поиск в Django? - PullRequest
9 голосов
/ 17 марта 2010

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

См:

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. Каковы их преимущества?

Ответы [ 6 ]

16 голосов
/ 17 марта 2010

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

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

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

  • Быстрее
  • выполнять поисковые запросы, даже не обращаясь к базе данных.
  • Выделить искомые термины
  • Функциональность "More like this"
  • орфографические предложения
  • Лучший рейтинг
  • и т.д ...

Недостатки:

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

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

5 голосов
/ 17 марта 2010

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

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

4 голосов
/ 17 марта 2010

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

4 голосов
/ 17 марта 2010

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

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

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

2 голосов
/ 17 марта 2010

Я думаю, что полнотекстовый поиск на уровне приложения - это больше вопрос того, что у вас есть и как вы ожидаете, что оно будет масштабироваться. Если вы используете небольшой сайт с низким уровнем использования, я думаю, что было бы более доступным потратить некоторое время на создание настраиваемого полнотекстового поиска, а не на установку приложения для его поиска. И приложение будет создавать больше зависимости, обслуживания и дополнительных усилий при хранении данных. Сделав поиск самостоятельно, вы сможете встроить приятные пользовательские функции. Как, например, если ваш текст точно соответствует одному заголовку, вы можете направить пользователя на эту страницу вместо того, чтобы показывать результаты. Другой - разрешить префиксы 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 голосов
/ 17 марта 2010

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

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

...