Как стать автором
Обновить

Комментарии 45

в рамках решения моей задачи — использование Neo4j никаких плюсов не дало

Потому-что ваши данные реляцыонные и отнюдь не графовые. Представление характеристик товаров графом не совсем корректно, и обогнать MySQL в таких задачах достаточно трудно.

Намного интереснее было бы увидеть как раз построение запросов типа:
«Выбрать контакты пользователей, которые лайкнули киноактерам, которые снялись в фильмах, в которых звучали саунтдтреки, которые были написаны музыкантами, которым я поставил лайк»


Потому-что ваши данные реляцыонные и отнюдь не графовые. Представление характеристик товаров графом не совсем корректно, и обогнать MySQL в таких задачах достаточно трудно.

Я представлял в виде графа не характеристики товаров, а соответствие критериям фильтрации. Критерии далеко не всегда тривиальные, иногда 1 чекбокс в фильтре — это проверка значений у 5 параметров товара. Там JOIN'ится очень много всего — финальные SQL запросы получаются очень громоздкими.
Финальное решение, конечно, очевидное — создать простую связь между критерием и товаром (подходит\не подходит), но мне оно пришло в голову только после использования Neo4j.
В рамках текущего проекта у меня не получилось придумать применение для Neo4j — поэтому оформил в виде конспекта для себя «на потом».

Намного интереснее было бы увидеть как раз построение запросов типа:
«Выбрать контакты пользователей, которые лайкнули киноактерам, которые снялись в фильмах, в которых звучали саунтдтреки, которые были написаны музыкантами, которым я поставил лайк»

По идее, примерно так
MATCH (me:User {userId:123})-[:Like]->(musicants:User)-[:Author]->(s:Soundtrack)-[:Used]->(f:Film)<-[:Starred]-(actor: User)<-[:Like]-(u:User) RETURN u
Задача поиска товара по группе фильтров — класическая задача для search engine а не database engine. Советую посмотреть в сторону elasticsearch:
www.elasticsearch.org/

Вот в частности решение одного из описанных кейсов для магазина: www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets.html

Интеграция elasticsearch в Symfony + Doctrine — github.com/FriendsOfSymfony/FOSElasticaBundle
Просмотрел ссылку на документацию по ElasticSearch facets. Насколько я понял, вы предлагаете использовать facet'ы для критериев? Примерно, как теги в примере.

Тогда у меня вопрос. Можно ли с помощью Facet'ов сделать запрос на поиск наподобие — найти статьи, у которых (есть тег1 И (есть тег2 ИЛИ есть тег3) И (есть тег4 ИЛИ есть тег 5 ИЛИ есть тег 6))?
Не совсем так. Faceted search — это целое направление — en.wikipedia.org/wiki/Faceted_search.
В elasticsearch искать можно по многим критериям. Подробнее можно почитать здесь www.elasticsearch.org/guide/en/elasticsearch/reference/current/search.html (общая информация о поиске и его типах) и здесь www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-queries.html (собственно часть возможностей поиска)

Также думаю будет полезно ознакомиться с этими статьями на хабре:
habrahabr.ru/company/mailru/blog/213849/
habrahabr.ru/post/122531/
Поддерживаю, в своем проекте работу с каталогом решили с помощью Elastic Search. Скорость и легкость масштабирования просто радует. Есть конечно нюансы, но они перекрываются полосами. Отмечу что документация на сайте не очень хорошая поэтому сразу предлагаю читать книгу Mastering Elastic Search. Там есть все ответы на ваши вопросы.
А это разве не самый обычный фасетный поиск, который легко реализуется на основе практически любого поискового движка?
К примеру, как говорили люди выше: elasticsearch
Я для примерно тех же целей использую NOSQL базу, конкретнее монгу. Ей все равно на структуру записи, и в то же время, искать по фильтрам и критериям очень просто.
главный (для меня) вопрос — это скорость выборки при поиске в базе Mongo из, например, 100.000 товаров, у каждого по 500 атрибутов (строковых\перечисляемых\числовых). По случайной комбинации из 20 параметров перемешанных через AND/OR. Именно это и планирую протестировать :)
Отпишитесь о результатах потом. И не забудьте индексы проставить.
У меня на мускуле работает это легко скорость около 0.05 сек на запросах в 20 параметров каши ор и анд
Тоже работает подобное на mysql, правда скорость на порядок меньше и база не очень большая. 0.05 с у вас случайно не по кэшированным запросам? По ним и у меня все быстро работает. Но проблема в том, что на таком кол-во вариантов кэш бессмысленен — слишком много комбинаций параметров.
Как вы храните характеристики в базе? У меня по сути EAV, правда слегка измененный вариант. У меня есть общий справочник характеристик, который к товарам никак не привязан. Непосредственно к товарам привязаны значения характеристик, а по значениям уже сами характеристики. У меня 4 типа характеристик (numeric, boolean, select, multiselect), по каждому свой запрос приходится делать. Надо наверное в отдельном посте это расписать :)
habrahabr.ru/post/45935/ примерно как описывал так и делал, EAV расширен тем, что string, int, float аттрибуты расскиданы по разным таблицам, чтобы были разные индексы, всякие select и multiselect сводятся к int через справочники. Да работает быстро без кеша ибо по бинарному индексу все, учтите так же что, выборка кластеризована по группам товаров и несмотря на то, что в базе ~ 300 000 товаров и 6 000 000 аттрибутов в каждой отдельной категории товаров обычно менее 10000 товаров и менее 200 000 аттрибутов и это радикально облегчает выборку. Короче делаем все по прямому индексу, ставим конечно памяти на сервер 16 гб и SSD диск, но на этом тюнинг кончается =)

Вообще все эти NoSQL для реляционных данных от безграмотности.
Select/Multiselect естественно тоже через справочники. А вот атрибуты по типам не раскидывал. А что это даст? Раз по каждому типу все равно идет отдельный запрос, то лучше вынести их в отдельные таблицы, чтобы поиск шел по меньшему кол-ву записей?

Ну и еще у меня обычный VDS за 1000р. в месяц, может в этом дело? :)
да, во все серьезные проекты я беру нормальные сервера.
UPD.
Изначально я задал разделение по типам потому что полагал, что хранить число в строке и вести по ним поиск — кощунственно, потому создаем 3 таблицы.
Глянул вашу статью. Ну так у меня поля все числовые, я строки не храню. Есть столбец value для boolean и numeric, есть столбец variant_id для select/multiselect (multiselect использует еще и value=0/1). Строковые характеристики отсутствуют как класс, нефиг — для порядку )) Правда value у меня float, наверное нехорошо…
не… MySQL в одном join с одной таблицы может использовать только один индекс, то есть если у вас в таблице аттрибутов 2 столбца: variant_id и value то индекс будет использоваться только по одному из них даже если он мультиколоночный по понятным причинам (там же нет подчинения связи variant_id и value) поэтому лучше делать больше таблиц, джойн на каждую будет использовать ее личный индекс — это позволяет искать все по индексам без переборов вообще
Кстати, а как вы решили вопрос с числовыми характеристиками, по которым мало вариантов? Ну например, слоты расширения в материнской плате. Их удобно задавать и хранить просто как число, но если вариантов мало, то в форме выводить не слайдер, а чекбоксы. Я пока налету конвертирую число в список значений, получая из базы все уникальные варианты. Похоже это тоже сильно сказывается на производительности, зато можно одной галочкой в настройках переключать вариант отображения по каждой характеристике.
Делаем ровно так же на производительности не сказывается вообще. просто проверьте что ваш запрос на уникальные использует индекс, должно летать.
Я вот все присматриваюсь к MongoDb для решения такой же задачи, и мучает меня вопрос. Из-за чего там достигается такая скорость поиска? Ведь принципиально новых способов повышения производительности в программировании никто не придумал — есть только два способа — платить либо ростом вычислительной мощности (распараллеливание), либо ростом хранилища (кэш). Правильно ли я понимаю, что по сути nosql по сравнения с sql — это своего рода кэш за счет денормализации, т.е. вместо лишних джоинов у нас все связанные данные уже есть в документе? Отсюда напрашивается другой вопрос — а как быть с изменениями данных? Если база денормализована, то при изменении связанных данных я должен пройтись по всем документам, где эти данные задействованы?
По сути да. Но это изначально неверный подход, ибо вся суть нерелятивных баз даных как раз в отсутствии отношений. Поэтому при использовании искусственных связей, та же монга начнет очень сильно отставать.
Не очень понял про искусственные связи. Если мне нужен именно справочник характеристик, чтобы в них был порядок, и каждый контент-менеджер не наполнял каталог, как ему вздумается, то связи там довольно очевидны. Само понятия справочника по своей природе «реляционно». Или вы хотите сказать, что не зачем использовать nosql там, где ему не место? В частности для подобного каталога.
Как раз для такой ситуации, когда структура товара не однородна и по ним требуется фильтр, подходят NoSQL решения. Притом на той же MongoDB ваша выборка
(характеристика1 = true AND (характеристика2 < 100)) OR (характеристика1 = false AND (характеристика3 > 17)) ... далее обычно мешанина из AND\OR
делается одной строчкой, со всеми сортировками, поисками по ключу, без каких-либо проблем.
Смотрите вот вы отфильтровали товары. У вас есть еще 50 характеристик по которым можно фильтровать эти отфильтрованные товары. Как вы рассчитаете количество товаров для каждой из этих 50 характеристик в уже отфильтрованных товарах? 50 запросов дополнительных пошлете?

Как сказал товарищ выше это задача search engine, а не database engine.
В монге можно использовать aggregation framework для этого. Скажем, это не самое изящное решение, но, с другой стороны, в ряде случаев оно лучше, чем таскание за собой elasticsearch.

Более того, в некоторых ситуациях, aggregation framework даст больше возможностей.
в ряде случаев оно лучше, чем таскание за собой elasticsearch

Это если в проекте уже используется Mongo. Если нет — добавить что mongo, что elasticsearch одинаково
Я изучал возможность добавления elasticsearch, и если монгу можно использовать для решения различных задач (пускай даже иногда в компромиссном варианте), то elasticsearch в очень многих ситуациях избыточен, особенно для проектов среднего масштаба. Тем более учитывая, что это не универсальный инструмент.
если монгу можно использовать для решения различных задач (пускай даже иногда в компромиссном варианте)
Иногда нужно делать одну задачу хорошо, а не несколько — посредственно
elasticsearch в очень многих ситуациях избыточен
я собственно с этим не спорю.

Обращаю внимание, что я не говорю, что elasticsearch лучше mongo, просто уточнил, что если в проекте используется только mysql, то добавление elasticsearch ничем не отличается от добавления mongo
В монго эт можно сделать одним запросом. Для таких случаев есть Aggregation framework

Если в двух словах объяснять: сначала $match для нужных нам фильтров, $unwind по оставшимся фильтрам, ну а далее стандартный $group на оставшиеся товары.

Как это работает можете посмотреть на примере в этой статье. Ничего против Seach engine не имею, но такие задачи можно решать и через NoSQL
Давайте говорить не в общем NoSQL, а конкретно о MongoDB. Понятие NoSQL все-таки будет пошире. Я очень рад, что в MongoDB есть такой функционал. И мне даже стало интересно, что быстрее будет считать фасеты, MongoDB или Elasticsearch?
Elasticsearch быстрее, aggregation framework — это не самая быстрая часть экосистемы MongoDB. Хотя, опять же, все будет зависеть от размеров, думаю на сравнительно небольших объемах данных разница будет несущественна.
Не плохая тема для статьи на хабре )
У меня вопрос — если взять структуру данных как в примере сможет ли ElasticSearch сделать примерно такую выборку — найти статьи, у которых (есть тег1 И (есть тег2 ИЛИ есть тег3) И (есть тег4 ИЛИ есть тег 5 ИЛИ есть тег 6))?
Да Elastic легко справится с этой задачей.
задача решается элементарно с помощью solr или sphinx
Не сложно будет статейку написать, раз элементарно? Без иронии, вопрос удобной фильтрации товаров очень многим магазинам нужен.
Это нужно писать цикл, сначала как искать, это тоже многим не известно. Затем как искать с использованием facets. На цикл боюсь меня не хватит. Но если вы хоть раз использовали solr, то нужно просто указать facet fields и затем оперировать filters query для уточнения.

Вообщем там все легко, нужно просто один раз сделать :) На статью меня навряд ли хватит.
Если есть возможность — сбросьте мне, пожалуйста, краткие инструкции в виде
Меняем в настройках по умолчанию в solr вот это вот…
Структура базы вот такая вот…
Заполняем тестовую базу вот так вот…
Для выборки по 3 критериям (кр1 AND (кр2 OR кр3)) пишим вот такой вот запрос…

Я проведу тесты и добавлю в статью. Будет интересно добавить Mongo и Solr и сравнить в реальных условиях скорость их работы.
А как в solr вы реализуете вложенную группировку fq с использованием булевых операторов? Или придется в случаях сложной логики фильтрации все в main query писать?
З.Ы. «Как искать» и «как искать с фасетами» знаю. Хотелось бы услышать ваше мнение/решение.
Спасибо за статью… а то подали заявку на доклад

Скажите, граф… Или об использовании NeoJ4 в веб-проекте
devconf.ru/offers/10
теперь понятно что за зверь такой :-)
и вам спасибо на добром слове.

Neo4j забавный зверек. Забавы ради, его вполне можно использовать вместо традиционной СУБД, но реальная польза от этого будет далеко не во всех проектах.
Все тут принялись советовать всякие поисковые движки, которые являются не более чем костылями сверху неполноценных субд, не способных делать хитрые фильтрации за приемлемое время и без монструозных запросов. В итоге у вас получится не одна субд с шардингом, репликацией, транзакциями и прочими плюшками, а две с дополнительными проблемами синхронизации и прочим геморроем.

Я бы рекомендовал посмотреть на OrientDB db-engines.com/en/system/Neo4j%3BOrientDB
Если есть возможность — сбросьте мне, пожалуйста, краткие инструкции в виде
Меняем в настройках по умолчанию в OrientDB вот это вот…
Структура базы вот такая вот…
Заполняем тестовую базу вот так вот…
Для выборки по 3 критериям (кр1 AND (кр2 OR кр3)) пишим вот такой вот запрос…

Я проведу тесты и добавлю в статью. Будет интересно добавить еще Mongo, Solr, OrientDB и сравнить в реальных условиях скорость их работы.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории