Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Смирнов Павел. Разработчик-аналитик службы интеллектуального анализа. Производительность, читаемость, скорость разработки. Как Python помог усидеть на трех стульях.

Slide 3

Slide 3 text

Аналитика в Яндексе Производительность, читаемость, скорость разработки

Slide 4

Slide 4 text

По типу используемых данных для достижения результата: › базовые показатели › сложные системы Типы аналитики 4

Slide 5

Slide 5 text

› App Метрика › Web Метрика › Стандартные отчеты на внутренних сервисах Инструменты анализа базовых показателей 5

Slide 6

Slide 6 text

Анализ сложных систем 6

Slide 7

Slide 7 text

› Какой эффект от рекламы по телевизору? Анализ сложных систем 7

Slide 8

Slide 8 text

› Какой эффект от рекламы по телевизору? › Есть два продукта с похожим контентом, мешает ли их реклама друг другу? Анализ сложных систем 8

Slide 9

Slide 9 text

› Какой эффект от рекламы по телевизору? › Есть два продукта с похожим контентом, мешает ли их реклама друг другу? › Какие пользователи реже пользуются сервисом и почему? Анализ сложных систем 9

Slide 10

Slide 10 text

› Какой эффект от рекламы по телевизору? › Есть два продукта с похожим контентом, мешает ли их реклама друг другу? › Какие пользователи реже пользуются сервисом и почему? › Какая объективная польза от разных приложений и сервисов? Какие из них надо развивать? Анализ сложных систем 10

Slide 11

Slide 11 text

› Какой эффект от рекламы по телевизору? › Есть два продукта с похожим контентом, мешает ли их реклама друг другу? › Какие пользователи реже пользуются сервисом и почему? › Какая объективная польза от разных приложений и сервисов? Какие из них надо развивать? › И т.д. Анализ сложных систем 11

Slide 12

Slide 12 text

Источником данных являются логи сервисов и приложений. Наши сервисы пишут более 700 различных логов. Объемами от нескольких МБ до сотен Тб в сутки. Источники данных 12

Slide 13

Slide 13 text

YT - система распределенных вычислений на основе модели Map-Reduce. Хранение и обработка данных 13

Slide 14

Slide 14 text

› Конструкторы расчета показателей в YT › SQL-like запросы к данным на YT › Написание кода на языках программирования Инструменты обработки данных 14

Slide 15

Slide 15 text

Умеет и любит работать с данными. Знает языки Python Аналитик 15

Slide 16

Slide 16 text

Аналитик 16

Slide 17

Slide 17 text

Плюсы: Аналитик 17

Slide 18

Slide 18 text

Плюсы: › Решение задач любой сложности Аналитик 18

Slide 19

Slide 19 text

Плюсы: › Решение задач любой сложности › Скорость написания кода Аналитик 19

Slide 20

Slide 20 text

Плюсы: › Решение задач любой сложности › Скорость написания кода › Скорость решения всей задачи зависит только от одного человека Аналитик 20

Slide 21

Slide 21 text

Плюсы: › Решение задач любой сложности › Скорость написания кода › Скорость решения всей задачи зависит только от одного человека › Читабельность кода Аналитик 21

Slide 22

Slide 22 text

Минусы: Аналитик 22

Slide 23

Slide 23 text

Минусы: › Неоптимальный код Аналитик 23

Slide 24

Slide 24 text

Минусы: › Неоптимальный код › Медленный язык программирования Аналитик 24

Slide 25

Slide 25 text

Минусы: › Неоптимальный код › Медленный язык программирования › "Велосипеды" и различия в коде с одинаковой функциональностью у нескольких аналитиков Аналитик 25

Slide 26

Slide 26 text

› Производительность › Читаемость › Скорость разработки Промежуточный итог 26

Slide 27

Slide 27 text

Решение №1 Производительность, читаемость, скорость разработки

Slide 28

Slide 28 text

Аналитик + разработчик 28

Slide 29

Slide 29 text

Минусы: Аналитик + разработчик 29

Slide 30

Slide 30 text

Минусы: › Время решения задачи Аналитик + разработчик 30

Slide 31

Slide 31 text

Минусы: › Время решения задачи › Скучные задачи для разработчика Аналитик + разработчик 31

Slide 32

Slide 32 text

› Производительность › Читаемость › Скорость разработки Промежуточный итог 32

Slide 33

Slide 33 text

Анализ работы с данными Производительность, читаемость, скорость разработки

Slide 34

Slide 34 text

Посчитать популярность запросов Задача 34

Slide 35

Slide 35 text

Входные данные 35 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 36

Slide 36 text

Подготовка данных для анализа Структура решения задачи 36 Фильтрация ненужных записей Извлечение нужных полей из записи Преобразование полей Бизнес логика задачи

Slide 37

Slide 37 text

Подготовка данных для анализа Структура решения задачи 37 Фильтрация ненужных записей Извлечение нужных полей из записи Преобразование полей Бизнес логика задачи 75% времени расчета 25% времени расчета

Slide 38

Slide 38 text

Деревья разбора Производительность, читаемость, скорость разработки

Slide 39

Slide 39 text

Входные данные 39 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 40

Slide 40 text

Входные данные 40 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 41

Slide 41 text

Входные данные 41 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 42

Slide 42 text

Входные данные 42 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 43

Slide 43 text

Входные данные 43 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 44

Slide 44 text

Входные данные 44 Server name Url search_1 https://www.yandex.ru/search/?text=ускорение%20свободного%20падения search_2 https://www.yandex.ru/search/touch/?text=Котёнок%20милый%20фото search_1 https://www.yandex.ru/search/?text=Как%20приготовить%20сырники%20дома search_2 https://www.yandex.ru/tech/api/?utt=132 search_3 https://www.yandex.ru/tech/api/?utt=213 Логи доступа к сервисам поиска

Slide 45

Slide 45 text

Дерево разбора Log line 45

Slide 46

Slide 46 text

Дерево разбора Log line Url Server name 46

Slide 47

Slide 47 text

Дерево разбора Log line Url Server name Parsed url 47

Slide 48

Slide 48 text

Дерево разбора Log line Url Server name Parsed url Protocol Host Page Params 48

Slide 49

Slide 49 text

Дерево разбора Log line Url Server name Parsed url Protocol Host Page Params Parsed params 49

Slide 50

Slide 50 text

Дерево разбора Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… 50

Slide 51

Slide 51 text

Дерево разбора Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 51

Slide 52

Slide 52 text

› Сохранение деревьев и их частей › Расширение существующих деревьев Дополнительные фичи деревьев 52

Slide 53

Slide 53 text

QB Производительность, читаемость, скорость разработки

Slide 54

Slide 54 text

Вызов функции qb = QB( log='access-log', fields=['decoded_text', 'server_name', 'page'], filters=[qbf.defined('decoded_text')] ) record = qb.prepare(log_line) if record not is None: yield record.decoded_text, record.server_name, record.page

Slide 55

Slide 55 text

Желаемая функция обработки def prepare_one_line(log_line): url = get_log_field('url', log_line) server_name = get_log_field(‘server_name’, log_line) parsed_url = parse_url(url) page = get_from_dict('page', parsed_url) params = get_from_dict('params', parsed_url) parsed_params = parse_url_params(params) text = get_from_dict('text', parsed_params) decoded_text = url_decode(text) if decoded_text is None: return None return Record(decoded_text=text, server_name=server_name, page=page)

Slide 56

Slide 56 text

Abstract Syntax Tree - дерево объектов языка Python Оно формируется путем анализа кода на Python, а используется компилятором для формирования байт-кода. AST 56

Slide 57

Slide 57 text

Инициализация объекта qb QB 57 Название дерева разбора Список полей для извлечения и описания дополнительных веток Список фильтраций QB AST Python AST Функция обработки

Slide 58

Slide 58 text

Дерево разбора лога Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 58

Slide 59

Slide 59 text

QB, работа с существующим деревом qb = QB( log='access-log', fields=['decoded_text', 'server_name', 'page'], filters=[qbf.defined('decoded_text')] )

Slide 60

Slide 60 text

QB, создание дерева разбора qb.QB( log='default-log', fields=[ qbe.log_field('url'), qbe.log_field('server_name’), qbe.custom('parsed_url', parse_url, 'url'), qbe.dictitem('params', from_='parsed_url'), qbe.custom('parsed_params', parse_params, 'params'), qbe.dictitem('text', from_='parsed_params'), qbe.custom('decoded_text', url_decode, 'text'), ], filters=[ qbf.defined('decoded_text'), ] )

Slide 61

Slide 61 text

[RootCommand(field='log_line'), ExtractCommand( field='parsed_log_line', ast=IfExpr( condition=IsNot(left=Field(name='log_line'), right=Const(value=None)), then=Apply( Const( value=), Field(name='log_line')), else_=Const(value=None)), extractor=), ExtractCommand( field='url'…), ExtractCommand( field='parsed_url'…), ExtractCommand( field='params'…), ExtractCommand( field='parsed_params'…), ExtractCommand( field='text'…), ExtractCommand( field='decoded_text'…), FilterCommand( ast=Is(left=Field(name='decoded_text'), right=Const(value=None))), ExtractCommand( field='server_name'…)]

Slide 62

Slide 62 text

def map(__qb2_input_stream): """Generated by qb2.compiler.compile""" for log_line in __qb2_input_stream: if log_line is None: continue parsed_log_line = parse_log_chomp(log_line) if parsed_log_line is None: continue __qb2_inline_0 = parsed_log_line.get url = __qb2_inline_0('url') if url is None: continue parsed_url = parse_url(url) if parsed_url is None: continue params = parsed_url.get('params') if params is None: continue parsed_params = parse_params(params) if parsed_params is None: continue text = parsed_params.get('text') if text is None: continue decoded_text = url_decode(text) if decoded_text is None: continue server_name = __qb2_inline_0('server_name') yield Record(url=url, server_name=server_name, parsed_url=parsed_url, params=params, parsed_params=parsed_params, text=text, decoded_text=decoded_text)

Slide 63

Slide 63 text

Оптимизации Производительность, читаемость, скорость разработки

Slide 64

Slide 64 text

Инициализация объекта qb QB 64 Название дерева разбора Список полей для извлечения и описания дополнительных веток Список фильтраций QB AST Python AST Функция обработки

Slide 65

Slide 65 text

Распространение фильтраций Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 65

Slide 66

Slide 66 text

Распространение фильтраций Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 66

Slide 67

Slide 67 text

Распространение фильтраций Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 67

Slide 68

Slide 68 text

def map(__qb2_input_stream): """Generated by qb2.compiler.compile""" for log_line in __qb2_input_stream: if log_line is None: continue parsed_log_line = parse_log_chomp(log_line) if parsed_log_line is None: continue __qb2_inline_0 = parsed_log_line.get url = __qb2_inline_0('url') if url is None: continue parsed_url = parse_url(url) if parsed_url is None: continue params = parsed_url.get('params') if params is None: continue parsed_params = parse_params(params) if parsed_params is None: continue text = parsed_params.get('text') if text is None: continue decoded_text = url_decode(text) if decoded_text is None: continue server_name = __qb2_inline_0('server_name') yield Record(url=url, server_name=server_name, parsed_url=parsed_url, params=params, parsed_params=parsed_params, text=text, decoded_text=decoded_text)

Slide 69

Slide 69 text

def map(__qb2_input_stream): """Generated by qb2.compiler.compile""" for log_line in __qb2_input_stream: if log_line is None: continue parsed_log_line = parse_log_chomp(log_line) if parsed_log_line is None: continue __qb2_inline_0 = parsed_log_line.get url = __qb2_inline_0('url') if url is None: continue parsed_url = parse_url(url) if parsed_url is None: continue params = parsed_url.get('params') if params is None: continue parsed_params = parse_params(params) if parsed_params is None: continue text = parsed_params.get('text') if text is None: continue decoded_text = url_decode(text) if decoded_text is None: continue server_name = __qb2_inline_0('server_name') yield Record(url=url, server_name=server_name, parsed_url=parsed_url, params=params, parsed_params=parsed_params, text=text, decoded_text=decoded_text)

Slide 70

Slide 70 text

Порядок разрешения ветвей Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 70

Slide 71

Slide 71 text

Порядок разрешения ветвей Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 71

Slide 72

Slide 72 text

def map(__qb2_input_stream): """Generated by qb2.compiler.compile""" for log_line in __qb2_input_stream: if log_line is None: continue parsed_log_line = parse_log_chomp(log_line) if parsed_log_line is None: continue __qb2_inline_0 = parsed_log_line.get url = __qb2_inline_0('url') if url is None: continue parsed_url = parse_url(url) if parsed_url is None: continue params = parsed_url.get('params') if params is None: continue parsed_params = parse_params(params) if parsed_params is None: continue text = parsed_params.get('text') if text is None: continue decoded_text = url_decode(text) if decoded_text is None: continue server_name = __qb2_inline_0('server_name') yield Record(url=url, server_name=server_name, parsed_url=parsed_url, params=params, parsed_params=parsed_params, text=text, decoded_text=decoded_text)

Slide 73

Slide 73 text

Объединение фильтраций filters=[ qbf.defined('server_name'), qbf.equals('server_name', 'search_1'), ]

Slide 74

Slide 74 text

Объединение фильтраций def map(__qb2_input_stream): """Generated by qb2.compiler.compile""" for log_line in __qb2_input_stream: if log_line is None: continue parsed_log_line = parse_log_chomp(log_line) if parsed_log_line is None: continue __qb2_inline_0 = parsed_log_line.get server_name = __qb2_inline_0(‘server_name') if server_name is None or server_name != 'search_1': сontinue . . .

Slide 75

Slide 75 text

› Вынос расчета констант › Расчет одинаковых выражений в условиях один раз за функцию › Замена некоторых выражений на уже посчитанные ранее › Вынос из-под цикла независимых от него частей › И другие Остальные оптимизации 75

Slide 76

Slide 76 text

def map(__qb2_input_stream): """Generated by qb2.compiler.compile""" for log_line in __qb2_input_stream: if log_line is None: continue parsed_log_line = parse_log_chomp(log_line) if parsed_log_line is None: continue __qb2_inline_0 = parsed_log_line.get url = __qb2_inline_0('url') if url is None: continue parsed_url = parse_url(url) if parsed_url is None: continue params = parsed_url.get('params') if params is None: continue parsed_params = parse_params(params) if parsed_params is None: continue text = parsed_params.get('text') if text is None: continue decoded_text = url_decode(text) if decoded_text is None: continue server_name = __qb2_inline_0('server_name') yield Record(url=url, server_name=server_name, parsed_url=parsed_url, params=params, parsed_params=parsed_params, text=text, decoded_text=decoded_text)

Slide 77

Slide 77 text

Оптимизация функций Производительность, читаемость, скорость разработки

Slide 78

Slide 78 text

Оптимизация функций Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 78

Slide 79

Slide 79 text

Оптимизация функций Log line Url Server name Parsed url Protocol Host Page Params Parsed params Text Other params… Other params… Other params… Decoded text 79

Slide 80

Slide 80 text

Оптимизация функций qb = QB( log='access-log', fields=['decoded_text', 'server_name', 'page'], filters=[qbf.defined('decoded_text')] )

Slide 81

Slide 81 text

[RootCommand(field='log_line'), ExtractCommand( field='parsed_log_line', ast=IfExpr( condition=IsNot(left=Field(name='log_line'), right=Const(value=None)), then=Apply( Const( value=), Field(name='log_line')), else_=Const(value=None)), extractor=), ExtractCommand( field='url'…), ExtractCommand( field='parsed_url'…), ExtractCommand( field='params'…), ExtractCommand( field='parsed_params'…), ExtractCommand( field='text'…), ExtractCommand( field='decoded_text'…), FilterCommand( ast=Is(left=Field(name='decoded_text'), right=Const(value=None))), ExtractCommand( field='server_name'…)]

Slide 82

Slide 82 text

Итоги Производительность, читаемость, скорость разработки

Slide 83

Slide 83 text

› Производительность › Читаемость › Скорость разработки Итоги 83

Slide 84

Slide 84 text

Смирнов Павел Разработчик-аналитик [email protected]