Мой опыт собеседований в Amazon и Zalando

Интервью в IT

За свою карьеру в IT я прошёл несколько десятков собеседований. Некоторые были интересными, но большинство однотипными и скучными. Не на все интервью я хожу обязательно из-за поиска работы. Бывает из любопытства, а иногда для поддержания тонуса и чтобы быть в курсе последних требований рынка. Я ещё помню хайп вокруг появления AJAX и одностраничных приложений. Затем тренд сместился на Big Data, машинное обучение, а сейчас без блокчейна уже и простой калькулятор не разработать. В общем, главное не зевать.

Здесь, пожалуй, нужно сделать отступление и объяснить, что из себя представляет типичное интервью разработчика. На рынке, уже достаточно давно, сложилась интересная ситуация. Несмотря на острый дефицит квалифицированных кадров, бывает, что работу найти не так просто. Многие хотят нанять разработчика уровня Senior(старший), а платить, как за Middle(средний) или Junior(младший). К тому же, как оценить уровень знаний потенциального работника? Тут уже каждый извращается, как может. Кто-то устраивает онлайн тестирование с задачками около олимпиадного уровня. Кто-то предлагает парное программирование — это когда код пишете вместе в каком-нибудь онлайн редакторе. А могут дать сделать тестовое задание. Хорошо ещё, если оно не большое, на пару часов, а то могут предложить задачку на пару дней, а потом даже не ответить. Это, кстати, распространённая проблема — затягивание интервью на несколько недель или даже месяцев, а иногда и отсутствие какой-либо обратной связи. Получаются такие кошки — мышки, где одни пытаются продать себя подороже и не прогадать, а другие оценить, стоит ли кандидат запрашиваемых денег или, в худшем сценарии, договориться так, чтобы платить меньше.

Amazon

Немало ещё зависит и от имени. Известного разработчика многие будут рады видеть и могут легко предложить специальные условия — например, разрешить 50% времени работать на опенсоурс. Аналогично и с компаниями — для многих Гугл, Фейсбук или Амазон — работа мечты. И чтобы попасть туда, люди готовы ходить на многомесячные интервью. Так, один из моих бывших коллег, устроился в Майкрософт после 5-6 этапов, которые суммарно заняли более полугода. Меня же, большие компании, никогда особо не интересовали. Сразу же после института я понимал, что знаний не хватит. Потом уже как-то стало не до того и относительная свобода в «стартапах» не давала крамольным мыслям забраться в голову. Ровно до тех пор, пока однажды, когда я ещё работал в Бразилии, один мой коллега не позвал на выездную сессию на интервью в Амазон. Я тогда отказался, т.к. работу менять не собирался, но мысль, что стоило попробовать просто ради интереса, вертелась. И когда несколько недель назад мне написал рекрутер из Амазона о наборе разработчиков в команду Алексы (голосовой помощник), я решил, что стоит хоть раз посмотреть, как устроены подобные интервью. К тому же, предлагали бесплатную поездку в Гданьск. В Гданьске я уже был пару лет назад на конференции, но город толком рассмотреть не удалось, так что был дополнительный мотиватор :).

Процесс состоял из трёх частей, про которые я и расскажу:

  1. Онлайн задачи.
  2. Вопросы по телефону.
  3. Сессия из 4-х интервью в Гданьске.

Онлайн задачи.

Для первого этапа мне прислали ссылку на онлайн тест, где нужно было решить 2 задачки за 75 минут и пройти поведенческий тест минут на 15. Задачки оказались совсем не сложными и я их решил довольно быстро. Приведу скриншоты с текстом задач, чтобы вы могли оценить.




Интервью по телефону

Через некоторое время рекрутер снова со мной связалась, сказала, что я решил все задачки и мы договорились о телефонном звонке:

Thank you for getting back to me so quickly. We’d love to move forward with a Phone discussion. Please revise Hash map, Hash table , binary tree, Big O Notation.

В назначенное время мне позвонила рекрутер и просто зачитала список вопросов, на которые мне нужно было ответить. Я так понимаю, что у неё были готовые ответы и она просто сверяла с тем, что я говорил. Соответственно, если хотите пройти этот этап, лучше отвечать, как можно короче и яснее, безо всяких там «а вот если, то…».

Сами вопросы были совсем несложными и строго из списка, который мне прислали. Пара примеров:

  • Расскажите про Hashtable
  • Чем отличаются обходы дерева в глубину (Depth-first) и в ширину (Breadth-first).
  • Что происходит при удалении элемента в бинарном дереве поиска.

Онсайт собеседование в Гданьске

Через несколько дней мне пришёл ответ.

И я стал собираться в Гданьск. Мне предложили выбрать по приоритетам время и день интервью. Я первым приоритетом указал утреннее время и мне назначили встречу с 8:30 утра до 13:00 дня. Стоит отметить, что саму поездку Амазон организовал отлично. Оплатили приличную гостиницу на две ночи, перелёты в удобное для меня время, а также такси до аэропорта и их офиса. Офис находится в современном бизнес-центре в деловой части города.

После регистрации на ресепшене и небольшого ожидания с другими кандидатами, меня пригласили в отдельную комнату, где и проходило интервью. Из любопытного, было еще 4 участника и все они были местные, из Польши. В комнате была маркерная доска и можно было приносить ноутбук, чем я и воспользовался.

Регламент следующий: 4 интервью с разными людьми по часу. 45 минут собственно на интервью и 15 минут на отдых. Во время отдыха можно немного прогуляться, сходить на кухню, что-то перекусить или выпить воды или кофе.

Каждое интервью начиналось с небольшого представления обоих сторон, общих вопросов о работе и опыте. Далее следовали поведенческие вопросы по типу «как бы вы повели в себя в такой ситуации?» или «расскажите какой-нибудь случай, где вам удалось проявить себя?» и т.д. На самом деле, как мне показалось, ответы на эти вопросы интересовали моих интервьюеров не менее, а то и более, чем техническая часть. На это тратилось примерно 20-30 минут. Еще минут 20 уходило на технические вопросы и так выходило, что времени на отдых практически не оставалось. 2-3 минуты перекура и следующий этап. Довольно выматывающе. Правда, следует отметить, что я со своей стороны тоже пытался провести собеседование и задавал довольно много вопросов о внутренней кухне Амазона.

Техническая часть была не особо сложной. Первые трое интервьюеров давали алгоритмические задачки. Если успевал решить задачу до конца времени, то давали следующую. При этом у всех были разные требования — первый просил решать на доске и при этом очень строго относился к синтаксису. Я в какой-то строчке пропустил точку запятую, так он меня несколько минут мучал на тему, что где-то есть ошибка. Я перепроверил в голове алгоритм несколько раз, прежде чем сообразил, что проблема совсем в другом. Второй ноборот — попросил решать на компьютере, что для меня комфортнее. У третьего был комбинированный вариант — сначала попросил схематично изобразить алгоритм решения на доске, а затем перенести его в код. Сами задачки, которые я вспомнил:

  1. Числа представлены в виде связного списка. Нужно написать функцию — сложения двух чисел. Результат также связный список.
  2. В очень длинной строке найти самую короткую фразу, которая содержит все ключевые слова. Например строка «to be or not to be what is a question» и ключевые слова «question», «to», «be». Ответ: «to be what is a question»
  3. Implement a stack that in addition to push and pop has a function min that returns the element with the minimum value. It should be possible to implement all operations in O(1) time.
  4. Given a list of words, write a program to find the longest word made of other words in the list.

С последним интервьюером мы пообщались по вопросам дизайна и архитектуры приложений. Сначала он спрашивал о моей работе, какие технологии используем, почему они были выбраны. Затем предложил спроектировать сервис для антивируса. Он должен принимать запрос на проверку какого-либо файла на S3 и работать ассинхронно. Немного поговорили про вопросы масштабирования решения.

Офер и мои впечатления

Скажу сразу — офер мне не дали. Через несколько дней пришёл стандартный ответ от рекрутера, что спасибо за участие, но у нас есть более подходящие кандидаты и желаем вам удачи. Я не очень расстроился, т.к. во-первых на офер и не расчитывал, а во-вторых и не готовился особо. Вся подготовка свелась к чтению по диагонали pdf версии «Cracking the Coding Interview 6th Edition». Кстати, для подготовки к такого рода собеседованиям просто маст хэв вещь. Буквально всё, что там описано, происходило и у меня на интервью. Вроде бы даже какие-то задачи совпали, но я это уже позже обнаружил )

Самим интервью и компанией я остался скорее разочарованным. Итак, что мне не понравилось. Во первых сам формат интервью. Я реально не понимаю, что можно выяснить давая задачки со школьной олимпиады? Только что кандидат умеет их решать? Я таких товарищей видел много, тока на практике оказывалось, что более ничего они не умеют. Но это холиварный вопрос — уже сколько копий сломано на эту тему.

Второе, что мне не понравилось — собеседовавшие меня инженеры. Нет, как люди они очень милые и приятные. Со всеми мы довольно дружески и интересно пообщались. Но вот, что сразу напрягло — они все очень долго работают в Амазоне. У некоторых так это единственный работодатель. Самый «младший» там работает уже 7 лет, а «старший» вроде 15. Здесь нужно понимать, что Амазон очень большая компания и, как принято, у них полно своих велосипедов и опенсоурс использут мало или же делают свои форки. Вдобавок, ты обычно отвечаешь совсем за небольшую часть проекта, в котором работаешь. В итоге ты становишься квалифицированным, но узким специалистом в продукте, который используется только одной компанией. И по моим собеседникам это было видно. «Архитектор» ничего не знал про Кафку (это которая очередь, а не писатель 😉 ). Инженер занимающийся SQL движком Presto (предлагают как сервис в AWS) ничего не слышал про Calcite и т.п.

В общем, такой кровавый энтерпрайз. В очередной раз убедился, что это не моё. Из того, что понравилось — это организация всех этапов. Видно, что уже отлаженный процесс без лишних проволочек.

Если всё же кому-то захочется устроиться на работу в Амазон или Гугл или куда-то ещё, то дам несколько советов. Как я понял из общения с коллегами, собеседовашихся в подобные компании, везде плюс — минус одинаковый процесс.

  • Прочитать и разобрать все темы из «Cracking the Coding Interview 6th Edition»
  • Заранее подготовить ответы на поведенческие вопросы. Как мне показалось, так им придают даже большее внимание, чем техническим.
  • Потренироваться решать задачки на листке. В том числе писать код, который будет компилироваться. Некоторым интервьюерам это важно.
  • Быть увереным и не впадать в панику. Даже если не знаете, как решить задачу, придумайте решение в лоб и потом его прооптимизируйте. Даже брутфорс алгоритм лучше, чем никакого.

Zalando

В процессе собеседования с Amazon, я так вошёл во вкус, что согласился пообщаться ещё с одной очень крупной компанией. Zalando — самая крупная в Европе компания, специализирующаяся на онлайн-продажах одежды и обуви. Это уже было интереснее, т.к. основным языком у них является Scala, а нежелание работать с Java, после задачек для Амазона у меня только увеличилось. Я, к тому же, подал заявку на вакансию дата инженера с Big Data стеком. Это важно, почему, узнаете в конце.

Сам процесс построен по уже знакомому принципу:

  1. Сначала онлайн звонок с HR (специалист отдела кадров).
  2. Затем онлайн тест.
  3. Техническое собеседование по скайпу.
  4. И в конце онсайт интервью в головном офисе в Берлине.

В моём случае, правда, порядок оказался нарушен — сначала был онлайн тест, а только затем звонок с HR. Я считаю, что это неправильно, т.к. этот звонок нужен для предварительного проговора условий и если что-то не устроит, то и тест делать не нужно. Как оказалось впоследствии, HR у Zalando работают так себе. Отвечают обычно долго. Моему бывшему коллеге, прислали решение о собеседовании только через месяц, когда для него это было уже совсем неактуально.

Онлайн тест

Здесь также дали две задачки, которые нужно было решить за полтора часа. Первую я решил довольно быстро и только настроился на вторую, как проснулся ребёнок и пришлось его успокаивать. В итоге у меня вместо часа осталось только 20 минут времени. Я начал было паниковать и в итоге залил самое простое решение, которое проходило тесты. Особенность здесь такая, что после отправки решения оно прогоняется на расширенных тестах и там вторая задача успешно справилась только на 80%.

Сами задачки.



Техническое собеседование

Несмотря на какие-то ошибки в решении второй задачи, меня позвали на следующий этап. Если честно, то не очень помню о чём мы разговривали, но технические вопросы мы обсуждали больше с точки зрения архитектуры — какие инструменты следует применять и в каких случаях. Всё это касалось только стека для работы с большими данными.

Онсайт в Берлине

Недели так через две приходит ответ, что они были бы рады со мной пообщаться и пригласили на онсайт в Берлин. Ну что же, нужно ехать, к тому же давно уже не пил пиво в столице Германии 😉

Как я уже упоминал, организационная составляющая в немецкой компании оставляет желать лучшего. В итоге все билеты покупались буквально в последний момент и я был уже не уверен, что полечу, в принципе. К тому же здесь уже появились лимиты — билеты до 300€ и оплачивали только одну ночь в гостинице до 100€.

Я прилетел за день до интервью и успел к нему как следует подготовиться 🙂

В офисе я сфотографировал только ресепшн.

У меня было 3 интервью с инженерами из разных команд. Мне они все очень понравились — интересные, разносторонние люди. Один мне предложил, если не получится с той командй куда я собеседуюсь прийти к ним. Я сказал, что обязательно подумаю. Сам формат собеседований тот же, что и в Амазон — каждое интервью по 45 минут и 15 минут перерыв. И также у меня выходило, что мы общались как минимум по часу, а один раз и того более.

Первое интервью было на знание Scala. Мне предложили реализовать конструкцию try-with-resources. Я, конечно мог сразу написать итоговый результат, но решил поиграть в игру от простого наивного решения к более сложному. В итоге мы довольно интересно провели время, обсуждая текущее состояние языка.

Второе интервью было архитектурным. Мне предложили реализовать REST-сервис корзины интернет магазина. Тут я сразу не разобрался, конкретно, что от меня хотят и направился не в ту сторону. Но в процессе обсуждения я, наконец-то, выяснил, что требовалось сделать и предложил своё решение. Изначально оно было с использованием Key-Value хранилища, но под конец я, зачем-то, сказал, что можно ещё упростить и сделать на Event Sourcing архитектуре и тогда внешнее Key-Value хранилище будет не нужно. Мы пообсуждали плюсы и минусы этого решения.

На третьем интервью мы обсуждали подходы к разработке. Говорили о том, как я пишу функциональный код, какие паттерны и библиотеки я использую и почему. В основном обсуждение строилось на примере кода из моего github репозитория. Ещё немного поговорили о тестовых задачках. Оказывается, у них трекается активность в онлайн редакторе и его удивило, что я был неактивен более сорока минут подряд. Я объяснил ситуацию с ребёнком и на этом обсуждение закончили.

Офер и мои впечатления

По итогам, все обсуждения с техническими специалистами мне понравились. Умные и квалифицированные люди. HR, в принципе, тоже с работой справились, но могли бы быть и порасторопнее. Чего я точно не ожидал, так их ответа. Дело в том, что по своим ощущениям я все этапы прошел на отлично, за исключением начала обсуждения дизайна REST сервиса. Вот такое письмо пришло от рекрутера:

В самом отказе нет ничего страшного, может просто рожей не вышел. Но приведенная причина меня смутила — т.е. они прислали отказ на позицию дата инженера, на основании того, что им не понравилось моё обсуждение REST-сервиса? А конкретно ES модели! Очень странно. У них, кстати, в описании вакансии, кроме Hadoop, Spark, Hive ничего больше нет, никакого намёка на REST. Ну да ладно, реального намерения идти к ним не было — наслышан об относительно невысоких зарплатах и потребительского отношения к работникам. Но осадочек остался. Вот так вот случайно брошенной фразой можно всё «испортить».

Подводя итог хочу сказать — не бойтесь ходить на интервью. Даже отказ в одном месте — это совсем не конец вашей карьеры, а очень хороший опыт, который поможет в будущем выстроить правильную линию поведения и укажет пробелы в знаниях. А вообще, 95% процентов интервью похожи, как две капли воды. Часто даже вопросы одни и те же спрашивают. В моём случае я получил то, что хотел — опыт прохождения собеседований в крупных компаниях и бесплатные поездки по Европе 🙂

Ate logo!

Понимаем implicit’ы в Scala

В последнее время у меня было несколько разговоров с друзьями из Java мира об их опыте использования Scala. Большинство использовали Scala, как улучшенную Java и, в итоге, были разочарованы. Основная критика была направлена но то, что Scala слишком мощный язык с высоким уровнем свободы, где одно и тоже можно реализовать различными способами. Ну и вишенкой на торте недовольства являются, конечно же, implicit’ы. Я соглашусь, что implicit’ы одна из самых спорных фич языка, особенно для новичков. Само название «неявные», как бы намекает. В неопытных руках implicit’ы могут стать причиной плохого дизайна приложения и множества ошибок. Я думаю каждый, работающий со Scala, хотя бы раз сталкивался с ошибками разрешения ипмлиситных зависимостей и первые мысли были что делать? куда смотреть? как решить проблему? В результате приходилось гуглить или даже читать документацию к библиотеке, если она есть, конечно же. Обычно решение находится импортом необходимых зависимостей и проблема забывается до следующего раза.

В этом посте я бы хотел рассказать о некоторых распространенных практиках использования имплиситов и помочь их сделать более «явными» и понятными. Наиболее распространенные варианты их использования:

  • Неявные параметры (implicit parameters)
  • Неявные преобразования (implicit conversions)
  • Неявные классы (implicit classes — «Pimp My Library» паттерн)
  • Тайп-классы (type classes)

В сети много статей, документации и докладов, посвященных этой теме. Я, однако, хотел бы остановиться на их практическом применении на примере создания Scala-friendly API для замечательной Java библиотеки Typesafe Lightbend Config. Для начала нужно ответить на вопрос, а что, собственно, не так с родным API? Давайте взглянем на пример из документации.

import com.typesafe.config.ConfigFactory

val conf = ConfigFactory.load();
val foo = config.getString("simple-lib.foo")
val bar = config.getInt("simple-lib.bar")

Я вижу здесь, как минимум, две проблемы:

  1. Обработка ошибок. Например, если метод getInt не сможет вернуть значение нужного типа, то будет брошено исключение. А мы хотим писать «чистый» код, без исключений.
  2. Расширяемость. Этот API поддерживает некоторые Java типы, но что, если мы захотим расширить поддержку типов?

Давайте начнем со второй проблемы. Стандартное Java решение — наследование. Мы можем расширить функциональность базового класса путем добавления новых методов. Обычно это не является проблемой, если вы владеете кодом, но что делать если это сторонняя библиотека? «Наивный» путь решения в Scala будет через использование неявных классов или «Pimp My Library» паттерна.

implicit class RichConfig(val config: Config) extends AnyVal {
  def getLocalDate(path: String): LocalDate = LocalDate.parse(config.getString(path), DateTimeFormatter.ISO_DATE)
}

Теперь мы можем использовать метод getLocalDate, как если бы он был определен в исходном классе. Неплохо. Но мы решили проблему только локально и мы должны поддерживать всю новую функциональность в одном RichConfig классе или потенциально иметь ошибку «Ambiguous implicit values», если одинаковые методы будут определены в разных неявных классах.

Можно ли как-то это улучшить? Здесь давайте вспомним, что обычно в Java, наследование используется для реализации полиморфизма. На самом деле, полиморфизм бывает разных видов:

  1. Ad hoc полиморфизм.
  2. Параметрический полиморфизм.
  3. Полиморфизм подтипов.

Наследование используется для реализации полиморфизма подтипов. Нас же интересует ad hoc полиморфизм. Он означает, что мы будем использовать другую реализацию в зависимости от типа параметра. В Java это реализуется при помощи перегрузки методов. В Scala его можно дополнительно реализовать при помощи тайп классов. Эта концепция пришла из Haskel, где является встроенной в язык, а в Scala это паттерн, который требует implicit’ов для реализации. Если описать вкратце, то тайп класс — это некоторый контракт, например трейт Foo[T], параметризованный типом T, который используется в разрешении неявных зависимостей и нужная имплементация контракта выбирается по типу. Звучит запутано, но на самом деле это просто.

Давайте рассмотрим на примере. Для нашего случая, определим контракт для чтения значения из конфига:

trait Reader[A] {
  def read(config: Config, path: String): Either[Throwable, A]
}

Как мы видим, трейт Reader параметризирован типом A. Для решения первой проблемы мы возвращаем Either. Больше никаких исключений. Для упрощения кода можем написать тайп-алиас.

trait Reader[A] {
  def read(config: Config, path: String): Reader.Result[A]
}

object Reader {
  type Result[A] = Either[Throwable, A]

  def apply[A](read: (Config, String) => A): Reader[A] = new Reader[A] {
    def read[A](config: Config, path: String): Result[A] = Try(read(config, path)).toEither
  }

  implicit val intReader = Reader[Int]((config: Config, path: String) => config.getInt(path))
  implicit val stringReader = Reader[String]((config: Config, path: String) => config.getString(path))
  implicit val localDateReader = Reader[LocalDate]((config: Config, path: String) => LocalDate.parse(config.getString(path), DateTimeFormatter.ISO_DATE);)
}

Мы определили тайп класс Reader и добавили несколько реализаций для типов Int, String, LocalDate. Теперь нужно научить Config работать с нашим тайп классом. И здесь уже пригодится «Pimp My Library» паттерн и неявные аргументы:

implicit class ConfigSyntax(config: Config) extends AnyVal {
  def as[A](path: String)(implicit reader: Reader[A]): Reader.Result[A] = reader.read(config, path)
}

Мы можем переписать более кратко при помощи ограничения контекста(context bounds):

implicit class ConfigSyntax(config: Config) extends AnyVal {
  def as[A : Reader](path: String): Reader.Result[A] = implicitly[Reader[A]].read(config, path)
}

И теперь, пример использования:

val foo = config.as[String]("simple-lib.foo")
val bar = config.as[Int]("simple-lib.bar")

Тайп классы — очень мощный механизм, который позволяет писать легко расширяемый код. Если требуется поддержка новых типов, то можно просто написать реализацию нужного тайп класса и поместить её в контекст. Также, используя приоритет в разрешении неявных зависимостей, можно переопределять стандартную реализацию. Например, можно определить другой вариант LocalDate ридера:

implicit val localDateReader2 = Reader[LocalDate]((config: Config, path: String) =>
  Instant
    .ofEpochMilli(config.getLong(path))
    .atZone(ZoneId.systemDefault())
    .toLocalDate()
)

Как мы видим, implicit’ы, при правильном использовании, позволяют писать чистый и расширяемый код. Они позволяют расширить функциональность сторонних библиотек, без изменения исходного кода. Позволяют писать обобщённый код и использовать ad hoc полиморфизм при помощи тайп классов. Нет необходимости беспокоиться о сложной иерархии классов, можно просто разделить функциональность на части и реализовывать их отдельно. Принцип разделяй и властвуй в действии.

Ссылка на github проект с примерами.

Статья на Habrahabr.

How to work with Hive tables with a lot of partitions from Spark

One of the common practice to improve performance of Hive queries is partitioning. Partitions are simply parts of data separated by one or more fields. Creating a partitioned table is simple:

CREATE TABLE events (
  created TIMESTAMP,
  user STRING,
  time STRING,
  request STRING,
  status STRING,
  size STRING,
  referer STRING
) PARTITION BY (
  year INT,
  month INT,
  day INT,
  hour INT,
  country STRING
)

On HDFS will be created next folder structure:

/user/hive/warehouse/default.db/events/year=2018/month=1/day=1/hour=1/country=Brazil

So every time when we will use partitioned fields in queries Hive will know exactly in what folders search data. It can significantly speedup execution because instead of full scan Hive engine will use only part of data.

Win? No. We have another problem — there are a lot of recommendations to limit amount of partitions in about 10000. Lets calculate how much partitions could have our table per one year:

1 year * 12 months * 30 days * 24 hours * 100 countries = 864000 partitions.

About 1MM partitions is much more than recommended 10K! Ok, we can remove country from partitioning and it will get us 8640 partitions per year — much better. But what if we require data for 2,3,5,10 years? We can again remove by hour partitioning but our queries became slower or may be we load data by hour and sometimes need to reload some hours. Solution is simple — keep our partitioning structure as is. Hive can efficiently work even with 1MM partitions but with some reservations.

Let’s review Hive architecture.

What main parts do we have here:

  1. HiveServer parse sql query, do query optimizations, request table’s metadata from Metastore Server, execute query (MR2, Spark, Tez).
  2. Metastore manage all metadata: tables structure, partitions and etc. As backend storage using relational database. By default Hive uses built-in Derby server but it can (and must for production use) be reconfiguring to MySQL or PostgreSQL.

Spark implement his own SQL Thrift Server and interacts with Metastore (Schema Catalog in term of Spark) directly.

When HiveServer build execution plan on partitioned table it request data about available partitions and have two methods for it:

  1. listPartitions — return all partitions for table. As we already know partitions are stored in database. And if we have a lot of entries at can take considerable time to retrieve all of them. It will decrease total performance and even cause to errors like: java.net. SocketTimeoutException: Read timed out
  2. listPartitionsByFilter — try to pushdown some of the filters to  relational storage.

That’s mean when you write query like

select * from events where year=2018 

the filter part related to partitioned columns will used by Metastore Server to get only required data:

select "PARTITIONS"."PART_ID" from "PARTITIONS"   
  inner join "TBLS" 
    on "PARTITIONS"."TBL_ID" = "TBLS"."TBL_ID" and "TBLS"."TBL_NAME" = 'events' 
  inner join "DBS" 
    on "TBLS"."DB_ID" = "DBS"."DB_ID" and "DBS"."NAME" = 'default' 
  inner join "PARTITION_KEY_VALS" "FILTER1" 
    on "FILTER1"."PART_ID" = "PARTITIONS"."PART_ID" and "FILTER1"."INTEGER_IDX" = 1 
  where ("FILTER1"."PART_KEY_VAL" = '2018')

So to have fast queries we need to be sure listPartitionsByFilter method is used. To support it for Spark spark.sql.hive.metastorePartitionPruning option must be enabled.

By default Hive Metastore try to pushdown all String columns. The problem with other types is how partition values stored in RDBMS — as it can be seen in query above they are stored as string values. So trying to pushdown filter like year > 2018 will return wrong result. Fortunately there is a configuration property hive.metastore.integral.jdo.pushdown (false by default) for Hive Metastore which turn on partial support for integral types. Partial mean it will support only few logical operations: equals and not equals.

/**
* @return true iff filter pushdown for this operator can be done for integral types.
*/
public boolean canJdoUseStringsWithIntegral() {
  return (operator == Operator.EQUALS)
  || (operator == Operator.NOTEQUALS)
  || (operator == Operator.NOTEQUALS2);
}

Does it mean filters like year between 2015 and 2018 will not pushdown? Not really — it depends on SQL optimisation engine. For example Spark prior 2.0 doesn’t support such optimizations and will work only with '=', '!=', '<>' operations. But latest versions do this job well and will transform it to year=2015 or year=2016 or year=2017 or year=2018. Even filter like year(from_unixtime(created)) > 2015 on Spark 2.x will be processed correctly.
To make sure that everything works correctly you can set INFO level logs for Hive Metastore and search lines like:

[INFO] org.apache.hadoop.hive.ql.log.PerfLogger: </PERFLOG method=get_partitions_by_filter

Ate logo!