Шпаргалка по проектированию системы: ElasticSearch
Что такое Поиск и почему он так важен?
Если Вы уже читали мои предыдущие статьи о поиске, то знаете, насколько критичен поиск для любого приложения. Подумайте сами: у всех различных веб-приложений и мобильных приложений, которыми Вы пользуетесь каждый день, будь то Netflix, Amazon, Swiggy и т. д., есть одна общая черта, а именно поисковая строка, которая всегда находится на главной странице в самом верху. Если Вы проектируете какую-либо систему, в девяносто девяти случаях из ста Вы в первую очередь будете думать о том, как обеспечить эффективный поиск.
Построение поисковой системы - дело непростое, где наверняка может пригодится ElasticSearch. Если Вы ничего не знаете о том, как работают поисковые или рекомендательные системы, эта статья станет для Вас настоящим открытием. Мы обсудим, что такое ElasticSearch, где он работает, а где нет, а также рассмотрим три распространенные схемы, в которых используется ElasticSearch. Есть еще много других важных атрибутов поисковой системы, о которых мы обязательно поговори чуть позже.
Что такое ElasticSearch?
ElasticSearch - это популярная база данных, которая делает то, с чем большинство баз данных не справляется: Поиск. Поиск настолько важен для ElasticSearch, что это прописано прямо в его названии!
Если Вы еще не слышали об ElasticSearch, то, вероятно, задаетесь вопросоме: почему поиск так сложен? Почему реляционная база данных не может выполнять поиск? Ведь большинство реляционных баз данных поддерживают различные способы поиска и фильтрации данных, такие как запрос WHERE, ключевое слово LIKE или индексы. Даже в MongoDB можно писать запросы на поиск данных…
Чтобы понять ответ, представьте, что Вы создаете новостной сайт. Когда пользователь ищет новости с помощью Вашей строки поиска, возможно, по запросу «COVID19 в Нью-Дели», его интересуют все статьи, в которых говорится о COVID в Нью-Дели. В простой поисковой системе это означало бы сканирование всех статей в базе данных и возвращение тех, которые содержат слова «COVID19» или «Нью-Дели». С реляционной базой данных так не получится. Реляционная база данных позволит Вам искать статьи по определенным признакам, например, статьи, написанные определенным автором, статьи, опубликованные сегодня, и т. д., но она не может (по крайней мере, не может делать это эффективно) выполнять поиск, при котором сканируется каждая новостная статья (обычно их десятки миллионов) и возвращаются те, которые содержат определенные слова.
Кроме того, нужно учитывать еще множество тонкостей. Как Вы оцениваете эти статьи? Может быть, есть статья о распространении COVID19, а может быть, есть статья о новых инфекциях, как определить, какая из них более релевантна запросу пользователя, или, другими словами, как Вы сортируете эти статьи по релевантности?
Ответ прост: ElasticSearch! ElasticSearch может делать все это и многое другое прямо из коробки.
Но, как и все остальное в этом мире, у него есть свои недостатки. Давайте обсудим, что такое ElasticSearch, когда его стоит использовать и, самое главное, когда нет.
ElasticSearch - Возможности поиска
ElasticSearch предоставляет возможность выполнять «полнотекстовый поиск». Под полнотекстовым поиском понимается поиск фразы или слова в огромной базе документов. Продолжим наш предыдущий пример: представьте, что Вы создаете новостной сайт, содержащий миллионы новостных статей. Каждая статья содержит некоторые данные, такие как заголовок, подзаголовок, содержание статьи, время ее публикации и т. д. В контексте ElasticSearch каждая статья хранится в виде JSON-документа.
Вы можете загрузить все эти документы в ElasticSearch, а затем за несколько миллисекунд выполнить поиск по определенным словам или фразам. Так, если Вы загрузите все новостные статьи, а затем выполните поиск «COVID19 в Дели», ElasticSearch вернет все статьи, в которых есть слова «COVID19» или «Дели».
Чтобы продемонстрировать поиск в ElasticSearch, давайте настроим Elasticsearch и загрузим в него некоторые данные. Для этой статьи я буду использовать набор данных News, который
я нашел на Kaggle (Misra, Rishabh, “News Category Dataset.” arXiv preprint arXiv:2209.11429 (2022)) (Источник) (Лицензия). Набор данных довольно прост, он содержит около 210 000 новостных статей с х заголовками, краткими описаниями, авторами и некоторыми другими полями, которые нас не очень интересуют. На самом деле нам не нужны все 210 000 документов, поэтому в ES я загружу только 10 000 документов и начну поиск.
Вот несколько примеров документов из этого набора данных —
[
{
"link": "https://www.huffpost.com/entry/new-york-city-board-of-elections-mess_n_60de223ee4b094dd26898361",
"headline": "Why New York City’s Board Of Elections Is A Mess",
"short_description": "“There’s a fundamental problem having partisan boards of elections,” said a New York elections attorney.",
"category": "POLITICS",
"authors": "Daniel Marans",
"country": "IN",
"timestamp": 1689878099
},
....
]
Каждый документ представляет собой новостную статью. Каждая статья содержит ссылку, заголовок, краткое описание, категорию, авторов, страну (случайные значения, добавленные мной) и временную метку (опять же случайные значения, добавленные мной).
Запросы Elasticsearch написаны в формате JSON. Вместо того ,чтобы углубляться во всевозможные синтаксисы, которые можно использовать для создания поисковых запросов, давайте начнем с самого простого и будем отталкиваться от него.
Одним из самых простых полнотекстовых запросов является запрос multi_match (не парьтесь по поводу запросов данных в ElasticSearch, это довольно просто, мы поговорим об этом ближе к концу статьи). Идея проста: Вы пишете запрос, а ElasticSearch выполняет полнотекстовый поиск, по сути сканируя все документы в Вашей базе данных, находя те, в которых есть слова, содержащиеся в запросе и присваивая им оценку. Например,
GET news/_search
{
"query": {
"multi_match": {
"query": "COVID19 infections"
}
}
}
По запросу «COVID19» найдено несколько релевантных статей. Вот результаты, которые я получил -
[
{
"_index" : "news",
"_id" : "czrouIsBC1dvdsZHkGkd",
"_score" : 8.842152,
"_source" : {
"link" : "https://www.huffpost.com/entry/china-shanghai-lockdown-coronavirus_n_62599aa1e4b0723f8018b9c2",
"headline" : "Strict Coronavirus Shutdowns In China Continue As Infections Rise",
"short_description" : "Access to Guangzhou, an industrial center of 19 million people near Hong Kong, was suspended this week.",
"category" : "WORLD NEWS",
"authors" : "Joe McDonald, AP",
"country" : "IN",
"timestamp" : 1695106458
}
},
{
"_index" : "news",
"_id" : "ODrouIsBC1dvdsZHlmoc",
"_score" : 8.064016,
"_source" : {
"link" : "https://www.huffpost.com/entry/who-covid-19-pandemic-report_n_6228912fe4b07e948aed68f9",
"headline" : "COVID-19 Cases, Deaths Continue To Drop Globally, WHO Says",
"short_description" : "The World Health Organization said new infections declined by 5 percent in the last week, continuing the downward trend in COVID-19 infections globally.",
"category" : "WORLD NEWS",
"authors" : "",
"country" : "US",
"timestamp" : 1695263499
}
},
....
]
Как видете, он возвращает документы, в которых обсуждаются инфекции COVID19. Кроме того, докменты отсортированы в порядке релевантности (поле _score показывает, насколько релевантен тот или иной документ).
ElasticSearch имеет богатый язык запросов с множеством функций, но пока достаточно знать только то, что построить простую систему поиска очень легко: достаточно загрузить все данные в ElasticSearch и использовать простой запрос, который мы обсуждали ранее. У нас есть множество возможностей для улучшения, настройки и регулировки производительности и релевантности поиска (напомню, подробнее о поисковых запросах - в конце этого поста).
Распределенная архитектура
ElasticSearch работает как распределенная база данных. Это означает, что в одном кластере ElasticSearch есть несколько узлов. Если один узел становится недоступным или выходит из строя, , другие узлы берут на себя дополнительную нагрузку и продолжают обслуживать запросы пользователей. Таким образом, несколько узлов способствуют повышению доступности системы.
Несколько узлов также помогают масштабировать системы, данные и пользовательские запросы могут быть разделены между этими узлами, что приводит к снижению нагрузки на каждый узел. Например, если Вы собираетесь хранить 100 миллионов новостных статей в ElasticSearch, Вы можете разделить эти данные на несколько узлов, причем на каждом узле будет храниться определенный набор статей. Сделать это довольно просто, ведь ElasticSearch поставляется со специальными встроенными функциями.
Масштабируемость
ElasticSearch масштабируется горизонтально и может разделять данные между несколькими узлами. Это означает, что Вы всегда можете повысить производительность запросов, добавив несколько узлов в кластер ElasticSearch.
Однако архитектура кластера ElasticSearch требует гораздо большего внимания, чем просто установка дополнительных серверов. Существуют различные типы узлов, на этих узлах выполняются процессы, называемые «шардами», и каждый шард, узел, может иметь несколько типов и вариантов конфигурации.
В двух словах: для масштабирования кластера и повышения производительности Вы можете добавить больше машин, между которыми впоследствии будут распределены данные и запросы. Это обеспечивает лучшую производительность и высокую масштабируемость системы.
Моделирование данных на основе документов
ElasticSearch - это база данных документов, которая хранит данные в формате JSON, подобно MongoDB. Так, в нашем примере каждая новостная статья хранится в кластере в виде JSON-документа.
Анализ данных в режиме реального времени
Анализ данных в режиме реального времени - это наблюдение за действиями пользователей в режиме реального времени и понимание моделей их поведения. Мы можем составить график поведения пользователей и лучше понять их, что позволит улучшить наш продукт. Например, допустим, мы измеряем каждый клик, событие прокрутки и время чтения на нашем новостном сайте. Мы наносим эти показатели на дашборд и наблюдаем за ними в течение нескольких дней. С помощью этого мы можем собрать множество полезных сведений для улучшения нашего новостного приложения. Мы выяснили, что пользователи обычно пользуются сайтом в 9-10 часов утра, а также выяснили, что пользователи обычно нажимают на статьи, которые имеют отношение к их стране. Используя эту информацию, мы можем увеличить количество ресурсов в пиковое время (9-10 утра) и, возможно, показывать статьи из страны пользователя на его домашней странице.
Elasticsearch подходит для анализа данных в реальном времени благодаря своей распределенной архитектуре и мощным поисковым возможностям. При работе с данными в реальном времени, такими как журналы, метрики или обновления социальных сетей, Elasticsearch эффективно индексирует и хранит эту информацию. Благодаря индексированию в режиме, близком к реальному времени, поиск по данным осуществляется практически мгновенно сразу же после их получения. ElasticSearch также хорошо работает и с другими инструментами, такими как Kibana для визуализации или Logstash и Beats для сбора метрик.
В конце статьи мы рассмотрим архитектуру, которая способствует всему этому.
Затраты
ElasticSearch дорог в эксплуатации и обслуживании. Как и все в этом мире, за все хорошее приходится платить. Для выполнения полнотекстового поиска ElasticSearch хранит большой объем данных в оперативной памяти и строит сложные индексы. Это означает, что для его работы требуется много оперативной памяти, а это дорого.
Короче говоря, он обеспечивает потрясающую производительность при выполнении полнотекстового поиска, но стоит недешево.
Когда ElasticSearch бесполезен
Поддержка ACID
ElasticSearch, как и большинство баз данных NoSQL, имеет очень ограниченную поддержку ACID, поэтому, если Вам нужна поддержка транзакций, ElasticSearch точно не Ваш вариант. Следствием этого является то, что если Вы вставляете документ (в ElasticSearch это называется «индексированием» документа) в ElasticSearch, он может быть доступен другим узлам не сразу, и может пройти несколько миллисекунд, прежде чем он станет виден им.
Допустим,Вы создаете банковскую систему; если пользователь кладет деньги на свой счет, Вы хотите, чтобы эти данные были видны мгновенно для всех остальных транзакций, которые совершает пользователь. С другой стороны, если Вы используете ElasticSearch для обеспечения поиска на Вашем новостном сайте при публикации новой статьи, то, вероятно, вполне допустимо, чтобы в течение первых нескольких миллисекунд статья не будет видна всем пользователям.
Сложные операторы join
ElasticSearch не поддерживает операции JOIN или отношения между различными таблицами. Если Вы уже пользовались реляционными базами данных, это может Вас немного шокировать, но большинство баз данных NoSQL имеют ограниченную поддержку этих типов операций.
Если Вы хотите выполнять JOIN или использовать внешние ключи для связанных структурированных данных, ElasticSearch может не оправдать Ваши ожидания.
Небольшой набор данных или слишком простые запросы
ElasticSearch - система сложная и дорогостоящая. Запуск и управление большим кластером ElasticSearch требует не только знаний и навыков инженеров-программистов и инженеров DevOps, но даже привлечения работников, специализирующихся на управлении и архитектуре кластеров ElasticSearch, называемых «архитекторами ElasticSearch». Существует множество вариантов конфигурации и архитектурных решений, с которыми можно поиграть, и каждый из них оказывает значительное влияние на запросы и всасывание данных, тем самым косвенно влияя на пользовательский опыт в основных потоках системы.
Если Вы хотите выполнять простые запросы или иметь относительно небольшой объем данных, то лучше выбрать БД попроще.
Как вписать ElasticSearch в дизайн Вашей системы
Для одной системы обычно требуется несколько баз данных, каждая из которых обеспечивает работу различных функций. Давайте рассмотрим пример, чтобы лучше понять возможности использования ElasticSearch.
Допустим, Вы хотите создать сервис потокового видео, что-то вроде Netflix.
Как поисковая система:
Очень часто ElasticSearch используется в качестве вторичной базы данных, обеспечивающей выполнение полнотекстовых поисковых запросов. Это очень полезно для нашего приложения для потокового видео. Мы не можем хранить видео в ElasticSearch, и мы, вероятно, не хотим хранить в ElasticSearch данные, связанные с биллингом или пользователями.
Для этого у нас могут быть другие базы данных, но мы можем хранить названия фильмов, их описание, жанры, рейтинги и т. д. именно в ElasticSearch.
Тогда наша архитектура будет выглядеть так:
Мы можем поместить в ElasticSearch данные, по которым хотим организовать полнотекстовый поиск. Когда пользователь выполняет операцию поиска, мы можем запросить кластер ElasticSearch. Таким образом, мы получаем возможности полнотекстового поиска в ElasticSearch, а когда нам нужно обновить информацию о пользователе, мы можем выполнить эти обновления в нашем основном хранилище.
Как конвейер анализа данных, работающий в режиме реального времени:
Как мы уже говорили ранее, понимание моделей поведения пользователей - важный шаг в принятии решения о том, как развивать продукт дальше. Мы можем публиковать события, такие как события потока кликов и события прокрутки, чтобы лучше понять, как пользователи используют наш продукт.
Например, в нашем приложении для потокового видео мы можем публиковать событие с данными о пользователе и фильме всякий раз, когда пользователь нажимает на фильм или передачу. Затем мы можем анализировать и строить графики для того, чтобы лучше понять, как именно пользователи используют наш продукт. Например, мы можем заметить, что пользователи чаще используют наш продукт вечером, чем днем, или что пользователи могут предпочитать передачи или фильмы на своем родном языке, а не на других языках. Исходя из этого, мы можем разработать наш продукт так, чтобы улучшить качество обслуживания пользователей.
Вот как выглядит базовая система для анализа данных в реальном времени с использованием ElasticSearch и Kibana (инструмент для создания дашбордов, который хорошо работает в комплексе с ElasticSearch):
Как система рекомендаций:
В ElasticSearch можно создавать запросы, в которых определенным атрибутам будет отдаваться большее предпочтение (так называемый boosting). Например, вместо простого запроса с помощью ElasticSearch мы можем создавать базовые рекомендательные системы. Мы можем хранить информацию о пользователе, такую как его страна, возраст, предпочтения и т. д., и генерировать запросы, чтобы получить популярные фильмы или сериалы для этого пользователя.
Заключение
Как проектировать кластеры ElasticSearch?
Создание кластера ElasticSearch - задача непростая, требующая знаний об узлах, шардах, индексах и о том, как все это организовать. Существует почти бесконечное количество вариантов архитектуры, кроме того, эта область постоянно развивается (особенно с ростом популярности искусственного интеллекта и поиска на его основе).
Поисковые запросы и совершенствование поисковых систем
Поиск - сложная штука, очень сложная. Существует множество способов улучшить поисковые системы, сделать их более мощными. Одним из них является ElasticSearch. В этой статья я немного пролил свет на то, что он из себя представляет. Не бросайте обучение этой теме, продолжайте копать глубже.
Поиск с учетом контекста
Недавно я прочитал замечательную историю о поисковых системах. Вы можете представить себе поисковую систему, которую мы обсуждали до сих пор, как механический, жесткий поиск. Когда пользователь вводит слово, мы находим все документы, в которых это слово встречается, и возвращаем их.
Или Вы можете думать о поисковой системе как о библиотекаре. Когда пользователь задает вопрос, скажем, «Какова была роль Уинстона Черчилля во Второй мировой войне?», библиотекарь не просто предлагает ему книги, в которых есть слова «Уинстон», «Черчилль» или «Вторая мировая война». Вместо этого библиотекарь оценивает и понимает клиента и его контекст. Может быть, это школьник, и вместо того, чтобы порекомендовать огромный учебник, она найдет книгу, более подходящую для ребенка помладше. А может, у нее нет ни одной книги с названием «Уинстон Черчилль», тогда она найдет книгу о Второй мировой войне или британских премьер-министрах и порекомендует ее. Библиотекарь может даже порекомендовать разные книги для экзаменов или для домашнего задания на летние каникулы (в некоторых странах на летние каникулы задают огромный список литературы).
Мы это понимаем, но как наша система узнает, что Уинстон Черчилль был британским премьер-министром, и порекомендует книги о Великобритании во время Второй мировой войны, или как наша система поймет контекст обсуждения, поймет пользователя и порекомендует книги, подходящие именно ему?
Все не так сложно, как кажется на первый взгляд. Это называется семантическим поиском, и именно так строят свои поисковые системы большинство крупных технологических компаний.
Семантический поиск - это набор поисковых технологий, направленных на понимание смысла пользовательских запросов и контекста контента, что позволяет получать более точные и контекстуально релевантные результаты поиска, учитывая взаимосвязи между словами и намерения, стоящие за поиском.






