Pull to refresh

Comments 78

По опыту, на сколько эффективнее выборки MySQL? Или можно как-то объединить: хранение mysql, поиск ES, даст ли это преимущества? Не придумаю никак сравнительный тест.
По опыту: можно в MySQL хранить данные (например, контактные данные миллиона человек), а с помощью ElasticSearch организовать нечёткий поиск по именам, фамилиям, номерам телефонов и т.д. ElasticSearch вернёт идентификатор, поиск по ID в MySQL будет уже быстрым.
Можно не только хранить ID, но и поля этого человека и уже не обращаться к mysql. Я упоминал об этом в статье.
Можно конечно, если нам например нужно вывести какую-то условно «карточку».
Mysql — это надежное хранилище, источник исходных данных, ES — поисковый движок. У них разные задачи.
В большинстве случаев используют Mysql + ES. Бывают случаи, когда не очень важные данные хранят сразу в ES, например логи.
ES может забрать на себя нагрузку на чтение с Mysql, т.е. пишем в Mysql, а читаем из ES. ES горизонтально масштабируется значительно проще, чем mysql, т.к. есть автоматический шардинг.
Надо смотреть на конкретные запросы и вполне возможно, что mysql при выборке по первичному ключу будет быстрее.
Но нужно понимать, что в ES есть значительно больше типов запросов, чем в mysql, например поиск по geo координатам, с помощью плагинов можно сделать поиск по изображениям.
ПС. под mysql тут можно понимать любую реляционную БД.
Спасибо! Нет ли чего почитать по успешной реализации подобной связки? В Ваших публикациях, к сожалению, такого нет :(
З.Ы. только начал вкуривать ES.
Для начала этого урока будет достаточно. Ваше приложение после записи в mysql будет писать данные в ES. Т.е. взаимодействие идет через приложение.
Я советую потом прочитать официальную документацию, она хорошо написана и там есть классные примеры.
Я такое делал на рельсах пару лет назад, получилось весьма интересно, работает до сих пор, нареканий нет. Если интересно в контексте Rails, могу поделиться сниппетами.
Использую связку mysql + elasticsearch для хранения и поиска по закладкам. На приблизительно 500к записей разница получается приблизительно раз в 10-15. Запись ищется в elasticsearch он возвращает id, а далее mysql достает по id саму запись из базы. Сравнение конечно несколько не правильное, ибо в elastic'е используется стемминг, а в mysql просто поиск по like'у, и теоретически можно попытаться настроить лучше. Вопрос в том нужно ли это. По факту писать фильтры через elasticsearch получается удобней. Из минусов elasticsearch любит память.
UFO just landed and posted this here
Используется добрый LIKE '%search%' точнее по факту там чуть похитрее но в целом да ^_^
Match against не использую, ибо иногда приходится искать маленькие слова, а оно их вроде как не любит, по крайней мере раньше не любило :)
UFO just landed and posted this here
ну вот, а еще там стемминг не полноценный :) нет конечно всегда можно вручную преобразовать все слова.
Еще одним из плюсов elasticsearch'а можно посчитать возможность удобно делать фасетный поиск. А еще elasticsearch неплохо может горизонтально масштабироваться. Не уверен что производительность match against тоже так можно поднимать, но это чисто мысли, ибо пол миллиона записей даже с десятком полей это ни о чем практически в любой бд если не косячить.
В общем у всех свои задачи :)
Там где стемминг и фасетный поиск не нужны используется как раз match against, на скорость что характерно жалоб нет. А для закладок использую elastic удобно получается. Так что применимость у всего своя. И если вас все устраивает то внешний поиск действительно не нужен.
Для эластика есть морфологические плагины, которые больше, чем стемминг, например «люди» и «человек» будут приведены к одному и тому же токену. Посмотрите в сторону плагина russian_morphology, например. Хотя в нем встречаются забавные артефакты. Плюс возможность поиска с расстоянием между словами (с количеством перестановок, если точнее) и другие прелести Lucene.
Память бывает разная, но все базы данных так или иначе любят память. Например, сейчас в эластике уже можно настроить использование doc_values для необходимых полей, в этом случае куча уже может использоваться меньше при выполнении запросов, а данные будут маппиться в память и при необходимости выкидваться опять же средствами оси.
у меня сейчас следующая связка фильтров — 'lowercase', 'russian_morphology', 'english_morphology', 'ru_stopwords', 'ru_stemming', человек — люди вполне неплохо отрабатывает. На тему поиска с расстоянием думаю в будущем подкрутить, когда подсказки к запросам буду делать, пока как то не надо. в основном или поиск по словам или фасеты. Да и эластик сейчас староват надо будет обновлять, но для этого же время надо будет выделить чтобы все переписать :)
так у вас же включен russian_morphology ) Уберите его, и человек/люди расползутся в разные токены.
:) а зачем, специально же добавлялось.
правда я предполагал что он все же больше определяет однокоренные слова, то есть такой продвинутый стемминг, так что спасибо за просвещение.
в изначальном комментарии говорилось, что эластик использует стемминг. Я лишь уточнил, что токенизация не ограничивается стеммингом )
Про doc_values могу сказать, что на hdd сильно просаживает индексацию, но память таки да, экономит. На ssd не использовали, но вроде не должно быть такого.
А какая нагрузка индексации и структура кластера? Не замечал заметного снижения производительности при использовании doc_values (как раз-таки на hdd, правда SAS 10K), в моем случае скорость индексации была до 2К/сек (не пиковая, а фактическая), запись производилась на ноды, расположенные на 3 серверах
Тестировали даже не на той версии, что сейчас используем, но всё же тогда надо было решить "брать или не брать". На тестовой машине с ES 2.0 doc_values просадил скорость индексации где-то на 15%, решили тогда отказаться. Сейчас наверно лучше, не знаю.
Кластер большой, к тому же по паре инстансов для обхода "ограничения" размера хипа в 32гб. Скорость 20-25к/с в среднем. Так что суммарно я думаю могло (может и сейчас) сильно просадить индексацию. А ещё сжатие включили, что сейчас оказалось пустой тратой, как мне кажется…
Сейчас уже подумываем взять обратно doc_values, на другом кластере для меньшего объёма данных.
UFO just landed and posted this here
А если в MySQL просто создать индекс по всем нужным полям — это не поможет, потому что у нас в запросе RANGE, или просто памяти займёт слишком много?
У нас ES используется как полноценная БД из-за мастабируемости и распределённого поиска, плюс к этому, за счёт кластера достигается высокая пропускная способность, а также лёгкость добавления ноды. Вроде бы PostgreSQL кластер тоже умеет, но не знаю как у него с вышеперечисленным, не говоря уже про MySQL. Но в ES нет такого мощного SQL, какой он есть в РБД. Так что каждому своё.
Конечно используем РБД, но скорее для вставки из ES для других приложений, которые используют их для своей работы.
Тут нужно быть осторожным, тк ES может потерять данные, особенно в кластерной конфигурации.
https://aphyr.com/posts/317-jepsen-elasticsearch
Я делал перевод статьи по ES как NoSQL базу — https://habrahabr.ru/company/percolator/blog/222765/
Есть даже проект Crate.io. Это что-то вроде sql над es: https://crate.io/a/how-is-crate-data-different-than-elasticsearch/
Postgresql из коробки не умеет кластер, есть PostgresXL но это немного не о том.
А как насчёт 2.х? Мы используем 2.1, а последняя сейчас вообще 2.3.
По поводу sql, то мы используем ES по назначению — поиск документов, поэтому нет потребности в каких-то сложных выборках или джойнах.
Распределенная система подвержена сетевым сбоям и разделению кластера. Что произойдет если кластер разделится на 2 половины и будет происходить запись в обе половины? Это условный пример, и нужно смотреть как ES поведет себя в этой ситуации, наверняка в меньшей части кластера мастер не будет выбран и запись не пойдет.
Я просто хочу обратить внимание, что с распределенными системами не все так просто. И придется чем-то жертвовать.
В сети есть много материалов, тот же Aphyr. Можно погуглить материалы про cap теорему.
Это всё понятно, что оно может так случиться. У нас такого ешё не наблюдал, поэтому не знаю. Но я думаю лучше было бы действительно остановить запись (и тогда сработают всякие сигнализации) и не терять данные, тогда это не будет проблемой. Техническую проблему можно устранить и продолжить запись, а потерянные данные не вернёшь.
Можно в настройках настроить минимальное количество мастеров для функционирования кластера, чтобы избежать сплитбрейна
Мы тоже используем ЕС как полноценную базу данных для документов (в терминах NoSQL). Клиенты и админы очень довольны.
Кстати, ES вместе с Кибаной официально рекомендуются Амазоном. Про предел индексации в 34К в секунду (тот же Кинетик гарантирует 1К в секунду на шард) на ноду тут уже писали.
Почему бы не использовать в качестве базы данных базу данных (mongodb). Насколько я понял из докладов, ЕS, как база данных, во всём ему проигрывает, кроме опций поиска. Мы используем их вместе, хранение в mongodb, поиск — в ES.
Потому что Mongo не Lucene. Нам так надо.
Сейчас уже не совсем правильно называть ES поисковым движком. Это уже больше аналитическая система с широкими возможностями агрегации данных.
Все-таки ES — это поисковый движок, а вот стек ELK — аналитическая система
Подскажите, а какой алгоритм лучше исопльзовать для следующего — есть большой каталог товаров с параметрами, изначально хранится в mysql. Происходит поиск по базе эластика и в ответ выдаётся какой-либо результат (набор товаров). Как организовать постраничную навигацию по результатам? Средствами эластика или передавать коды товаров в sql-запрос и данные для конкретной страницы брать из mysql?
Если наладить хранение документов в эластике целиком, то необходимость во втором запросе в mysql отпадет
ES умеет постраничную выдачу. В этой статье есть секция "Сортировка", в ней используется ключ size.
Так же с помощью Scroll можно избежать проблемы постраничной выдачи, когда между получением страниц происходит вставка. Т.е. мы выбираем первую страницу, в кто-то добавил документ, который мог быть на первой странице, соответственно все документы съедут и последний документ с первой страницы продублируется и встанет на первое место на вторую страницу. А Scroll делает снимок и новый документ в выдачу не попадет. Надеюсь понятно объяснил)
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html
Да, более-менее, спасибо
Использование скроллов для постраничной выдачи пользователю — не очень хорошая идея. Скролл между запросами будет висеть в памяти. А по истечении указанного срока жизни пропадет. Если пользователь «засиделся» на странице, то следующую он может не получить.
Согласен, я упомянул скролл, чтобы просто показать эту возможность.
Только этот скролл медленный тормоз, на больших объемах будете ждать сутками.
Кстати, если в магазине предусмотрены фильтрации по нескольким типам признаков я бы сразу порекомендовал обратить внимание на фасеты в Elastic — просто отличная штука!
В своем сервисе для поиска по товарам магазина успешно используем аггрегацию. Проблемы были только с вложенными структурами (категории), но изменив модель в ES проблема ушла.
У меня такой вопрос: это что же за блог, для индексации которого применяется Elasticsearch? Какая же у вас посещаемость?)
Да это же просто пример на кошечках и собачках)
Не в посещаемости дело, а в возможностях поиска.
Например, wordpress.org, в котором на ES сделан поиск по всем блогам, созданным в системе.
Второй большой проект с высокой нагрузкой и распределённой системой по датацентрам полностью на эластике делаем, 2 года — полёт нормальный. Пришлось многое осознать как правильно всё это готовить, но результат очень приятный, ведь основная суть архитектуры, что независимо какой у тебя объём данных храниться, поиск по ним будет одинакового быстрый из-за распределённости.
Как вы шардируете данные?
Заводите новый индекс, через определенный интервал времени?
Просто на горячую изменить кол-во шардов для индекса невозможно.
Наверняка используете роутинг, т.к. при увеличении кол-ва данных будет падать скорость поиска.
Расскажите, пожалуйста, про "правильную готовку".
Роутинг вводили, потом выводили с трудом. Не везде его можно использовать, он очень сильно привязывает всё к знанию этого самого роута, а не везде это возможно знать изначально в запросе.
Система спроектирована так, что у нас есть версионность и разделение по типам, например users у нас как индекс {company}_users_v{1..999} в нём есть типы admin, operator, engineer, abonent и т.п.
Индексы связаны между собой через alias как {company}_users => {company}_users_*
А как это всё переживает разрыв связи между датацентрами?
Точно так же как и в любом другом кластере, срабатывает failover.
А у вас бывают очень тяжеловесные запросы, которые тормозят всю систему? Мы все никак не можем решить такую проблему: есть запросы пользовательские, которые должны отрабатываться быстро, а есть админские, которые по минуте выполняются. При этом во время выполнения админских запросов весь индекс тормозит. Как бы так понизить приоритет одним запросам, и поднять другим?
Пробовал через preference, и при этом все равно необъяснимо тормозит.
Для начало нужно понять из-за чего именно такое происходит, сделайте explain или лучше profile, чтобы понять на что уходит время. А после уже будет видно в чём проблема и можно подумать над её решением.
Напишите пост про боевое применение Эластика, многим очень интересно будет.)
Объясните мне, дилетанту в области nosql, два момента в отличиях Mongodb, ES и Sphinx:

1. Что лучше использовать для задач фасетного поиска, например для поиска по параметрам товаров интернет-магазина?

2. Есть ли в Mongodb полнотекстовый поиск с учетом русской морфологии и с ранжированием результатов? Если да, то зачем тогда использовать ES и Sphinx? Они реально быстрее?

Давно присматриваюсь к nosql-решениям и никак не могу сделать выбор между Mongodb, ES и Sphinx именно в разрезе этих двух задач: полнотекстовый и фасетный поиски. Интуиция подсказывает выбор в пользу Mongodb как более зрелого, проверенного и быстрого решения. Но это только интуиция.
UFO just landed and posted this here
про эластик ваша информация устарела, это давно уже полноценная nosql БД, имеет свои плюсы и минусы. Данные там потерять можно точно так же как и в любой другой БД, в которой нет транзакций ;)
UFO just landed and posted this here
стоп стоп) вы сами себе противоречите. Если у вас кластер редиса, то проблема будет ровно такой же вы потеряете данные за тот промежуток времени снапошотов, которые установлены в настройках. В эластике всё тоже самое, пишется в одну ноду, потом разноситься по другим, если не успел записать (выдернули свет) они просто потеряются как и в случаи с редисом/монгой. В запросе к эластику на запись можно ожидать записи данных и выставить на эту запись обновления индекса мгновенно без задержки, по умолчанию все записи собираются в pool и раз в секунду переиндексируются.
UFO just landed and posted this here
Если вам нужны фасетки и более-менее нормальная морфология — берите Apache Solr или ElasticSearch. И то, и другое использует поисковый движок Apache Lucene под капотом.

В случае Solr'а при использовании docValues стоит брать 4.10 или подождать 5.6. Или использовать поля с docValues=false, тогда проблемы нет. Если говорить про интернет-магазин, то вариативность данных для каждой из фасеток, скорее всего, небольшая (сотни-тысячи значений), так что требования по памяти для UnInvertedField кэша будут небольшие.

Авторизованные данные, имхо, стоит хранить снаружи (mysql, postgres, mongo — куда лучше лягут по структуре), чтобы иметь возможность переиндексировать, экспериментировать с индексами (например, вкрутить кастомную морфологию) и т. п.

Для нормализации порекомендую попробовать AOT'овскую морфорлогию.
Расскажите, а можно ли в ES делать что-то типа join'а по разным индексам или типам? И как это вообще работает?
Насколько я понимаю, типичный сценарий для ES следующий. Каждый день (или через другой промежуток времени) создается новый индекс, который содержит данные за данный период времени. Допустим, что я сохраняю логи в ES. Получается, что в терминах ES таблица логов — это отдельный тип (type). Теперь допустим, что мне надо в другом типе сохранять какую-то внешнюю информацию (например маппинг между ip адресом и страной, где размещается сервер логов). Для этого, насколько я понимаю, нужно создать новый тип с этими данные. В этом случае мне интересно:
1) как организовать join между двумя типами
2) в случае создания нового индекса, нужно пересоздавать тип маппинга. Как обычно избавляются от избыточной информации в этом случае?
Есть parent-child query. Это аналог join.
Нельзя организовать join между двумя типами, потому что данные могут находиться на разных шардах. Обычно в индекс просто записывается избыточная информация. При создании новых индексов можно использовать шаблоны.
Но в целом, если вы уже взялись за ES, привыкайте к денормализации.
Делать join между несколькими шардами нельзя. Но при индексации можно указать parent и оба документа окажутся на одном шарде.
Конечно. И это не единственный способ — в руководстве рекомендуют выбрать один из четырех: join на стороне приложения, денормализация, вложенные документы и parent-child. Каждый хорош для своих целей, но мне показалось, что для исходной задачи ("например маппинг между ip адресом и страной, где размещается сервер логов") проще всего было бы применить денормализацию.
Отличная «get started» статья получилась у вас!
Прошелся по всем примерам и действительно есть теперь общее представление в первом приближении.

Можете только подсказать момент, какой вообще лучше метод, чтобы загонать данные в индекс для уже существующего приложения (на php-mysql)? Сделать скрипт и поштучно (либо какими-то порциями) закидывать? И потом при редактировании, удалении, добавлении нового уже в своей бизнес логике обращаться к эластику? Либо перепарсивать как-то все периодически. Я слышал про «river», но не особо понял как он работает.
Спасибо!

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

River стал deprecated.
В примеры стоит добавить:
-H 'Content-Type: application/json'
Анализаторы состоят из одного Tokenizer и нескольких необязательных TokenFilters. Tokenizer может предшествовать нескольким CharFilters.

Поправьте меня, если я что-то не так понял, но по логике сначала идет обработка с помощью CharFilters, затем Tokenizer, а потом TokenFilters. То есть сначала обрабатываем строку целиком, потом разбиваем ее на токены, потом обрабатываем токены. В таком случае Tokenizer не предшествует CharFilters, а следует за ними, то есть они ему предшествуют.
Sign up to leave a comment.

Articles