Здравствуйте. Я уже задавал этот вопрос неделю назад на английском языке, но ответа не получил, а он очень нужен. Мне надо составить запрос на агрегирование с фильтрованием.
Дано - есть 3 таблицы базы данных - Объявление, Фильтр и Категория Фильтра (Ad, Filter, FilterCategory соответственно). Версия эластика - 2.3
Ad имеет связь m2m с Filter и с Filter прооброшен fk на FilterCategory. Т.е. у объявления и категории может быть множество фильтров. Объявления проиндексированы в эластик. Вот пример документа с продакшена http://pastebin.com/hY6aneyz
где фильтры объявления обозначены полями - filters_ids, filters_names и filters_slugs
а категории - filter_categories_ids, filter_categories_names и filter_categories_slugs
Надо - отфильтровать и агрегировать объявления по запросу с примерно таким псевдокодом:
WHERE (filter = 'othodyi' OR filter = 'pervichka') AND (category = 'po-forme' AND category = 'po-vidu')
Т.е. у объявления обязательно должны присутствовать все категории и любые из фильтров
Благодарю за быстрый ответ. Запрос работает, но дает не тот результат который я ожидал, поэтому мне придется задать вопрос по-другому.
Мне надо реализовать выборку объявлений по их классификации. Например, если у нас есть такие объявления:
Объявление 1
по-цвету
красный
черный
по-форме
гранула
порошок
крошка
Объявление 2
по-цвету
красный
Объявление 3
по-форме
гранула
крошка
Объявление 4
по-цвету
белый
по-типу
пп
Тогда изначальная выборка по ним будет выглядеть так:
по-форме
гранула 2
крошка 2
порошок 1
по-цвету
красный 2
черный 1
белый 1
по-типу
пп 1
Если юзер выберет "крошка", то "по-форме" не изменится, но "по-цвету" будут только "красный" и "черный" - 1, т.к. только одно объявление соответствует каждому из них, и категория "по-типу" не войдет в выборку. Соответственно мне нужен запрос который это выполнит.
Но если категории не часто обновляются, и их количество не очень большое, то более оптимальное решение было бы создать отдельные поля для каждой категории. Тогда можно было бы обойтись без nested.
А вы проницательны. Да, так можно сделать, но пока из-за особенностей рабочего кода лучше оставить как есть.
А как в таком случае будет выглядеть запрос? Насколько я понимаю, псевдокод будте примерно таким:
WHERE ((classification.category_id=category1 AND classification.filters_slugs=filter1) OR (classification.category_id=category1 AND classification.filters_slugs=filter2)) AND (classification.category_id=category2 AND classification.filters_slugs=filter3)
Боюсь что в Лапландском королевстве все опять не так как надо. Запрос работает и в при выборе фильтров он показывает действительные числа. Проблема с теми фильтрами которые не были выделены и соответственно не вошли в запрос - они "проседают".
Покажу на примере:
стартовая выборка
и здесь мы выбрали несколько фильтров.
У нас действительно 758 объявлений с тегами "белый" и "гранула" и 1819 объявлений с тегами "гранула" и "белый" или "черный". Но например объявлений с "красный" и "гранула" в действительности 62.
Мне надо реализовать этот функционал аналогично заппос , например как на этой странице.
Прочел. Потом заметил что ссылка для 1.7 и прочел ту же статью для 2.3. Я так понимаю вы намекаете на Multi-field terms aggregationedit ? Но я не понимаю какое отношение это имеет к моей проблеме.
Хорошо, тогда я попробую начать с самого начала и подробнее. У нас есть 3 таблицы: "Объявление" с m2m на "Фильтр" с fk на "Категория фильтра".
На работе дали задание сделать фасетную навигацию по объявлениям с учетом того как они отклассифицированы (это фильтры и их категории), по образу популярных коммерческих площадок. Например:
И вот тут-то и начинаются проблемы. Как человек привыкший к sql, я даже не могу точно описать принцип по которому там происходит выборка.
Т.е. в общих словах это действительно "ИЛИ" внутри фасетов и "И" между ними. Но мне не очевидно почему, например у той же техносилы, при выборе пары брендов в мониторах "проседать" начинают другие фасеты, кроме текущего. Я только знаю что это реализовано с использованием эластика или солра.
Запрос который вы мне помогли составить похож на то что мне нужно, но он правильно работает только для выбранных фильтров. Т.е. возвращаясь к предыдущему своему посту, "красный", как я понял, отображает количество объявлений из тех где есть "гранула" и ("белый" или "черный"). А должен отображать количество объявлений где есть "красный" и "гранула", даже при том что "красный" не выделен.
P.S. Про document counts are approximate я знаю и везде где это критично стоит size: 0.
Я все равно не понимаю, что вы хотите. Может быть это? Если нет, вы не могли бы привести какой-нибудь простой пример - вот 10 записей, вот поля в них, вот запрос, вот что я хочу видеть?
запрос_для вытаскивания товаров, фильтры - А, Б, В
глобальная агрегация, сбрасывающая скоуп, в нее попадает все
внутри глобальной агрегации три фильтрующих под-агрегации
одна из них имеет фильтром Б, В (все кроме А), при этом она делает term по A
вторая их них имеет фильтром А, В, при это она делает агрегацию по Б
третья имеет фильтром Б, В, при этом она делает агрегацию по В
итого запрос выглядит примерно так
Q = A, B, C
GA
FA
filter B C
term A
FB
filter A C
term B
FC
filter A B
term C
Итого, допустим у нас 5 документов
док1 = красная большая машина
док2 = красный большой дом
док3 = красный большой квадрат
док4 = красный маленький дом
док5 = желтый большой дом
запрос = красный + большой + дом
глобальная агрегация
агрегация по цвету = ищется в рамках размер + тип
агрегация по размеру = ищется в рамках цвет + тип
агрегация по типу = ищется в рамках цвет + размер
итого, в результате будет
тотал = 1
хит = док2 = красный большой дом
агрегация по цвету = красный (1) + желтый (1) (потому что ищет большие дома)
агрегация по размеру = большой (1) + маленький (1) (потому что ищет красные дома)
агрегация по типу = дом (1) + квадрат (1) (потому что ищет красный + большой)
Apache, Apache Lucene, Apache Hadoop, Hadoop, HDFS and the yellow elephant
logo are trademarks of the
Apache Software Foundation
in the United States and/or other countries.