Я хотел бы реализовать поисковую функцию в 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. Каковы их преимущества?
Я предлагаю вам использовать поисковую систему.
Мы использовали Haystack search , модульное поисковое приложение для django, поддерживающее многие поисковые системы (Solr, Xapian, Whoosh и т. Д.)
Преимущества:
Недостатки:
Мы очень довольны этим решением, и его довольно легко реализовать.
Ответьте на ваш общий вопрос: определенно используйте для этого подходящее приложение.
В запросе вы всегда проверяете все содержимое полей (заголовок, текст, теги). Вы не получаете никакой выгоды от индексов и т. Д.
При правильной системе полнотекстового поиска (или как вы ее называете) текст (слова) индексируются каждый раз, когда вы вставляете новые записи. Таким образом, запросы будут выполняться намного быстрее, особенно когда ваша база данных растет.
Я думаю, что полнотекстовый поиск на уровне приложения больше зависит от того, что у вас есть и как вы ожидаете его масштабирования. Если у вас небольшой сайт с низкой посещаемостью, я думаю, что было бы более доступным потратить некоторое время на создание настраиваемого полнотекстового поиска, а не на установку приложения, которое будет выполнять поиск за вас. И приложение создало бы больше зависимостей, обслуживания и дополнительных усилий при хранении данных. Сделав поиск самостоятельно, вы сможете встроить приятные пользовательские функции. Например, если ваш текст точно соответствует одному заголовку, вы можете направить пользователя на эту страницу вместо отображения результатов. Другой вариант - разрешить префиксы 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))
SOLR очень легко настроить и интегрировать с Django. Стог сена делает это еще проще.
Для полнотекстового поиска в Python см. PyLucene .Это позволяет выполнять очень сложные запросы. Основная проблема здесь в том, что вы должны найти способ сообщить своей поисковой системе, какие страницы изменились, и в конечном итоге обновить индекс.
Кроме того, вы можете использовать Google Sitemaps , чтобы сообщить Google, что нужно быстрее индексировать ваш сайт, а затем встроить настраиваемое поле запроса на ваш сайт. Преимущество здесь в том, что вам просто нужно сообщить Google об измененных страницах, и Google сделает всю тяжелую работу (индексирование, анализ запросов и т. Д.). Вдобавок ко всему, большинство людей привыкли использовать Google для поиска, и это также будет поддерживать ваш сайт в глобальном поиске Google.
На самом деле, в запросе, который вы опубликовали does, используется OR, а не AND - вы используете \
для разделения объектов Q
. AND будет &
.
В целом, я бы настоятельно рекомендовал использовать подходящую поисковую систему. У нас был хороший успех с Haystack поверх Solr - Haystack управляет всей конфигурацией Solr и предоставляет хороший API, очень похожий на собственный ORM Django.