В поисках Мяу 😺 - самая симпатичная кошка из каждого города с помощью Elasticsearch

# самый милый кот на город

Факт о кошках: Мяу - одно из самых распространенных имен кошек (по понятным причинам 😸).

Работая над этой статьей, я понял, что есть много людей, которые любят кошек. Существует множество веб-сайтов, предлагающих имена для кошек, например, см. Www.findcatnames.com. Iknowwhereyourcatlives.com - это интересный эксперимент по визуализации данных, в ходе которого обнаруживается выборка из миллиона общедоступных изображений кошек в мире. Честно говоря, это основная причина, по которой я закончил рассмотрение кошек в качестве примера для этой статьи. 😉

Давайте разберемся в самой постановке проблемы:

Найдите самого симпатичного кота по имени Мяу в каждом городе.

В городе было бы много милых кошек. Нам нужно выбрать только по одному симпатичному котику из каждого города, которого зовут Мяу.

Эта постановка задачи является примером типичного запроса наибольшее количество на группу (отсюда и симпатичный кот на город). Интересно, что этот вопрос возникает несколько раз в неделю на StackOverflow. Чтобы быть точным, на момент написания этой статьи было 10 206 вопросов с тегом maximum-n-per-group и подсчетом.

Давайте возьмем небольшой набор данных о кошках с идентификатором столбца, именем кошки, городом и уровнем привлекательности в диапазоне от 1 до 10, причем 10 - самый симпатичный.

Ожидаемый результат для этого набора данных:

Прежде чем переходить к Elasticsearch, давайте посмотрим, как добиться этого с помощью SQL. Есть несколько способов сделать это, в зависимости от базы данных; могут быть и более эффективные решения. Один, который работает с базами данных:

Мы не будем вдаваться в подробности решения SQL, поскольку цель состоит в том, чтобы решить его с помощью Elasticsearch. Тем не менее, не стесняйтесь оставлять комментарий, если вы хотите, чтобы я объяснил что-то конкретное.

Давайте перейдем к Elasticsearch, чтобы решить эту проблему.

Краткое описание Elasticsearch согласно Википедии.

Elasticsearch - поисковая машина на базе библиотеки Lucene. Он предоставляет распределенную, многопользовательскую полнотекстовую поисковую систему с веб-интерфейсом HTTP и документами JSON без схем. Elasticsearch разработан на Java и выпущен как открытый исходный код в соответствии с условиями лицензии Apache.

Было бы неплохо выполнить локальную настройку Elasticsearch и Kibana (необязательно). Если он у вас уже есть, он идеален. Еще я предлагаю установить его, чтобы самому опробовать скрипты. Следуйте инструкциям с официального сайта Elasticsearch, чтобы установить его локально. Или, если это кажется слишком громоздким (на самом деле это не так), вы можете использовать облачные сервисы, такие как Elasticsearch Cloud (14-дневная бесплатная пробная версия, кредитная карта не требуется) или bonsai.io (бесплатный план без кредитной карты). Лично я пробовал bonsai.ai и в течение 5 минут запускал запросы на предоставление Kibana через bonsai.io. Превосходно. 🤓

Даже если это слишком много 🙄, используйте эту площадку для поисковых запросов.

О, и я забыл представить Кибану. Кибана согласно Википедии.

Kibana - панель визуализации данных с открытым исходным кодом для Elasticsearch. Он предоставляет возможности визуализации поверх контента, проиндексированного в кластере Elasticsearch. Пользователи могут создавать гистограммы, линейные диаграммы и точечные диаграммы, а также круговые диаграммы и карты поверх больших объемов данных.

Какой бы вариант вы ни выбрали, давайте начнем с создания нового индекса cat и массового импорта нашего набора данных.

Если вы используете Kibana, просто скопируйте и вставьте запрос ниже, чтобы создать новый индекс cat со свойствами id, name, town & cuteness.

Чтобы выполнить массовый импорт, скопируйте и вставьте образец данных под запросом.

* Все скрипты Elasticsearch протестированы в версии Elasticsearch 7.2.

Чтобы повысить точность, мы изменим решение, чтобы отдать больше предпочтения точному совпадению, чем частичному совпадению, и упорядочить результат по привлекательности.

Во-первых, давайте начнем с поискового запроса, чтобы получить кошек с кличкой мяукать. У нас может быть простой wildcard запрос, но нам также нужно повысить оценку для точного совпадения. Для этого мы будем использовать запрос function_score с двумя функциями (строки 13 и 20 ниже), придавая больший вес точному совпадению. function_score позволяет изменять количество документов, получаемых по запросу. Вот так будет выглядеть наш поисковый запрос:

Теперь давайте посмотрим на агрегатную часть. В Elasticsearch мы можем выполнять агрегирование по поисковому запросу. Есть несколько техник агрегирования. В нашем случае мы будем использовать агрегацию на основе терминов, которая относится к семейству сегментирования. Для лучшего понимания давайте сначала рассмотрим последний запрос. Воспользуйтесь этой ссылкой для запуска и попробуйте сами.

Поскольку нам нужно создать по одному ведру для каждого города, я добавил "field": "town" в терминах агрегирования. Это даст нам несколько кошек в городе, но нам нужны только самые симпатичные, поэтому мы будем использовать субагрегацию. Посмотрите на блок из строки 37 выше. Я добавил две субагрегации group_docs и max_cuteness. group_docs - это агрегирование top_hits, в котором я настроил возвращать только одну сортировку записей на основе привлекательности и оценки поискового запроса. Такое агрегирование поможет создать только одну запись для каждой корзины.

Теперь нам также нужно упорядочить ведра в зависимости от максимальной привлекательности на ведро. Для этого я определил субагрегатор max_cuteness для максимальной агрегации. Он возвращает максимальную привлекательность для города, которую я использую в основном агрегаторе group в строке 34 для упорядочивания каждого сегмента. В строке 2 "size": 0 используется только для возврата агрегированного результата.

Подводя итог, для этого запроса я использовал запрос function_score, terms, top_hits и max агрегации, чтобы решить самую симпатичную проблему -cat-per-town. Спасибо за чтение! Прокомментируйте, если у вас есть какие-либо сомнения или вы чувствуете, что знаете лучший способ «Найди Мяу!»

P.S: Готовы к вызову самый милый кот в городе ? Напишите в Твиттере свое лучшее решение для SQL или Elasticsearch с хэштегом # cutest-cat-per-town, #findingmeow 👨‍💻 или оставьте комментарий ниже. Если мы найдем ваше решение лучше, чем наше, мы включим ваше сообщение вместе с вашим именем. Используйте эту площадку, чтобы протестировать и поделиться своим решением.

Если вам понравилась статья, похлопайте 👏 и помогите другим увидеть ее. Мяу был бы признателен за это 😻 . Подпишитесь на меня, чтобы увидеть другие подобные статьи.