Transcription
Привет! В этом видео мы рассмотрим всё, что вам нужно знать про Elasticsearch для начала работы. Поговорим о том, что такое Elasticsearch, для чего он нужен, и изучим базовые понятия для работы с ним. А также рассмотрим, как развернуть сервер Elasticsearch локально, изучим основные команды для работы с документами и индексами. И в завершении, также посмотрим Elasticsearch на примере веб-приложения с полнотекстовым поиском.
В описании к этому видео вы также найдёте краткий конспект и ссылку на репозиторий с проектом, чтобы вы могли самостоятельно повторить всё то, что мы рассмотрим здесь. Ставь лайк и подписывайся на канал, чтобы не пропустить выпуск новых видео. Усаживайтесь поудобнее, ну а мы начинаем.
Что такое Elasticsearch? Для начала, давайте поговорим о том, зачем нам в приложении может понадобиться Elasticsearch и что это вообще такое. Представьте, что мы разрабатываем веб-приложение — картотеку фильмов по типу IMDb или КиноПоиск. Пользователи могут просматривать информацию как о конкретном фильме, так и смотреть весь список фильмов, которые есть на нашем сайте. Упрощенно, архитектура такого приложения можно изобразить следующим образом: есть сервер, который обрабатывает запросы от пользователей, и есть база данных, которая хранит себе информацию о фильмах. База данных может быть любой, как реляционной, так и не реляционной, сейчас это не имеет значения. Но для определённости, остановим наш выбор на реляционной базе данных.
Когда пользователь запрашивает информацию по конкретному фильму, например, с ID 23, в нашей базе данных он посылает GET-запрос по пути `/movies/23`. Сервер срабатывает такой запрос по ходам базы данных с запросом вида `SELECT ID, title, ... FROM films WHERE ID = 23`. А когда запрашивает список всех фильмов, то запрос может выглядеть примерно таким образом: `SELECT * FROM films`.
Этих запросов достаточно, пока всё, что нам нужно — это получение информации по конкретному фильму или просмотр списка всех фильмов один за другим. Просматривать список всех фильмов один за другим в поисках нужного может быть утомительно, поэтому для удобства пользователей необходимо добавить возможность поиска фильма по названию, фразе, описанию фильма, стране производства или чему-то ещё. Можно попробовать организовать такой поиск уже имеющимся в нашем распоряжении средством — базой данных. Когда пользователь ввёл строку, то мы можем искать фильм в таблице фильмов по подстроке или шаблону, а запрос в базу данных может выглядеть примерно таким образом: `SELECT * FROM films WHERE title LIKE '%<search_string>%' OR description LIKE '%<search_string>%'`.
Если у вас нет опыта работы с реляционными базами данных, и эти запросы кажутся непонятными, не волнуйтесь. Для понимания работы Elasticsearch это не критично. Но если вы хотите разобраться в основах SQL и научиться уверенно работать с базами данных, у меня есть для вас курс по SQL и PostgreSQL. Он доступен на платформах Stepik и Udemy. Этот курс охватывает всё, что нужно, чтобы начать работать с реляционными базами данных, а также содержит большое количество практических заданий на написание SQL-кода и проверочных тестов. Курс постоянно обновляется и дополняется новыми материалами. Ссылки на курсы и промокод со скидкой будет в описании к этому видео.
А мы вернёмся к нашему примеру. В целом, организовать поиск средствами базы данных возможно. Однако такой подход обладает рядом недостатков: запросы могут быть медленными при больших объёмах данных, сложно реализовать эффективный поиск по составным условиям, а результаты поиска могут быть не совсем точными и релевантными. Нам нужен полнотекстовый поиск. Если вы не сталкивались с таким понятием ранее, то кратко — это такой поиск, который позволяет искать текст в документах по ключевым словам или фразам. При полнотекстовом поиске анализируется содержимое текста, и в результате выдаются наиболее релевантные документы. Здесь как раз и приходит на помощь Elasticsearch.
Итак, что же такое Elasticsearch? Если кратко, Elasticsearch — это хранилище документов с возможностью создавать полнотекстовые индексы для последующего поиска, чаще всего используемое в качестве поискового движка. Elasticsearch добавляет к возможностям библиотеки Apache Lucene, на котором основан, такие функции как шардирование, репликацию, удобный JSON API и множество других улучшений. Это делает Elasticsearch одним из самых популярных решений для полнотекстового поиска.
С Elasticsearch структура нашего приложения немного изменится. У нас появляется поисковый движок. Как от этого меняется логика нашего приложения? В первую очередь, нам необходимо построить индекс Elasticsearch по уже имеющимся фильмам, чтобы при обращении к нему с каким-то запросом мы получали в ответ список фильмов, удовлетворяющих этому запросу. Нам достаточно, чтобы Elasticsearch возвращал в ответ на наши запросы только ID фильмов, так как по этим ID мы легко и быстро получим сами фильмы из базы данных. Дальше мы обязаны поддерживать этот индекс в актуальном состоянии, то есть при изменении информации о фильмах в базе данных нам нужно обновить соответствующую информацию в Elasticsearch, при удалении фильма из базы — удалить соответствующую запись и так далее.
Как в связи с этим меняется логика нашего приложения? Когда пользователь запрашивает какой-то фильм по его ID, то сервер отправляет запрос в базу данных напрямую, как и раньше. Elasticsearch для такой операции нам совсем не нужен. А вот если пользователь отправляет поисковый запрос, то есть пытается найти фильм по его описанию, то логика меняется. Вместо неэффективного запроса в базу данных мы отправляем поисковый запрос в Elasticsearch. В ответ Elasticsearch возвращает нам список ID фильмов, удовлетворяющих данному запросу, с ранжированием — сначала самые подходящие, потом менее подходящие документы. С этими ID мы идём с простым запросом в базу данных для получения записи фильмов и возвращаем уже эти документы пользователю.
Добавление поискового движка вроде Elasticsearch расширяет возможности поиска нашего приложения, но в то же время увеличивает его сложность и также затраты на обслуживание. Однако, если поиск в вашем приложении является одним из ключевых компонентов, то плюсы от использования Elasticsearch слегка перекрывают все минусы, что мы увидим позже на практическом примере. А пока двинемся дальше и поговорим про основные понятия в Elasticsearch.
Основные понятия. Для начала работы с Elasticsearch нам необходимо ознакомиться с базовыми понятиями: это индексы, документы и запросы. Давайте обо всём по порядку.
Индекс. Индекс предназначен для группировки данных в логические структуры. У нас может быть индекс по фильмам, или индекс по товарам, или какой-то ещё. Если проводить аналогию с реляционными базами данных, то это как таблица в реляционной базе, только более гибкая, так как может хранить документы разной схемы.
Документы. Это непосредственно записи в индексе. Если мы опять сравниваем с реляционными базами данных, то это аналогично строке в таблице, но со своими отличиями.
Запросы. Запросы в Elasticsearch предназначены для поиска и фильтрации данных в индексах. С помощью запросов мы можем находить документы, соответствующие определённым условиям, сортировать результаты по релевантности, выполнять агрегации и многое другое. Если сравнивать с реляционной базой данных, то это как обычные SQL-запросы, только выглядят по-другому.
Помимо этих базовых понятий, при работе с Elasticsearch также полезно понимать, как устроены шарды и реплики, какие бывают анализаторы, как работает ранжирование и многое другое. Однако это выходит за рамки данного видео. Если вы хотите увидеть ролик на эти темы, напишите об этом в комментариях, так я пойму, что тема вам интересна. А пока нам хватит и этих рассмотренных понятий.
Установка и запуск через Docker. Давайте теперь посмотрим на Elasticsearch на практике, и первое, что нам нужно — это запустить её локально на нашем компьютере. Самый простой способ запустить Elasticsearch локально — это использовать Docker. С помощью Docker вы можете быстро настроить и запустить контейнер с Elasticsearch без необходимости ручной установки и настройки. Если вы не знакомы с Docker, то в описании к этому ролику вы найдёте ссылку на видео, где за 20 минут рассказывается про основы Docker.
Давайте перейдём в терминал. Пишем `docker run` для запуска контейнера. Дальше прокидываем порт контейнера на порт хоста. У Elasticsearch нам нужен порт 9200. Зададим переменное окружение `discovery.type`, установим её значение в `single-node`, так кластер Elasticsearch будет состоять из одного узла. Мы запускаем Elasticsearch для себя, не в продакшене, так что этот режим нам подойдёт. И наконец, пишем название образа Elasticsearch и необходимую версию. Давайте возьмём `7.17.22`.
Видим, что контейнер запущен. Можем проверить, что всё работает как надо, перейдя в браузер на `localhost:9200`. В ответ видим информацию о запущенном инстансе Elasticsearch, текущую версию, версию библиотеки Lucene и прочую информацию. Значит, всё запущено как надо. Поздравляю, мы только что подняли локальный Elasticsearch и готовы приступить непосредственно к работе с ним.
API Elasticsearch. Давайте теперь перейдём непосредственно к взаимодействию с Elasticsearch. Взаимодействие с Elasticsearch происходит по HTTP-протоколу командами GET, PUT, POST и другими, в зависимости от выполняемых операций. То есть, мы можем обращаться к Elasticsearch, например, через консоль с помощью утилиты командной строки `curl` или через удобный графический интерфейс, такой как Postman. Я воспользуюсь Postman.
Индексы. Давайте создадим наш первый индекс. Напомню, что индекс в Elasticsearch представляет собой структуру, подобную таблице в реляционной базе данных. Индекс используется для хранения, поиска и анализа данных. Вообще, индекс в Elasticsearch можно не создавать явно, если добавить документ в несуществующий индекс, Elasticsearch автоматически создаст этот индекс. Однако лучше создавать его самостоятельно. Так мы получаем больший контроль над структурой данных, можем уточнить, какие анализаторы будут использованы, какие поля стоит индексировать и многое другое.
Для создания индекса отправим PUT-запрос к нашему серверу. Пишем адрес, где находится сервер Elasticsearch, у нас это `localhost:9200`, и дальше название индекса. Пусть это будет `first-index`. В теле же запроса мы можем указать различные настройки индекса, такие как количество шардов, на которые делится индекс, количество реплик, определить кастомные анализаторы и прочее.
Mappings. Mapping используется для определения типов данных. Давайте определим только поля и типы данных в mappings, а настройки и прочие параметры оставим по умолчанию. Для этого пишем `mappings`, в нём указываем `properties`, в котором указываем непосредственно поля. Давайте, например, будем хранить информацию о товарах в магазине. Определим поле `title` — тип `text`. Название будем хранить на русском языке, поэтому анализатор для этого поля возьмём `russian`. Он доступен из коробки Elasticsearch. Также добавим поле `price` — тип `float` и информацию о доступности и недоступности товаров — `available` — `boolean`.
Выполним запрос. Видим, что индекс успешно создан.
Добавление и обновление документов. После того, как мы создали наш индекс, давайте добавим в него документы. Чтобы добавить документ в индекс, нужно отправить PUT-запрос на добавление этого документа. Для этого пишем `localhost:9200`, дальше название индекса, в котором мы добавляем документ, у нас это `first-index`, дальше пишем `_doc` и дальше указываем ID документа. У нас это первый документ, так что пусть будет `1`. В теле запроса указываем те поля и информацию, которую мы хотим сохранить: `title`: "Проводные наушники", `price`: 4999, `available`: true.
Выполним запрос. Видим, что документ успешно добавлен в индекс `first-index`. Результат выполнения этого запроса: `created`, то есть был создан новый документ. Если мы отправим запрос по этому же пути, но скажем, изменим цену на 5999, то видим статус `updated` и что версия документа обновилась. То есть, в результате такого запроса был обновлён существующий документ, а не создан новый.
Создание документа. Как видим, одна и та же команда может как создавать документ, так и обновлять его. Это бывает удобно. Однако у такого поведения есть и обратная сторона: мы можем случайно обновить или перезалить какой-то документ данными, сами того не заметив. Поэтому при создании новых документов лучше использовать метод `create`. Отличие его от предыдущего метода состоит в том, что если документ по такому ID существует, то в ответ будет возвращена ошибка. Давайте выполним запрос на создание документа. Для этого к предыдущему запросу добавим `_create`. Выполним запрос. Видим в ответ ошибку, которая говорит, что документ с таким ID уже существует. Если же мы сейчас поменяем ID на `2` в нашем запросе, то уже видим, что запрос выполнился без ошибок.
Получение документа. Чтобы получить документ по ID, необходимо выполнить GET-запрос получения документа по его идентификатору. Тело запроса здесь уже не нужно. Давайте выполним запрос. Видим в ответ документ с индексом `1`. Давайте попробуем получить документ с индексом `2`. Видим новый результат. Если же мы попытаемся получить документ с несуществующим ID, то получим ошибку `404 Not Found`.
Удаление документа. Для удаления документа в индексе используется HTTP-метод `DELETE`. При попытке удалить несуществующий документ, также как и в прошлом запросе, получаем в ответ `not found`. Если же мы поменяем ID на существующее в нашем индексе и выполним такой запрос, то видим результат `deleted`.
Поиск. Поиск — это ключевая функция Elasticsearch. Для выполнения поиска по документам используется специальный endpoint `_search`. Если мы сейчас выполним GET-запрос `localhost:9200/first-index/_search`, то в ответ получим все документы, находящиеся в индексе, так как мы никак не конкретизировали наш запрос и все документы подходят под такие критерии поиска. Сейчас у нас всего один документ в индексе, и возможности поиска на таком наборе документов посмотреть будет затруднительно. Давайте добавим ещё 100 документов в наш индекс. Для добавления такого количества документов воспользуемся Bulk API. Для этого отправим POST-запрос на добавление нескольких документов. Пишем `localhost:9200/first-index/_bulk`. В теле запроса нам необходимо построчно указать сами добавляемые значения и метаданные, в какой индекс и под каким ID добавляем. У меня уже есть заготовка этих данных. Давайте вставим её в тело запроса. В конце обязательно должна присутствовать пустая строка.
[музыка]
Выполним запрос. Видим, что команда успешно выполнена. Вернёмся теперь во вкладку с запросом поиска документов и снова отправим запрос. Видим, что теперь совпадение 101 к одному документу. Мы только что добавили ещё 100. В ответе, правда, присутствуют не все 101 документ, а лишь первая страница. В теле запроса мы можем уточнить `offset` и размер выдачи. Давайте добавим эти параметры в тело запроса. Для этого пишем `from`, зададим `20`, а размер выдачи ограничимся текстом в поле `title`. Для этого пишем `match` и поле, по которому ищем, у нас `title`. Давайте попробуем найти что-то беспроводное. Пишем "беспроводной" и выполним запрос.
Сейчас в ответе видим два документа, удовлетворяющие нашему поиску. В каждом документе ответа, помимо самих данных, есть также поле `score` — параметр, указывающий, насколько тот или иной документ больше или меньше удовлетворяет условиям поиска. Сейчас оба документа имеют одинаковый скор, так как искали мы по слову "беспроводной", а оно присутствует и в одном, и в другом документе. В этом плане документы одинаковые. Давайте чуть поменяем наш запрос и будем искать "беспроводной наушник". Выполним запрос. Видим в результате уже три документа. Теперь у документов уже разный скор. Лучше всего нам подходит документ с названием "беспроводные наушники", что в целом и ожидаемо. Но также под запрос попадают и просто "наушники" и что-то "беспроводное" — у нас это "мышь", правда, они уже имеют меньший скор.
Обратите внимание на то, как документы ранжируются — наиболее подходящие запросы. Документы мы можем искать не только по тексту, но и, например, по диапазону цен и признаку доступности или недоступности товара в магазине, а также комбинировать несколько условий в одно. Давайте для примера напишем запрос для поиска товаров в ценовом диапазоне от 15 до 50, который есть в наличии, `available: true`. Для этого пишем запрос `bool`, дальше `must`, и в массиве перечисляем условия, которые должны выполниться. Первое — напишем запрос в диапазоне `range` по `price`, и второе — на точное совпадение поля `available` значению `true`.
[музыка]
Выполним запрос. Видим в результате четыре документа, удовлетворяющие данному запросу. Цена каждого из найденных товаров лежит в диапазоне от 15 до 50, а значение `available` у всех `true`.
Рассмотренные примеры поиска лишь верхушка айсберга всех возможностей Elasticsearch. Однако полный обзор синтаксиса и особенностей поиска заслуживает отдельного ролика. А нам пока хватит и этих примеров для того, чтобы посмотреть, как Elasticsearch работает на практике.
Пример на реальном проекте. Теперь давайте рассмотрим, как работает Elasticsearch на примере веб-приложения. Elasticsearch не привязан к какому-то конкретному языку или фреймворку. Ваше приложение может быть написано на любом языке программирования. Мы же здесь рассмотрим возможности Elasticsearch на примере Spring Boot приложения на Java. В качестве примера реализуем приложение для поиска фильмов, что-то наподобие КиноПоиска или IMDb. А из функционала ограничимся только непосредственно поиском. Всё наше приложение будет состоять из одной главной веб-страницы со строкой поиска. Пользователи могут написать и отправить поисковый запрос, а в ответ будут возвращены фильмы, удовлетворяющие критериям поиска. Мы будем выводить название и описание фильма, рейтинг, состав актёров и обложку.
Давайте рассмотрим такое приложение сначала без использования Elasticsearch. Поиск организуем средствами базы данных, а затем подключим Elasticsearch и посмотрим, как это преобразует наше приложение.
Без использования Elasticsearch архитектурно наше приложение выглядит достаточно просто. У нас есть контроллер с двумя endpoint'ами: endpoint по корневому пути просто возвращает пустую заглавную страницу со строкой поиска, а endpoint `/search` обрабатывает поисковые запросы. Он получает из сервиса список фильмов, удовлетворяющих условиям поиска, и передаёт эти данные в модель для отрисовки на всё той же странице с поисковой строкой. Метод `searchMovies` совсем простой. Он просто обращается к репозиторию для поиска соответствующих фильмов. Репозиторий производит поиск фильмов непосредственно в базе данных с помощью такого SQL-запроса: `SELECT * FROM movies WHERE LOWER(title) LIKE LOWER('%' || :query || '%') OR LOWER(description) LIKE LOWER('%' || :query || '%') ORDER BY rating DESC`. А мы приводим всё к нижнему регистру и ищем по прямому вхождению поисковой строки в названии фильма или его описании. Мы не знаем, как правильно аранжировать результаты такого поиска, поэтому сортировать будем по убыванию рейтинга. Модель данных `Movie` представляет из себя обычный POJO-объект с нужными нам полями. Это весь код нашего приложения. Есть также скрипты. За основу я взял топ-250 фильмов КиноПоиска, а также HTML-шаблон нашей страницы, но там ничего интересного нет. Для упаковки данного приложения в контейнер используется `jib`-плагин, подключенный в `pom.xml`, а запуск этого контейнера с необходимыми ему сервисами — базой данных и Elasticsearch — осуществляется с помощью `docker-compose`. На всём этом я не застрял внимание, так как это сейчас неважно, а ссылку на репозиторий с кодом вы найдёте в описании к видео.
Давайте упакуем наше приложение. Пишем `mvn clean compile jib dockerBuild` и запустим его командой `docker-compose up`. Сейчас нам не нужно поднимать сервис Elasticsearch, так как в этой версии приложение он никак не используется, поэтому поднимем только само приложение и базу данных. Пишем `app` и `db`. Для первого запуска потребуется время, чтобы скачать недостающие образы. Видим, что приложение запущено. Давайте перейдём в браузер и посмотрим на него. Перейдём на `localhost:8080`. Видим заглавную страницу сайта с поисковой строкой. Давайте рассмотрим различные поисковые запросы. Начнём с такого: `один`. Видим, что найдено 47 фильмов. Первая выдача — "Список Шиндлера". В описании фильма есть цифра "1" в числе "1.00", поэтому наш наивный поиск вернул этот фильм. Дальше видим "1+1" — вполне релевантная выдача. И дальше видим множество других фильмов, где "один" просто встречается в тексте, и это не то, что мы бы ожидали найти.
Давайте напишем "кукушка". Фильмов со словом "кукушка" в названии или описании нет, поэтому мы ничего не находим. Давайте попробуем "зелёный". Видим в результате поиска два фильма. В каждом из них слово "зелёный" встречается в описании, так что эти фильмы нам подходят. Однако наш наивный поиск не может найти фильмы "Зелёная миля" или "Зелёная книга", так как слово "зелёный" там в другой форме. Давайте попробуем поискать фильм по слову "брат". Тут видим, что нашлось аж 26 фильмов. Однако релевантность выдачи оставляет желать лучшего. В описании некоторых фильмов присутствует слово "брат", однако это всё же не то, что нам нужно. А фильм "Начало" попал к нам в выдачу, потому что в описании есть слово "обратное", а "Бриллиантовая рука" содержит слово "забрать". И напоследок, давайте попробуем поискать фильмы про шестидесятые и восьмидесятые годы. Допустим, у нас настроение посмотреть что-то про те времена. Пишем `1960 1980`. По такому запросу мы ничего не находим.
Как видим, в целом поиск работает, однако его качество оставляет желать лучшего. Остановим наше приложение и изменим его логику на такую, где поиск по поисковому запросу будет осуществляться с помощью Elasticsearch, а уже по найденным документам в нём мы будем получать данные из базы данных по их ID. Эта логика реализована в ветке `elasticsearch`. Давайте переключимся на неё: `git switch elasticsearch` и посмотрим, как наше приложение выглядит сейчас. У нас появились дополнительный служебный контроллер и сервис — `reindexController` и `reindexService`. Они нужны нам для первичной индексации всех документов. При вызове метода `reindexAllMovies` мы вытаскиваем все фильмы из базы данных и отправляем их в поисковый индекс. Основной контроллер практически не изменился. В нём поменялась только одна строка: вместо поиска фильмов старым методом мы вызываем новый метод `searchMoviesViaElastic`. Давайте взглянем на него. В нём первым делом мы идём в Elasticsearch с нашим поисковым запросом. Дальше составляем мапу между ID фильма и его позицией выдачи эластика для последующей сортировки записей из базы данных. Ну и непосредственно получаем наши фильмы по ID из базы данных и сортируем в соответствии с выдачей Elasticsearch. Самое интересное здесь кроется в `ElasticsearchRepository` в методе `searchByQuery`. Давайте взглянем на него. Этот метод формирует такой поисковый запрос Elasticsearch. В запросе сначала ищется наиболее релевантные документы по ключевым словам в обоих полях. Вес у названия фильма выше, чем у описания. Затем усиливает результаты, где найдены точные фразы в названии и описании, чтобы такие документы получили более высокий вес. Это лишь один из возможных запросов. Вы можете самостоятельно настраивать и пробовать собственный модели поиска, проверяя гипотезы, каким полям присвоить больший вес, каким меньший, а какие лучше игнорировать.
Давайте пересоберём наше приложение и запустим снова. Перейдём в консоль: `mvn clean compile jib dockerBuild` и запустим тут. Теперь понадобятся все компоненты, поэтому пишем просто `docker-compose up`. Видим, приложение запущено. Давайте перейдём в браузер и попробуем все те же запросы, что и в прошлый раз. Пишем `один`. Видим пустую выдачу. Это связано с тем, что мы не проиндексировали наши документы в поисковом индексе. Сейчас пусто. Но мы это предусмотрели и создали endpoint, который занимается переиндексацией, забирает все фильмы из базы данных и отправляет их в эластик. Давайте запустим эту переиндексацию. Пишем `reindex`. Видим, что переиндексация завершена. Всё прошло достаточно быстро, но и фильмов в нашей базе данных не так много. Вернёмся к поиску и повторим запрос. Видим, под критерий поиска попадают три фильма. Первым мы видим "1+1", как и хотелось, так как "один" встречается в названии, а мы в нашем запросе такому совпадению продаём больший вес. Дальше идёт "12 разгневанных мужчин", тут в описании есть распределение голосов "11:1", и фильм "Гонка" про Формулу-1, собственно "один" встречается как раз в названии гонки Формулы-1. Никаких случайных фильмов, в которых просто где-то встречается "один", как в наивном поиске, у нас нет.
Следующий запрос: "кукушка". Теперь мы нашли фильм "Пролетая над гнездом кукушки". Слово "кукушка" в изначальном виде отсутствует в названии фильма, но Elasticsearch произвёл стемминг обоих слов, так что конкретные формы слов не влияют на выдачу. Дальше введём "зелёный". Теперь в топе у нас "Зелёная миля" и "Зелёная книга". Эти фильмы совсем отсутствовали в первой версии нашего поиска. Теперь же с этим всё ок. И также, как и в прошлой версии, есть "Шрек" и "Запах женщины".
Попробуем "брат". Теперь выдача выглядит так, как надо. Первыми попадает выдача фильмов "Брат" и "Брат 2", так как в нашем поиске название имеет больший вес, чем описание. А дальше идут фильмы, где в описании также присутствует "брат", притом видим, что это "Американская история X" или "Человек дождя", то есть фильмы, где сюжет в значительной степени завязан на теме братьев, а случайным вхождением по частям слов, как это было в прошлый раз, нет.
Ну и запрос `1960-1980`. Здесь видим фильмы про шестидесятые и восьмидесятые годы. Тут и "Лицо со шрамом", и "Зелёная книга", и "Услуга". Как видим, во всех этих примерах точность и релевантность поиска в случае использования Elasticsearch значительно превосходит уровень поиска, основанного на обычном поиске в базе данных.
Это был Elasticsearch за 30 минут. Здесь мы рассмотрели основы Elasticsearch. Однако осталось множество тем, которые не были раскрыты: полные возможности поиска, ранжирования, а также обзор ELK-стека, частью которого является Эластик. Эти темы требуют отдельного, более глубокого рассмотрения. Если вам понравилось это видео и хочется продолжения, то ставьте лайки и напишите об этом в комментариях. Как всегда, спасибо за просмотр и до встречи в следующем видео!