Это десятая статья в серии, где я описываю свой опыт написания веб-приложения на Python с использованием микрофреймворка Flask.

Цель данного руководства — разработать довольно функциональное приложение-микроблог, которое я за полным отсутствием оригинальности решил назвать microblog.

Краткое повторение


В предыдущей статье мы улучшили наши запросы так, чтобы они возвращали посты на страницу.

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

Для многих типов веб-сайтов можно просто позволить Google, Bing, и т.п. проиндексировать все и предоставлять результаты поиска. Это хорошо работает с сайтами, которые имеют в основе статические страницы, такие как форум. В нашем маленьком приложении базовая единица контента это короткий пользовательский пост, а не целая страница. Мы хотим более динамичный результат поиска. Для примера, если мы ищем слово «dog» мы хотим видеть все сообщения пользователей, включающие это слово. Очевидно, что страница результата поиска не существует до тех пор, пока никто не проведет поиск, поэтому поисковики не смогут проиндексировать ее.

Введение в системы полнотекстового поиска


К сожалению поддержка полнотекстового поиска в реляционных базах данные не стандартизирована. Каждая база даннные реализует полнотекстовый поиск по-своему, и SQLAlchemy не имеет на этот случай подходящей абстракции.

Мы сейчас используем SQLite для нашей базы, поэтому мы просто могли создать полнотекстовый индекс, используя возможности предоставялемые SQLite, в обход SQLAlchemy. Но это плохая идея, потому что если в один прекрасный день мы решим перейти на другую базу данных, нам придется переписать наш полнотекстовый поиск для другой базы данных.

Вместо этого, мы собираемся оставить нашу базу для работы с обычными данными, и создать специализированную базу для поиска.

Есть несколько систем полнотекстового поиска с открытым исходным кодом. Только одна, насколько мне известно, имеет расширение Flask называемое Whoosh, и движок ее тоже написан на Python. Преимущество использования чистого Python это возможность установить его и запустить везде, где доступен Python. Недостатком является эффективность поиска, которая не сравнится с движками написанными на C или C++. На мой взгляд было бы идеальным решением иметь расширение для Flask которое может соединятся с разными системами и абстрагировать нас от деталей, как это делает Flask-SQLAlchemy освобождая нас от ньюансов различных баз данных, но в области полнотекстового поиска нет пока ничего подобного. Разработчики на Django имеют очень хорошее расширение, которое поддерживает различные системы полнотекстового поиска называемое django-haystack. Может быть в один прекрасный день кто-нибудь создаст аналогичное расширение для Flask.

Но сейчас, мы реализуем наш поиск с помощью Whoosh. Расширение, которое мы собираемся использовать это Flask-WhooshAlchemy, которая объединяет базу Whoosh с моделью Flask-SQLAlchemy.

Если у вас пока нет Flask-WhooshAlchemy в вашем виртуальном окружении, самое время установить его. Пользователи Windows должны сделать так:

Все другие могу сделать так:

 

Конфигурация


Конфигурация у Flask-WhooshAlchemy очень простая. Мы просто должны сказать расширению имя нашей базы для полнотекстового поиска (файл config.py):

 

 

Изменения модели


Поскольку Flask-WhooshAlchemy интегрируется Flask-SQLAlchemy, нам нужно указать какие данные должны быть проиндексированы в каких моделях (файл app/models.py):

Модель теперь имеет новое поле __searchable__, которое представляет собой массив со всеми полями бд, которые должны попасть в индекс. В нашем случае нам нужен только индекс поля body нашего поста.

Мы также проводим инициализацию полнотекстового индекса для этой модели вызывая функцию whoosh_index.

Так как мы не меняли формат нашей базы, нам не нужно делать новую миграцию.

К сожалению все посты, которые были в базе до добавления движка полнотекстового поиска, не будут проиндексированы. Чтобы убедиться что база данных и движок поиска синхронизированы мы должны удалить все посты из базы и начать сначала. Сначала запускаем интерпретатор Python. Для пользователей Windows:

Для всех остальных:

Этим запросом мы удаляем все посты:

 

 

Поиск


Сейчас мы готовы к поиску. Давайте сначала добавим несколько постов в БД. У нас есть два способа сделать это. Мы можем запустить приложение и добавить посты через web-браузер, как обычный пользователь, или мы можем сделать это через интерпретатор.

Через интерпретатор мы можем сделать это следующим образом:

 

Расширение Flask-WhooshAlchemy очень крутое, потому что соединяется с Flask-SQLAlchemy автоматически. Нам не нужно поддерживать индекс полнотекстового поиска, все делается прозрачно для нас.

Сейчас мы имеем несколько постов проиндексированных для полнотекстового поиска и можем попробовать поискать:

Как вы можете видеть в примерах, запросы не обязательно должны ограничиваться одиночными словами. По факту Whoosh поддерживает прекрасный язык поисковых запросов.

Интеграция полнотекстового поиска в наше приложение


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

Конфигурация


В конфигурации мы должны указать сколько результатов поиска нужно вернуть (файл config.py):

 

Форма поиска


Мы собираемся добавить форму поиска в строку навигации вверху страницы. Расположнение в верхней части очень удачное, так как поиск будет доступен со всех страниц.

Сначала мы должны добавить класс формы поиска (файл app/forms.py):

Затем нам нужно создать объект формы поиска и сделать его доступным для всех шаблонов. Положим его в панель навигации, которая является общей для всех страниц. Простой способ добиться этого это создать форму в обработчикеbefore_request, и вставить его в глобальную переменную (файл app/views.py):

 

Затем мы добавим форму в наш шаблон(файл app/templates/base.html):

Обратите внимание мы отображаем форму поиска только когда пользователь вошел в систему. Точно так же, обработчик before_request создаст форму только когда пользователь вошел в систему, поскольку наше приложение не показывает никакого контента неавторизованым гостям.

View. Функция Search


Поле action для нашей формы был установлен выше, чтобы отправлять все запросы в функцию search нашего представления. Это то место где мы будем выполнять наши полнотекстовые запросы (файл app/views.py):

 

Страница результатов


После того как строка запроса передана формой, обработчик POST передает ее через перенаправление в обработчик search_results (файл app/views.py):

 

Функция search_result отправляет запрос в Whoosh, передавая вместе с запросом ограничение по количеству результатов, чтобы защититься от потенциально большого количества результатов поиска.

Поиск завершается в шаблоне search_result (файлapp/templates/search_results.html):

 

 

И здесь мы снова можем повторно использовать наш post.html.

 

Заключительные слова


Мы сейчас завершили еще одну очень важную, хотя и часто упускаемую из вида функцию, которой должно обладать приличное веб-приложение.

Ниже я выкладываю обновленную версию приложения microblog во всеми изменениями, сделанными в этой статье.

Как всегда, базы данных нет, вы должны создать ее самостоятельно. Если вы следите за этой серией статей, вы знаете как это делать. Если же нет, то вернитесь к статье о базе данных, чтобы узнать.

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

Miguel

 

Мега-Учебник Flask, Часть 10: Полнотекстовый поиск

Отключите, пожалуйста, AdBlock / uBlock. Поддержите наш проект! Сайт не переполнен рекламными блоками, поп-андерами и другими видами рекламы.