Clickstream - это набор событий (events) о переходах реальных пользователей в интернете (их история интерент серфинга/браузинга), представленная в формате, похожем на access log веб-сервера. Пример эвента:
{
"server_stamp": 1506816287000,
"client_stamp": 1506816166795,
"url": "https://www.kurnik.pl/pilka/",
"domain": "kurnik.pl",
"referer": "https://www.kurnik.pl/pilka/",
"referer_domain": "kurnik.pl",
"status_code": 200,
"country_code": "GB",
"browser": "Chrome",
"operating_system": "Windows7",
"uid": "5e1d8d214ed4c39ce19f8351963bfa9c"
}
- server_stamp - unix timestamp в миллисекундах, когда событие было зарегистрировано.
- client_stamp - unix timestamp в миллисекундах, представляющий время у пользователя.
- url - URL, по которому зашел пользователь.
- domain - TLD сайта, полученный из url.
- referer - URL, с которого перешел пользователь (может отсутствовать в случае прямого захода).
- referer_domain - TLD сайта, полученный из referer (может отсутствовать в случае прямого захода).
- status_code - ответ от HTTP-сервера на запрошеный URL.
- country_code - двухбуквенный код страны (ISO 3166).
- browser - браузер пользователя.
- operating_system - операционная система пользователя.
- uid - уникальный идентификатор пользователя.
Реализовать построение сессий серфинга/браузинга по набору эвентов с использованием Spark API.
В задании использован подход TDD. Реализован класс эвента в src/main/scala/com/semrush/data/event.scala
. Реализован unit-тест в src/test/scala/com/semrush/session_test.scala
. Нужно написать код, реализующий объект/класс com.semrush.data.data_processor
, с которым unit-тесты начнут успешно выполняться. Исходные данные в тесте представлены в виде набора JSON строк, которые нужно десериализовать и промаркировать идентификатором сессии.
Прототип функции:
def apply(rawRDD: org.apache.spark.rdd.RDD[String]): org.apache.spark.rdd.RDD[com.semrush.data.event]
Идентификатор сессии генерируется функцией makeSid.
def makeSid(uid: String, domain: String, startStamp: java.util.Date) : String = startStamp.getTime.toString + (uid, domain).hashCode
На вход принимаются:
- uid - идентификатор пользователя.
- domain - домен, по которому построена сессия.
- startStamp - пользовательский timestamp (client_stamp) первого эвента в сессии.
Правила построения сессий пытаются воспроизвести Google Analytics c учетом специфики clickstream данных.
- К одной сессии могут относиться только эвенты от одного и того же пользователя для одного и того же домена (domain).
- Эвенты в сессии отсортированы по времени пользователя, а не по времени сервера.
- Пользовательская сессия разрывается в следующих случаях:
- Пользователь зашел на другой сайт (у эвента отличный от сессии domain). В этом случае начинается новая сессия для другого сайта.
- Пользователь зашел на этот же сайт (у эвента и сессии domain совпадают), но переход был осуществлен с другого сайта (referer_domain определен и отличается от domain сессии).
- Интервал между эвентами сессии - больше 30 минут.
- Пользовательская сессия не разрывается, и эвент считается принадлежащим к этой же сессии, если:
- Пользователь зашел на этот же сайт по прямой ссылке (у эвента и сессии domain совпадают, и referer_domain у эвента отсутствует).
- Пользователь зашел на сайт по ссылке с этого же сайта (у эвента и сессии domain совпадают, и referer_domain у эвента совпадает с domain сессии).
- Unit-тесты успешно проходят.
- Unit-тесты успешно проходят, код структурирован и читабелен.
- Unit-тесты успешно проходят, код структурирован, читабелен, и пригоден для запуска на реальном вычислительном кластере для обработки больших объемов данных.
- Unit-тесты успешно проходят, код структурирован, читабелен, и пригоден для запуска на реальном вычислительном кластере для обработки больших объемов данных. Код оптимизирован, добавлены комментарии, почему реализация именно такая, плюсы и минусы.
Для запуска нужны установленные sbt, java и scala.
sbt compile
sbt assembly
Добавить плагин в глобальный(или локальный) конфиг sbt (например, ~/.sbt/0.13/plugins/plugins.sbt):
resolvers += Resolver.sonatypeRepo("snapshots")
addSbtPlugin("org.ensime" % "ensime-sbt" % "0.1.5-SNAPSHOT")
Генерация проекта для ensime:
sbt ensimeConfig
Плагин интеграции со Spark уже включен в проект, локальные таски можно запускать примерно так:
sbt "sparkSubmit --master local[2] --class Main -- <arguments>"
Про интеграцию с емаксом можно почитать тут.