#common
A/B-тестирование 1/2.
A/B-тесты это когда вы сравниваете поведение пользователей при различных условиях. Например вы запускаете новую фичу и хотите понять, как она влияет на пользователей и влияет ли вообще. В данном случае вы можете поделить пользователей на две группы: тестовую с фичой и контрольную, у которой новой фичи нет. После какого-то времени смотрим на метрики и понимаем, отличаются ли значения у этих двух групп (прокрасились ли метрики и как они это сделали). Если результаты положительные, фичу можно принимать (в общем случае). Можно конечно принимать решения на ощущениях, но это опасный путь, который в долгосроке засадит ваш продукт в глубокую яму (если им злоупотреблять конечно).
Ну это ладно. Концептуально, я думаю, вы всё это знаете. Хочется осветить несколько связанных моментов.
1. Про разделение пользователей на группы😎
Это вообще довольно широкая тема, но концептуально тут существует всего пару подходов:
- берём всех пользователей и делим на k групп. При запуске нового эксперимента (экспа) берём две свободные группы из общего пула. Как только группы заканчиваются, приходится ждать, пока какой-нибудь эксп завершится, чтобы можно было начать новый;
- второй способ это перекрывать пользователей. Например пользователь может находиться сразу в нескольких тестовых группах и таким образом попадать под несколько экспериментов сразу (какие-то могут быть вкл, какие-то выкл). Реализовать это можно так: брать user_id и хешировать его с некоторой уникальной для эксперимента солью (seed для нашего хеша). Если сделать всё аккуратно, получится равномерное распределение пользователей на группы.
Однако в таком подходе стоит следить за тем, являются ли экспы независимыми, чтобы не похерить себе результаты.
Можно подходы в разных видах комбинировать.
Иногда у продуктов бывает своя специфика, из-за которой проводить аб-тесты над отдельными пользователями некорректно. Например в социальных сетях иногда проводят эксперименты над кластерами пользователей (link).
2. Важно правильно задизайнить эксперимент🤔
В моём опыте был один довольно понятный пример. Мы проводили тест с фичой на одной специфичной страничке нашего аппа, на которую заходят не все пользователи. При аб-тесте 50/50 (пользователь попадал в конкретную группу равновероятно при авторизации) мы словили очень маленький профит и решили фичу раскатить на всех. После чего метрики выросли очень сильно (порядка х10), хотя ожидалось всего в два раза. При выяснении, что же произошло, раскопали, что пользователи в тестовой группе в целом меньше пользовались этой частью приложения, когда в контрольной группе было больше таких пользователей. Тут налицо некорректный подход к дизайну экспа. Правильнее было бы делить пополам всех пользователей, которые пользуются конкретной частью приложения. В нашем случае вот рандом получился смещённым, что немного завело нас в тупик.
A/B-тестирование 1/2.
A/B-тесты это когда вы сравниваете поведение пользователей при различных условиях. Например вы запускаете новую фичу и хотите понять, как она влияет на пользователей и влияет ли вообще. В данном случае вы можете поделить пользователей на две группы: тестовую с фичой и контрольную, у которой новой фичи нет. После какого-то времени смотрим на метрики и понимаем, отличаются ли значения у этих двух групп (прокрасились ли метрики и как они это сделали). Если результаты положительные, фичу можно принимать (в общем случае). Можно конечно принимать решения на ощущениях, но это опасный путь, который в долгосроке засадит ваш продукт в глубокую яму (если им злоупотреблять конечно).
Ну это ладно. Концептуально, я думаю, вы всё это знаете. Хочется осветить несколько связанных моментов.
1. Про разделение пользователей на группы
Это вообще довольно широкая тема, но концептуально тут существует всего пару подходов:
- берём всех пользователей и делим на k групп. При запуске нового эксперимента (экспа) берём две свободные группы из общего пула. Как только группы заканчиваются, приходится ждать, пока какой-нибудь эксп завершится, чтобы можно было начать новый;
- второй способ это перекрывать пользователей. Например пользователь может находиться сразу в нескольких тестовых группах и таким образом попадать под несколько экспериментов сразу (какие-то могут быть вкл, какие-то выкл). Реализовать это можно так: брать user_id и хешировать его с некоторой уникальной для эксперимента солью (seed для нашего хеша). Если сделать всё аккуратно, получится равномерное распределение пользователей на группы.
Однако в таком подходе стоит следить за тем, являются ли экспы независимыми, чтобы не похерить себе результаты.
Можно подходы в разных видах комбинировать.
Иногда у продуктов бывает своя специфика, из-за которой проводить аб-тесты над отдельными пользователями некорректно. Например в социальных сетях иногда проводят эксперименты над кластерами пользователей (link).
2. Важно правильно задизайнить эксперимент
В моём опыте был один довольно понятный пример. Мы проводили тест с фичой на одной специфичной страничке нашего аппа, на которую заходят не все пользователи. При аб-тесте 50/50 (пользователь попадал в конкретную группу равновероятно при авторизации) мы словили очень маленький профит и решили фичу раскатить на всех. После чего метрики выросли очень сильно (порядка х10), хотя ожидалось всего в два раза. При выяснении, что же произошло, раскопали, что пользователи в тестовой группе в целом меньше пользовались этой частью приложения, когда в контрольной группе было больше таких пользователей. Тут налицо некорректный подход к дизайну экспа. Правильнее было бы делить пополам всех пользователей, которые пользуются конкретной частью приложения. В нашем случае вот рандом получился смещённым, что немного завело нас в тупик.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤3
#common
A/B-тестирование 2/2.
3. AA(B)-тесты🥳
Иногда вы хотите быть уверенным, что поведение пользователей и соответственно результаты эксперимента будут корректными, потому делите пользователей не на две группы, а на три (A, A и B). Таким образом вы смотрите, что ваши A-группы ведут себя одинаково и что B-группа приносит. Если же обе A показывают разные результаты, то у вас что-то не так с дизайном эксперимента (ну или чем-то другим). Соответстственно иногда даже проводят AA-тесты, чтобы понять, всё ли ок с точки зрения разбиения/поведения пользователей.
4. Ухудшающие тесты😍
Иногда вы хотите понять, стоит ли ещё развивать некоторую функциональность. Самый простой пример — замедление чего-либо. Можно замедлить фичу/страницу на 100мс и понять, влияет ли это на пользователей. Если в тестовой группе с замедлением мы получаем негативную прокраску метрик, значит имеет смысл оптимизировать проверяемую систему, чтобы получить профит.
Аналогично можно делать с качеством рекомендаций. И вообще с чем угодно.
Вообще все компании проводят неявные ухудшающие эксперименты. Например во время инцидентов (когда что-то падает). Тут может быть полезно не только починить проблему, но и проанализировать, как это повлияло на пользователей, чтобы получить какие-то новые знания.
5. Просадка метрик не всегда плохо😁
Иногда фича может повергнуть пользователя в шок своей непривычностью и новизной. Если вы делаете какие-то изменения, которые могут в будущем принести больше пользы (технически и продуктово), нормально принимать изменения с прокрашенными в красный метриками. Тут конечно надо знать меру и понимать, как возвращать результаты обратно. Если всё совсем плохо, но очень хочется запустить, садиться и думать, почему всё так плохо и что поменять в фиче, чтобы пользователям она заходила больше.
Ну а может ваша фича крутая, просто снаружи в мире произошло что-то, что массово повлияло на пользователей? Причём это может влиять как в хорошую, так и в плохую сторону. Такие вещи важно отслеживать.
6. Жгущие эксперименты☺️
Иногда новая функциональность начинает приносить огромный профит сразу с запуска. Чтобы не терять профит во время проведения теста, можно после включения 50/50 зафиксировать результаты, включить фичу на 80% пользователей и продолжить эксперимент на 10/10 (все доли конечно индивидуальны).
Подобный подход даже иногда автоматизируют, когда, например, раз в сутки самый успешный вариант раскатывается автоматически на бОльшую долю пользователей. В итоге можно получить автоматически раскатанный лучший вариант к концу аб-тестирования.
UPD 7. Обратные эксперименты🥴
Обратный эксп это когда вы отключаете фичу вместо её включения.
Мы как-то приняли фичу, а через какое-то время начали на неё получать репорты время от времени. Решили провести обратный эксп, чтобы понять, что с ней происходит, и получили без неё улучшение метрик. В итоге выключили её.
Причина была в ряде других фич, которые были пользователям более удобны, и вот эта подозрительная выбивалась из общей картины, из-за чего портила опыт юзеров.
Получилось, что мы включили функционал и получили рост метрик, а потом отключили функционал и получили ещё больший рост : )
Тут ссылочки на два доклада:
- Какие архитектурные решения в Яндекс Go позволяют запускать десятки продукт.экспериментов;
- Без A/B — результат XЗ, или Как мы построили платформу A/B-тестов в Ozon / Евгений Пак (Ozon).
A/B-тестирование 2/2.
3. AA(B)-тесты
Иногда вы хотите быть уверенным, что поведение пользователей и соответственно результаты эксперимента будут корректными, потому делите пользователей не на две группы, а на три (A, A и B). Таким образом вы смотрите, что ваши A-группы ведут себя одинаково и что B-группа приносит. Если же обе A показывают разные результаты, то у вас что-то не так с дизайном эксперимента (ну или чем-то другим). Соответстственно иногда даже проводят AA-тесты, чтобы понять, всё ли ок с точки зрения разбиения/поведения пользователей.
4. Ухудшающие тесты
Иногда вы хотите понять, стоит ли ещё развивать некоторую функциональность. Самый простой пример — замедление чего-либо. Можно замедлить фичу/страницу на 100мс и понять, влияет ли это на пользователей. Если в тестовой группе с замедлением мы получаем негативную прокраску метрик, значит имеет смысл оптимизировать проверяемую систему, чтобы получить профит.
Аналогично можно делать с качеством рекомендаций. И вообще с чем угодно.
Вообще все компании проводят неявные ухудшающие эксперименты. Например во время инцидентов (когда что-то падает). Тут может быть полезно не только починить проблему, но и проанализировать, как это повлияло на пользователей, чтобы получить какие-то новые знания.
5. Просадка метрик не всегда плохо
Иногда фича может повергнуть пользователя в шок своей непривычностью и новизной. Если вы делаете какие-то изменения, которые могут в будущем принести больше пользы (технически и продуктово), нормально принимать изменения с прокрашенными в красный метриками. Тут конечно надо знать меру и понимать, как возвращать результаты обратно. Если всё совсем плохо, но очень хочется запустить, садиться и думать, почему всё так плохо и что поменять в фиче, чтобы пользователям она заходила больше.
Ну а может ваша фича крутая, просто снаружи в мире произошло что-то, что массово повлияло на пользователей? Причём это может влиять как в хорошую, так и в плохую сторону. Такие вещи важно отслеживать.
6. Жгущие эксперименты
Иногда новая функциональность начинает приносить огромный профит сразу с запуска. Чтобы не терять профит во время проведения теста, можно после включения 50/50 зафиксировать результаты, включить фичу на 80% пользователей и продолжить эксперимент на 10/10 (все доли конечно индивидуальны).
Подобный подход даже иногда автоматизируют, когда, например, раз в сутки самый успешный вариант раскатывается автоматически на бОльшую долю пользователей. В итоге можно получить автоматически раскатанный лучший вариант к концу аб-тестирования.
UPD 7. Обратные эксперименты
Обратный эксп это когда вы отключаете фичу вместо её включения.
Мы как-то приняли фичу, а через какое-то время начали на неё получать репорты время от времени. Решили провести обратный эксп, чтобы понять, что с ней происходит, и получили без неё улучшение метрик. В итоге выключили её.
Причина была в ряде других фич, которые были пользователям более удобны, и вот эта подозрительная выбивалась из общей картины, из-за чего портила опыт юзеров.
Получилось, что мы включили функционал и получили рост метрик, а потом отключили функционал и получили ещё больший рост : )
Тут ссылочки на два доклада:
- Какие архитектурные решения в Яндекс Go позволяют запускать десятки продукт.экспериментов;
- Без A/B — результат XЗ, или Как мы построили платформу A/B-тестов в Ozon / Евгений Пак (Ozon).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2
#common
0. У Вадима Кравченко вышел большой пост про то, как быть хорошим ментором. Очень годный. Там ещё внутри миллион ссылок на другие более узкие статьи. Может я со временем их вычитаю и донесу частями самое интересное.
Рядом ещё могу вкинуть статью из вастрик клуба: Ты ментор. Не обосрись.
1. What’s Wrong With OpenAPI? Чуваки рассказывают, что не так с OpenAPI и что они сделали, чтобы жить лучше. Выглядит даже прикона.
2. Приконая статья про различные способы организовать ваши команды. Мы вообще работаем кросс-функциональным подходом. Словил себя на мысли, что часть недостатков такого подхода сказалась и на мне.
3. Интересная статья (правда по верхам) про эволюцию подходов к организации архитектуры вашего бекенда.
0. У Вадима Кравченко вышел большой пост про то, как быть хорошим ментором. Очень годный. Там ещё внутри миллион ссылок на другие более узкие статьи. Может я со временем их вычитаю и донесу частями самое интересное.
Рядом ещё могу вкинуть статью из вастрик клуба: Ты ментор. Не обосрись.
1. What’s Wrong With OpenAPI? Чуваки рассказывают, что не так с OpenAPI и что они сделали, чтобы жить лучше. Выглядит даже прикона.
2. Приконая статья про различные способы организовать ваши команды. Мы вообще работаем кросс-функциональным подходом. Словил себя на мысли, что часть недостатков такого подхода сказалась и на мне.
3. Интересная статья (правда по верхам) про эволюцию подходов к организации архитектуры вашего бекенда.
👍5❤4🤔1
#cpp
Наткнулся случайно на доку gcc, где описаны всякие штуки, которые поддерживает компилятор, и при просмотре увидел разные интересные (и не очень) штуки (и стандартные, и специфические для конкретного компилятора). Расскажу про несколько из них.
1. Тут в п.6 я писал про new_handler. Аналогичные штуки есть для std::terminate и std::unexpected.
2. Есть целый пак контейнеров, которые расширяют то, что есть в стандартной библиотеке. Некоторые концептуально повторяют уже существующие, некоторые нет:
- какая-то реализация для красно-чёрного дерева;
- реализация rope;
- реализация slist, что, кажется, просто forward list;
- какая-то ещё одна реализация строк под названием __versa_string;
- dynamic_bitset. Хотя конечно лучше брать такое в boost;
- думаю, многим известный valarray;
- gslice, являющийся подмножеством valarray;
- indirect_array, которые тоже подмножество valarray, но зададётся множеством индексов элементов;
- mask_array, задающий подмножество битовой маской.
- mini_vector, являющийся урезанной версией
- gp_hash_table — общий класс для hash-based ассоциативных контейнеров. Из интересного тут можно задавать свою resize policy (думал про такое для вектора когда-то).
3. Разные алгоритмы:
- subtractive_rng — генератор случайных чисел, основанный на каком-то там алгоритме;
- функция для нахождения медианы. Интересно, как это нормально делать сейчас стандартной библиотекой, чтобы не складывать числа в контейнер и не юзать
4. Всякие utils:
- реализация decimal;
- bitmap_allocator;
- freelist (про него и чувака выше можно почитать тут);
- пак утилит для дебага.
5. Type traits:
- реализации is_detected и detected_or;
- is_fast_hash, который реализован как угар имхо: для всех типов он fast, а для long double нет😏
Но вообще тут поинт в том, что вы как юзер можете написать специализацию, которая говорит, что для вашего типа хеш считается долго. Контейнер при этом будет кешировать значения хешей.
Короч накодили и живут себе.
Наткнулся случайно на доку gcc, где описаны всякие штуки, которые поддерживает компилятор, и при просмотре увидел разные интересные (и не очень) штуки (и стандартные, и специфические для конкретного компилятора). Расскажу про несколько из них.
1. Тут в п.6 я писал про new_handler. Аналогичные штуки есть для std::terminate и std::unexpected.
2. Есть целый пак контейнеров, которые расширяют то, что есть в стандартной библиотеке. Некоторые концептуально повторяют уже существующие, некоторые нет:
- какая-то реализация для красно-чёрного дерева;
- реализация rope;
- реализация slist, что, кажется, просто forward list;
- какая-то ещё одна реализация строк под названием __versa_string;
- dynamic_bitset. Хотя конечно лучше брать такое в boost;
- думаю, многим известный valarray;
- gslice, являющийся подмножеством valarray;
- indirect_array, которые тоже подмножество valarray, но зададётся множеством индексов элементов;
- mask_array, задающий подмножество битовой маской.
- mini_vector, являющийся урезанной версией
std::vector и работающий только для built-in и POD типов. А ещё он память не чистит🤪- gp_hash_table — общий класс для hash-based ассоциативных контейнеров. Из интересного тут можно задавать свою resize policy (думал про такое для вектора когда-то).
3. Разные алгоритмы:
- subtractive_rng — генератор случайных чисел, основанный на каком-то там алгоритме;
- функция для нахождения медианы. Интересно, как это нормально делать сейчас стандартной библиотекой, чтобы не складывать числа в контейнер и не юзать
nth_element. Пропозалов на это не видел. 4. Всякие utils:
- реализация decimal;
- bitmap_allocator;
- freelist (про него и чувака выше можно почитать тут);
- пак утилит для дебага.
5. Type traits:
- реализации is_detected и detected_or;
- is_fast_hash, который реализован как угар имхо: для всех типов он fast, а для long double нет
Но вообще тут поинт в том, что вы как юзер можете написать специализацию, которая говорит, что для вашего типа хеш считается долго. Контейнер при этом будет кешировать значения хешей.
Короч накодили и живут себе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10👌2❤1🔥1
#highload #pub
Мы с коллегой немножко напряглись и написали статью про то, как у нас работает поиск. Прошу к столу.
https://habr.com/ru/companies/yandex/articles/748134/
Мы с коллегой немножко напряглись и написали статью про то, как у нас работает поиск. Прошу к столу.
https://habr.com/ru/companies/yandex/articles/748134/
Хабр
Три движка для одной Лавки: как эволюционировала система поиска в сервисе
Лавка — сервис быстрой доставки продуктов. Один из важнейших сценариев использования сервиса для покупателя — это поиск. Примерно 30% товаров добавляются в корзину именно из его результатов. А ещё,...
❤24🔥13
#cpp
C++ Zero Cost Conf 2023.
Трек в Москве (link на трансляцию).
Был доклад про устройство компиляторов (я базово писал про это) и зачем в VK свой.
> Тут докладчик сказал, что они написали свой compiler и ускорили бекенд в 10 раз. Подумал, что очень хороший план писать на чём-то вроде php, чтобы потом переписать или накрутить трансляцию в плюсы и говорить, что всё очень сильно ускорили😂
> Оказалось, что доклад реально про KPHP, про который они уже рассказывали мильён раз в других местах🤯
Константин Владимиров рассказывал про масштабируемую векторизацию RISCV. Я не поклонник подобных низкоуровневых штук, потому скипнул. Но являюсь фанатом Константина, так что, если тема вам интересна, можно посмотреть. Уверен, доклад крутой и понятный.
У Ильи Шишкова был доклад под названием “Не с первого раза: упрощаем С++ код с помощью DSL”. Доклад примерно про то, как ребята решали какую-то бизнесовую задачу (я такое очень люблю). Я не прям понял всю специфику задачи, но солв интересный, не прям тривиальный C++ (всё понятно, но не циклы с ифами), процесс движения по задаче знаком (я думаю) каждому, рассказывает он хорошо. Можно смотреть.
От Романа Русяева был доклад про концепции неопределённого поведения (зачем оно всё же нужно? кроме как бесить программистов конечно же). Рассказ не под пиво (мне пришлось иногда напрягаться), но это даже и хорошо. Примеры интересные. Можно смотреть.
Доклад про корутины скипнул.
Антон Полухин рассказал новости от рабочей группы 21. Я делал выжимку в феврале. Докину про C++26:
- можно будет использовать плейсхолдер🤯 ;
- нормальный
- hazard pointer и rcu;
-
-
- ещё больше
-
- хеширование для типов из
- рефлексия пока не готова. Мб повезёт и будет в 26м стандарте (мб нет);
- контракты могут к 26ому стандарту доехать;
и всякое разное ещё.
Ощущается, что на некоторые вопросы Антон не пытался отвечать и просто съезжал👀
Что-то московский трек не очень порадовал. Есть ощущение, что конфа делается чтобы делать конфу. Завтра расскажу про белградскую часть.
C++ Zero Cost Conf 2023.
Трек в Москве (link на трансляцию).
Был доклад про устройство компиляторов (я базово писал про это) и зачем в VK свой.
> Тут докладчик сказал, что они написали свой compiler и ускорили бекенд в 10 раз. Подумал, что очень хороший план писать на чём-то вроде php, чтобы потом переписать или накрутить трансляцию в плюсы и говорить, что всё очень сильно ускорили
> Оказалось, что доклад реально про KPHP, про который они уже рассказывали мильён раз в других местах🤯
Константин Владимиров рассказывал про масштабируемую векторизацию RISCV. Я не поклонник подобных низкоуровневых штук, потому скипнул. Но являюсь фанатом Константина, так что, если тема вам интересна, можно посмотреть. Уверен, доклад крутой и понятный.
У Ильи Шишкова был доклад под названием “Не с первого раза: упрощаем С++ код с помощью DSL”. Доклад примерно про то, как ребята решали какую-то бизнесовую задачу (я такое очень люблю). Я не прям понял всю специфику задачи, но солв интересный, не прям тривиальный C++ (всё понятно, но не циклы с ифами), процесс движения по задаче знаком (я думаю) каждому, рассказывает он хорошо. Можно смотреть.
От Романа Русяева был доклад про концепции неопределённого поведения (зачем оно всё же нужно? кроме как бесить программистов конечно же). Рассказ не под пиво (мне пришлось иногда напрягаться), но это даже и хорошо. Примеры интересные. Можно смотреть.
Доклад про корутины скипнул.
Антон Полухин рассказал новости от рабочей группы 21. Я делал выжимку в феврале. Докину про C++26:
- можно будет использовать плейсхолдер
_ для неиспользуемых переменных (много раз в рамках области видимости). Теперь читы с макросами для получения анонимных имён не нужны (3й пункт). Тут Антон несколько раз говорил, что комитет смотрел на несколько крупных кодовых баз, чтобы реальные юзкейсы для каких-то фич и делал из этого какие-то выводы. С одной стороны круто. С другой стороны имхо параша какая-то. Словил вайб подгонки некоторых фичей под существующий у кого-то говнокод- нормальный
std::to_string для floating_point;- hazard pointer и rcu;
-
native_handle какой-то для получения дескрипторов файлов;-
std::function_ref;- ещё больше
constexpr (для комплексных чисел например);-
std::submdspan — подмножество std::mdspan из C++23 (код какой-то оч неприятный конечно с этими штуками);- хеширование для типов из
std::chrono;- рефлексия пока не готова. Мб повезёт и будет в 26м стандарте (мб нет);
- контракты могут к 26ому стандарту доехать;
и всякое разное ещё.
Ощущается, что на некоторые вопросы Антон не пытался отвечать и просто съезжал
Что-то московский трек не очень порадовал. Есть ощущение, что конфа делается чтобы делать конфу. Завтра расскажу про белградскую часть.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤2💔2
#cpp
C++ Zero Cost Conf 2023.
Трек в Белграде (link на трансляцию).
Первый доклад был про layout классов в C++. Как-то базово по ощущениям получилось. Имхо не для конференций такого левела (ну или я ту мач от неё ожидаю просто).
Второй — Акторная система YDB: история оптимизаций, позволивших обогнать конкурентов. Ещё не было ни одного доклада от челов из YDB, который мне зашёл, так что я скипнул. Мб потому что предметная область в целом не оч интересна.
Андрей Аксёнов рассказывал доклад под названием “Очередная крафтовая хеш-таблица”. Я в целом к его манере рассказывать привык, но какой-то конкретики в докладе не увидел. Можно послушать, но какие-то абстрактные рассуждения получились.
Хотя в целом я доклады Андрея люблю, потому что после них потом можно сидеть и гуглить всякие штуки довольно долго, просто потому что он упоминает много всего.
Был доклад от Александра Малкова про grpc и userver. Слушать немножко тяжеловато.
Я полгода назад смотрел, что там и как поддерживается и в тот момент нужны были довольно большие приседания, чтобы получить то, что есть для http. Если ребята и правда там поддержали много всего нужного, круто.
Правда словил вайб, что чересчур реклама какая-то фреймворка, но может докладчику реально очень нравится. В целом мы на нём живём. Проблем не ощущается.
Доклад Александра Боргардрта не слушал, т.к. он рассказывал то же самое на C++ Russia в мае (мб конечно что-то поменялось, но я не завлёкся послушать фулл доклад ради каких-то точечных отличий).
Я правда послушал его ответы на вопросы и что-то как-то токсично..
Последний доклад — Парсим числа через SIMD от Сергея Слотина (у него в прошлом году был неплохой доклад про ускорение бинпоиска). Я походу не оч осознал задачу, но там ускоряется парсинг чисел в json. Что это за джсоны такие интересно, в которых чисел так много, что подобные приседания становятся полезны.
А ещё осознал, что мне не понравилось в плане съёмок. Я как-то привык к CppCon и считаю, что там оч хорошо эта часть сделана. В записях там всегда есть преза и отдельным окошком докладывающий. Тут же иногда меняются планы (я вот слайд читал -> план поменялся -> не могу читать слайд -> жду, пока вернётся стандартный план), зачем-то показываются слушающие. Не прям удобно.
Потраченного времени не жаль, но верю, что ребята могут и сделают в будущем лучше.
C++ Zero Cost Conf 2023.
Трек в Белграде (link на трансляцию).
Первый доклад был про layout классов в C++. Как-то базово по ощущениям получилось. Имхо не для конференций такого левела (ну или я ту мач от неё ожидаю просто).
Второй — Акторная система YDB: история оптимизаций, позволивших обогнать конкурентов. Ещё не было ни одного доклада от челов из YDB, который мне зашёл, так что я скипнул. Мб потому что предметная область в целом не оч интересна.
Андрей Аксёнов рассказывал доклад под названием “Очередная крафтовая хеш-таблица”. Я в целом к его манере рассказывать привык, но какой-то конкретики в докладе не увидел. Можно послушать, но какие-то абстрактные рассуждения получились.
Хотя в целом я доклады Андрея люблю, потому что после них потом можно сидеть и гуглить всякие штуки довольно долго, просто потому что он упоминает много всего.
Был доклад от Александра Малкова про grpc и userver. Слушать немножко тяжеловато.
Я полгода назад смотрел, что там и как поддерживается и в тот момент нужны были довольно большие приседания, чтобы получить то, что есть для http. Если ребята и правда там поддержали много всего нужного, круто.
Правда словил вайб, что чересчур реклама какая-то фреймворка, но может докладчику реально очень нравится. В целом мы на нём живём. Проблем не ощущается.
Доклад Александра Боргардрта не слушал, т.к. он рассказывал то же самое на C++ Russia в мае (мб конечно что-то поменялось, но я не завлёкся послушать фулл доклад ради каких-то точечных отличий).
Я правда послушал его ответы на вопросы и что-то как-то токсично..
Последний доклад — Парсим числа через SIMD от Сергея Слотина (у него в прошлом году был неплохой доклад про ускорение бинпоиска). Я походу не оч осознал задачу, но там ускоряется парсинг чисел в json. Что это за джсоны такие интересно, в которых чисел так много, что подобные приседания становятся полезны.
А ещё осознал, что мне не понравилось в плане съёмок. Я как-то привык к CppCon и считаю, что там оч хорошо эта часть сделана. В записях там всегда есть преза и отдельным окошком докладывающий. Тут же иногда меняются планы (я вот слайд читал -> план поменялся -> не могу читать слайд -> жду, пока вернётся стандартный план), зачем-то показываются слушающие. Не прям удобно.
Потраченного времени не жаль, но верю, что ребята могут и сделают в будущем лучше.
👍16❤3👎1
#common #cpp
0. Это вообще довольно известная штука, но я о ней не писал, так что поделюсь.
Когда вы учите C++, вам говорят, что возвращаемое значение на перегрузку не влияет. Но это не значит, что нельзя использовать силу рук, чтобы намутить такое. Мы же всё-таки на C++ пишем☺️
Пусть есть две функции, которые отличаются только возвращаемым значением:
Мы хотим, чтобы следующий код заработал:
Нам поможет вот такая замечательная структура:
у которой операторы приведения типа как раз совершают необходимую логику, соответствующую функциям
Ну или можно сделать немножко аккуратнее и написать общую функцию, чтобы детали реализации не висели наружу:
И ссылочки.
1. Unexpected downsides of UUID keys in PostgreSQL.
2. Big Data is Dead. Статья прикольная, потому что идёт вразрез с моим мироощущением, где данных очень много и рано или поздно это начнёт приносить проблемы.
3. Goodbye, Clean Code.
0. Это вообще довольно известная штука, но я о ней не писал, так что поделюсь.
Когда вы учите C++, вам говорят, что возвращаемое значение на перегрузку не влияет. Но это не значит, что нельзя использовать силу рук, чтобы намутить такое. Мы же всё-таки на C++ пишем
Пусть есть две функции, которые отличаются только возвращаемым значением:
int process(std::string s);
bool process(std::string s);Мы хотим, чтобы следующий код заработал:
int i = process(some_string);
bool b = process(some_string);Нам поможет вот такая замечательная структура:
struct converter {
std::string s;
operator int() const;
operator bool() const;
};у которой операторы приведения типа как раз совершают необходимую логику, соответствующую функциям
process. Тогда наш код превращается в int i = converter{some_string};
bool b = converter{some_string};Ну или можно сделать немножко аккуратнее и написать общую функцию, чтобы детали реализации не висели наружу:
converter process(std::string s) {
return converter{s};
}
int i = process(some_string);
bool b = process(some_string);И ссылочки.
1. Unexpected downsides of UUID keys in PostgreSQL.
2. Big Data is Dead. Статья прикольная, потому что идёт вразрез с моим мироощущением, где данных очень много и рано или поздно это начнёт приносить проблемы.
3. Goodbye, Clean Code.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27❤4😈3😁2🤯1
#common
Мои ребята делают стартап со стримингом музыки.
Суть кратко:
- есть треки, на которые вы можете покупать nft;
- когда этот трек слушается на платформе, вы (пользователь) получаете доход в токенах;
- исполнитель получает доход как обычно + часть токенов с продаж nft;
- вы можете поддерживать артистов и зарабатывать на угадывании трендов.
На днях они выложили статью про то, как у них работает так называемая tokenomics, как они её моделировали, какие есть проблемные места. Учитывая, что я не прям в этой всей теме, получилось интересно.
Мои ребята делают стартап со стримингом музыки.
Суть кратко:
- есть треки, на которые вы можете покупать nft;
- когда этот трек слушается на платформе, вы (пользователь) получаете доход в токенах;
- исполнитель получает доход как обычно + часть токенов с продаж nft;
- вы можете поддерживать артистов и зарабатывать на угадывании трендов.
На днях они выложили статью про то, как у них работает так называемая tokenomics, как они её моделировали, какие есть проблемные места. Учитывая, что я не прям в этой всей теме, получилось интересно.
🤯15🤡6🔥4❤1👍1
#common #algo
Сегодня немножко математики.
Я думаю, что многие, кто занимался олимпиадами по информатике/спортивным программированием про это знают. Но когда-то мне очень сильно понравилась тема с ускорением подсчёта некоторых дп, если они являются линейной комбинацией прошлых вычисленных значений.
Предположим у нас есть следующее дп (не будем расписывать в общем виде):
с какой-то базой. Например
Предположим, мы хотим вычислить несколько конкретных значений (
Давайте посмотрим на это в виде матриц. Базовая матрица у нас имеет вид (это не определитель, я просто скобки не умею нормально рисовать):
где
Если мы перемножим матрицу ниже на столбец выше
мы получим вектор
в котором мы по факту получили сдвиг в нашей дп-шной последовательности на 1 вперёд (то есть вычислили
А теперь предположим, мы хотим найти
То есть по факту вы можете считать любую подобную “линейную” последовательность быстро для любого адекватного значения
Сегодня немножко математики.
Я думаю, что многие, кто занимался олимпиадами по информатике/спортивным программированием про это знают. Но когда-то мне очень сильно понравилась тема с ускорением подсчёта некоторых дп, если они являются линейной комбинацией прошлых вычисленных значений.
Предположим у нас есть следующее дп (не будем расписывать в общем виде):
dp[i] = 2dp[i-1] + 3dp[i-2] - dp[i-3]с какой-то базой. Например
dp[0, 1, 2] = {1, 2, 3}Предположим, мы хотим вычислить несколько конкретных значений (
dp[10^3], dp[10^15], то есть значения с очень большими номером), а не все (обычно так и бывает). Давайте посмотрим на это в виде матриц. Базовая матрица у нас имеет вид (это не определитель, я просто скобки не умею нормально рисовать):
| 1 |
a = | 2 |
| 3 |где
a_i это соответственно dp_i, i \in [0; 2]. Если мы перемножим матрицу ниже на столбец выше
| 0 1 0|
M = | 0 0 1|
|-1 3 2|мы получим вектор
| 2 |
| 3 |
| 11 |в котором мы по факту получили сдвиг в нашей дп-шной последовательности на 1 вперёд (то есть вычислили
dp[2], dp[3] и dp[4]). А теперь предположим, мы хотим найти
dp[n]. Конечно, эту последовательность умножений можно повторять раз за разом n - 3 раза, пока мы не получим нужный элемент. Но в чём тогда был смысл подобных движений? Давайте сначала нашу матрицу перехода бинарно возведём в (n-3)-ю степень и только потом умножим вектор a. Чтобы получить ответ, достаточно будет взять последний элемент получившегося столбца:ans = (bin_pow(M, n - 3) * a)[2];То есть по факту вы можете считать любую подобную “линейную” последовательность быстро для любого адекватного значения
n. Я когда-то, например, писал нахождение n-ого числа Фибоначчи на компиляции. Тут правда надо быть аккуратным с глубиной рекурсии и возможно подкрутить флаг -ftemplate-depth.👍19🤯5❤2🔥2
#common
1. Ubiquitous Caching: a Journey of Building Efficient Distributed and In-Process Caches at Twitter.
Доклад прикольный, но у infoq есть проблема, что они выкладывают именно расшифровку (т.е. картиночки вы не увидите). А сам доклад слушать тяжеловато (какие-то траблы со звуком). Может лучше тогда посмотреть короткий видос про устройство Segcache тут.
2. Building a strong knowledge sharing culture on engineering teams.
Это скорее заметка, которая рекламит конкретный продукт. И заголовок у неё кликбейтный. Но проблемы с документацией ребята описали хорошо.
3. HTTP/3 From A To Z: Core Concepts.
4. Should That Be a Microservice? Keep These Six Factors in Mind.
Ну и на этом пока всё.
Неделя получилась плотнее обычного по постам, но это выброс : )
1. Ubiquitous Caching: a Journey of Building Efficient Distributed and In-Process Caches at Twitter.
Доклад прикольный, но у infoq есть проблема, что они выкладывают именно расшифровку (т.е. картиночки вы не увидите). А сам доклад слушать тяжеловато (какие-то траблы со звуком). Может лучше тогда посмотреть короткий видос про устройство Segcache тут.
2. Building a strong knowledge sharing culture on engineering teams.
Это скорее заметка, которая рекламит конкретный продукт. И заголовок у неё кликбейтный. Но проблемы с документацией ребята описали хорошо.
3. HTTP/3 From A To Z: Core Concepts.
4. Should That Be a Microservice? Keep These Six Factors in Mind.
Ну и на этом пока всё.
Неделя получилась плотнее обычного по постам, но это выброс : )
👍6❤1🤯1
#common
В рамках постов про поиск расскажу про boolean retrieval model (источник — стенфордская книжка, которую мне накидывали в комментах).
> Почему retrieval? Вообще вот эта вся тема с поиском она скорее про извлечение информации из какого-то множества. Так и говорят: information retrieval (IR).
Предположим, мы хотим найти главы книги, для которых верно, что есть слова A и B, но нет слова C. Конечно, мы можем пройтись по тексту от начала до конца за O(n) и проверить выполнение условий для каждой главы, но в рамках реально огромных текстов и большого количества запросов это может быть неэффективно. Давайте запрепроцессим наш текст (индексируем его, поставив 1, если слово встречается в главе, и 0 иначе):
Так для каждого слова имеем булевый вектор. Давай ответим на запрос. Для этого сделаем
То есть наши условия выполняются для Ch1 и Ch4.
Boolean retrieval model — модель IR, когда любой запрос можно сформулировать в виде булевых операций над булевыми векторами для термов (терм == токен).
Если взять какие-то более реальные данные, то подобная матрица будет довольно разреженной, потому лучше хранить только единички. Так и появляется инвертированный индекс: когда для каждого терма хранится множество документов, в которых этот терм встречается. В инвертированном индексе обычно хранят постинги (posting) — вся инфа про терм в документе. В примере выше это был факт наличия, но в него можно класть ещё позицию в документе и что угодно ещё.
Множество постингов для терма обычно хранят на диске (предварительно это всё сжимается). Тут конечно встаёт вопрос, в каком виде. С одной стороны, можно хранить
Если мы хотим в рамках boolean retrieval ответить на запрос вроде
Несложно добавляется и условие на отсутствие терма (
Если в запросе есть
можно проверить сначала
B & C, если множества постингов для этих термов имеют минимальный размер (возможно потребуется предварительно привести запрос к дизъюнктивной нормальной форме).
Или можно бинарным поиском поискать id документов из более короткого листа постингов в более длинном.
Короче микрооптимизации такие.
Иногда в подобных системах реализуют так называемые proximity operators, которые задают более сложные условия на ответ. Например, как близко слова должны быть расположены в итоговом документе.
Из примеров коммерческого поиска с boolean retrieval model есть westlaw.com (правда там обязательный логин перед использованием).
В противовес этой модели существует ranked retrieval model, в которой запрос это просто текст (все мы пользуемся таким подходом, когда что-то гуглим).
В рамках постов про поиск расскажу про boolean retrieval model (источник — стенфордская книжка, которую мне накидывали в комментах).
> Почему retrieval? Вообще вот эта вся тема с поиском она скорее про извлечение информации из какого-то множества. Так и говорят: information retrieval (IR).
Предположим, мы хотим найти главы книги, для которых верно, что есть слова A и B, но нет слова C. Конечно, мы можем пройтись по тексту от начала до конца за O(n) и проверить выполнение условий для каждой главы, но в рамках реально огромных текстов и большого количества запросов это может быть неэффективно. Давайте запрепроцессим наш текст (индексируем его, поставив 1, если слово встречается в главе, и 0 иначе):
Ch1 Ch2 Ch3 Ch4 Ch5
A 1 1 0 1 0
B 1 0 1 1 1
C 0 1 1 0 0
D 0 0 0 1 1
…Так для каждого слова имеем булевый вектор. Давай ответим на запрос. Для этого сделаем
AND векторам слов A и B и инвертированного вектора С:11010 & 10111 & 10011 = 10010То есть наши условия выполняются для Ch1 и Ch4.
Boolean retrieval model — модель IR, когда любой запрос можно сформулировать в виде булевых операций над булевыми векторами для термов (терм == токен).
Если взять какие-то более реальные данные, то подобная матрица будет довольно разреженной, потому лучше хранить только единички. Так и появляется инвертированный индекс: когда для каждого терма хранится множество документов, в которых этот терм встречается. В инвертированном индексе обычно хранят постинги (posting) — вся инфа про терм в документе. В примере выше это был факт наличия, но в него можно класть ещё позицию в документе и что угодно ещё.
Множество постингов для терма обычно хранят на диске (предварительно это всё сжимается). Тут конечно встаёт вопрос, в каком виде. С одной стороны, можно хранить
std::vector постингов, так как тут минимален оверхед и данные лежат рядом. С другой стороны для быстрых вставок может лучше подойти какой-нибудь список. Учитывая, что постинги обычно отсортированы, при надобности даже скиплисты можно использовать (писал про них тут).Если мы хотим в рамках boolean retrieval ответить на запрос вроде
A & B, достаточно просто взять постинги для нужных термов и пересечь их.Несложно добавляется и условие на отсутствие терма (
A & B & !C). Это всё тривиально делается двумя указателями.Если в запросе есть
OR, то можно немного улучшить и посмотреть на размеры тех или иных множеств постингов. Условно для (A | B) & (C | D)можно проверить сначала
B & C, если множества постингов для этих термов имеют минимальный размер (возможно потребуется предварительно привести запрос к дизъюнктивной нормальной форме).
Или можно бинарным поиском поискать id документов из более короткого листа постингов в более длинном.
Короче микрооптимизации такие.
Иногда в подобных системах реализуют так называемые proximity operators, которые задают более сложные условия на ответ. Например, как близко слова должны быть расположены в итоговом документе.
Из примеров коммерческого поиска с boolean retrieval model есть westlaw.com (правда там обязательный логин перед использованием).
В противовес этой модели существует ranked retrieval model, в которой запрос это просто текст (все мы пользуемся таким подходом, когда что-то гуглим).
🔥7👍5❤2
#cpp
Что выведет следующий код?
Правильно. 42.
Про это, про explicit initialization, hidden friends и суммарно про то, как получить доступ к приватным методам любого класса можно прочесть в этой замечательной статье про один из трюков, найденных в folly.
Пока больше статей не насобирал ¯\_(ツ)_/¯
Что-то не залетает в последнее время.
==============================
В последнее время очень много статей про serverless архитектуры и штуки рядом. Я пока не оч вдупляю, зачем это надо, потому уверенно скипаю. Если вы что-то в этом понимаете и можете рассказать, зачем это надо и почему упрощает жизнь, накидывайте в комменты. Может я зря отказываюсь от такого контента.
Что выведет следующий код?
template <int N>
class SpookyAction {
friend int observe() {
return N;
}
};
int observe();
int main() {
SpookyAction<42>{};
std::cout << observe();
}Про это, про explicit initialization, hidden friends и суммарно про то, как получить доступ к приватным методам любого класса можно прочесть в этой замечательной статье про один из трюков, найденных в folly.
Пока больше статей не насобирал ¯\_(ツ)_/¯
Что-то не залетает в последнее время.
==============================
В последнее время очень много статей про serverless архитектуры и штуки рядом. Я пока не оч вдупляю, зачем это надо, потому уверенно скипаю. Если вы что-то в этом понимаете и можете рассказать, зачем это надо и почему упрощает жизнь, накидывайте в комменты. Может я зря отказываюсь от такого контента.
👏7👍3❤2🤔2
#highload #common
0. Вадим Кравченко про то, почему старый код это хорошо: link.
0. Why an Engineering Manager Should Not Review Code.
Хорошая статья про отличия engineering manager и technical lead.
0. Sidekick’s Improved Streaming Experience.
С развитием LLM’ок появляются новые задачи вроде красивого отображения их ответов. Хех, но прикона.
0. When Taylor Swift crashed Ticketmaster: A lesson on scaling for spikes.
Вроде классика, но вот интересно было бы узнать более подробно, как борются с ситуациями, когда спайки нагрузок могут быть х10-х100+.
0. Вадим Кравченко про то, почему старый код это хорошо: link.
0. Why an Engineering Manager Should Not Review Code.
Хорошая статья про отличия engineering manager и technical lead.
0. Sidekick’s Improved Streaming Experience.
С развитием LLM’ок появляются новые задачи вроде красивого отображения их ответов. Хех, но прикона.
0. When Taylor Swift crashed Ticketmaster: A lesson on scaling for spikes.
Вроде классика, но вот интересно было бы узнать более подробно, как борются с ситуациями, когда спайки нагрузок могут быть х10-х100+.
👍2❤1
#cpp #highload
-2. Asking questions the right way.
Я кстати как-то писал что-то около этого, но тут конечно статья совсем конфета.
-1. C/C++ performance pitfall: int8_t, aliasing and the ways out.
0. Scaling the Instagram Explore recommendations system.
Интересные мльные штуки узнал. Например про подход Two Tower модели.
1. Any Day Can Be Prime Day: How Amazon.com Search Uses Chaos Engineering to Handle Over 84K Requests Per Second.
Опять тут aws lambda какая-то, но прикона. Про chaos engineering писал чуть-чуть ранее.
-2. Asking questions the right way.
Я кстати как-то писал что-то около этого, но тут конечно статья совсем конфета.
-1. C/C++ performance pitfall: int8_t, aliasing and the ways out.
0. Scaling the Instagram Explore recommendations system.
Интересные мльные штуки узнал. Например про подход Two Tower модели.
1. Any Day Can Be Prime Day: How Amazon.com Search Uses Chaos Engineering to Handle Over 84K Requests Per Second.
Опять тут aws lambda какая-то, но прикона. Про chaos engineering писал чуть-чуть ранее.
👍4❤1
this->notes.
#common О подходах к реализации шаблонов/дженериков. В C++ всё просто и понятно. Каждый раз, когда вы используете шаблонный тип или шаблон функции с новым типом, компилятор просто генерирует конкретную специализацию для него. Отсюда возникают такие проблемы…
Сначала я хотел обновить и расширить инфой пост про дженерики.
Потом я нашёл статью, которая очень хорошо описывает базовые подходы реализации дженериков в различных языках программирования: link. Подумал, что можно было бы перевести её на хабр. Такое вот полезное упражнение.
Потом я поискал уже готовый перевод на хабре. И такой есть: link. Так что в итоге я ничего не сделал. Но почитать можно : )
Потом я нашёл статью, которая очень хорошо описывает базовые подходы реализации дженериков в различных языках программирования: link. Подумал, что можно было бы перевести её на хабр. Такое вот полезное упражнение.
Потом я поискал уже готовый перевод на хабре. И такой есть: link. Так что в итоге я ничего не сделал. Но почитать можно : )
🫡24👍5🐳2❤1
#common
Исправление очепяток 1/2.
Я думаю, понятно, зачем нужно уметь исправлять запросы, но вот хороший пример от Google про то, как люди ищут Britney Spears: link. Тут и brittiny spears, и drittney spears, и buttney spears, и много всего другого.
Исправления обычно делят на два вида: isolated-term correction (когда пытаемся исправить каждый отдельный терм запроса отдельно) и context-sensitive (когда каждый отдельный терм корректен, но при этом они не согласуются друг с другом). Сначала про первое.
Есть два основных, применяющихся вместе, алгоритмических метода исправлять опечатки: по расстоянию между строками (edit distance) и по пересечению n-грамм.
Когда говорят про расстояние между строками, обычно имеют в виду, что есть некоторое множество операций (например, добавление, удаление и замена символа), и тогда расстоянием между s1 и s2 будет кол-во операций, нужное, чтобы превратить одну строку в другую (в данном случае это расстояние Левенштейна). В общем случае различным операциям может назначаться разный вес (например изменить гласную на другую гласную это семантически “дешевле”, чем гласную на согласную; или пользователи часто промахиваются по клавиатуре, что означает, что некоторые ошибки в буквах возникают чаще).
Нахождение расстояния Левенштейна между двумя строками это известная таска на динамическое программирование. Однако в рамках больших поисковых индексов подобная операция для всех пар (терм запроса, терм в индексе) будет занимать огромное время. Потому это не прям хорошее решение, однако на него в более простых случаях можно наворачивать разные эвристики. Например одной из простых может быть предположение, что пользователь не ошибся в первом символе слова (в общем случае в первых k символах), что означает сужение поиска по индексу лишь среди термов, которые начинаются на тот же префикс.
Или можно например использовать улучшение метрики Левенштейна под названием Дамерау-Левенштейн, где разрешено переставлять символы.
Иногда (даже всегда) работают не с расстояниями, а с вероятностями. Например можно посчитать
где
Исправление очепяток 1/2.
Я думаю, понятно, зачем нужно уметь исправлять запросы, но вот хороший пример от Google про то, как люди ищут Britney Spears: link. Тут и brittiny spears, и drittney spears, и buttney spears, и много всего другого.
Исправления обычно делят на два вида: isolated-term correction (когда пытаемся исправить каждый отдельный терм запроса отдельно) и context-sensitive (когда каждый отдельный терм корректен, но при этом они не согласуются друг с другом). Сначала про первое.
Есть два основных, применяющихся вместе, алгоритмических метода исправлять опечатки: по расстоянию между строками (edit distance) и по пересечению n-грамм.
Когда говорят про расстояние между строками, обычно имеют в виду, что есть некоторое множество операций (например, добавление, удаление и замена символа), и тогда расстоянием между s1 и s2 будет кол-во операций, нужное, чтобы превратить одну строку в другую (в данном случае это расстояние Левенштейна). В общем случае различным операциям может назначаться разный вес (например изменить гласную на другую гласную это семантически “дешевле”, чем гласную на согласную; или пользователи часто промахиваются по клавиатуре, что означает, что некоторые ошибки в буквах возникают чаще).
Нахождение расстояния Левенштейна между двумя строками это известная таска на динамическое программирование. Однако в рамках больших поисковых индексов подобная операция для всех пар (терм запроса, терм в индексе) будет занимать огромное время. Потому это не прям хорошее решение, однако на него в более простых случаях можно наворачивать разные эвристики. Например одной из простых может быть предположение, что пользователь не ошибся в первом символе слова (в общем случае в первых k символах), что означает сужение поиска по индексу лишь среди термов, которые начинаются на тот же префикс.
Или можно например использовать улучшение метрики Левенштейна под названием Дамерау-Левенштейн, где разрешено переставлять символы.
Иногда (даже всегда) работают не с расстояниями, а с вероятностями. Например можно посчитать
p(w|s) – вероятность того, что имели в виду терм w, при условии, что получили терм s (эту величину мы пытаемся максимизировать). Тут применяем формулу Байеса:p(w|s) = C * p(s|w) * p(w),где
p(s|w) – вероятность того, что при наборе w можно получить s, а p(w) – вероятность того, что пользователь мог использовать терм w (тут уже речь идёт про модель конкретного языка). Не будем уходить глубже в этом месте и пойдём дальше (хотя тут много интересных моментов есть, вроде того, что в языке постоянно появляются новые слова; что можно строить модели того, как пользователи ошибаются).🔥6❤1
#common
Исправление очепяток 2/2.
Для сокращения кол-ва термов, с которыми в итоге можно считать расстояние, также можно использовать n-граммы. Построим n-грамм индекс (отображение из n-граммы во множество термов в документах), а потом пройдёмся по нему и достанем те термы, которые имеют “много” общих n-грамм с запросом. Например у нас есть запрос bord и индекс над биграммами:
Уже обсуждавшимися методами можно пересечь множества термов для всех биграмм и при выборе кол-ва общих биграмм 2 получить результаты aboard, boardroom и border.
Т.к. выбор количества общих n-грамм сильно зависит от размеров строк, можно оперировать более общими понятиями вроде коэффициента Жаккара, означающим меру сходства множеств (упоминал его в посте про вероятностные сд).
В случае, если после нахождения ближайших термов получается несколько, можно брать более популярный. Например популярным можно назвать терм, который чаще встречается в индексированных документах. А ещё можно смотреть, как сами пользователи исправляют свои ошибки и выбирать ту версию, которую они выбирают чаще. Вот этот подход с популярностями юзается примерно в любом решении: от гугла до небольших самописных штук, которые я видел.
В этом месте кстати есть различные способы использовать это для юзера. Можно просто безусловно попробовать поиск по документам, учитывая исправления (как делаем мы), а можно явно предложить замену, как делают это крупные поисковики.
С точки зрения context-sensitive исправлений самым простым решением может быть попробовать изменить в запросе каждый отдельный терм и поискать результаты по всем подобным запросам, после чего на основании кол-ва результатов/их релевантности выбрать подходящую исправленную версию.
Конечно, количество подобных “исправленных” запросов может быть огромным. Потому тут опять же есть всякие эвристики. Например использовать только самые популярные формы термов (или сочетаний термов) с учётом действий пользователей.
Также важным инструментом является т.н. phonetic correction.
Основная идея – научиться генерировать “фонетический хеш” слов, который будет совпадать, если они произносятся одинаково, даже если пишутся по-разному. Подходы для подобных задач называются soundex алгоритмами. Тут можно вики почитать.
Исправление очепяток 2/2.
Для сокращения кол-ва термов, с которыми в итоге можно считать расстояние, также можно использовать n-граммы. Построим n-грамм индекс (отображение из n-граммы во множество термов в документах), а потом пройдёмся по нему и достанем те термы, которые имеют “много” общих n-грамм с запросом. Например у нас есть запрос bord и индекс над биграммами:
bo: aboard about boardroom border
or: border lord morbid sordid
rd: aboard ardent boardroom border
Уже обсуждавшимися методами можно пересечь множества термов для всех биграмм и при выборе кол-ва общих биграмм 2 получить результаты aboard, boardroom и border.
Т.к. выбор количества общих n-грамм сильно зависит от размеров строк, можно оперировать более общими понятиями вроде коэффициента Жаккара, означающим меру сходства множеств (упоминал его в посте про вероятностные сд).
В случае, если после нахождения ближайших термов получается несколько, можно брать более популярный. Например популярным можно назвать терм, который чаще встречается в индексированных документах. А ещё можно смотреть, как сами пользователи исправляют свои ошибки и выбирать ту версию, которую они выбирают чаще. Вот этот подход с популярностями юзается примерно в любом решении: от гугла до небольших самописных штук, которые я видел.
В этом месте кстати есть различные способы использовать это для юзера. Можно просто безусловно попробовать поиск по документам, учитывая исправления (как делаем мы), а можно явно предложить замену, как делают это крупные поисковики.
С точки зрения context-sensitive исправлений самым простым решением может быть попробовать изменить в запросе каждый отдельный терм и поискать результаты по всем подобным запросам, после чего на основании кол-ва результатов/их релевантности выбрать подходящую исправленную версию.
Конечно, количество подобных “исправленных” запросов может быть огромным. Потому тут опять же есть всякие эвристики. Например использовать только самые популярные формы термов (или сочетаний термов) с учётом действий пользователей.
Также важным инструментом является т.н. phonetic correction.
Основная идея – научиться генерировать “фонетический хеш” слов, который будет совпадать, если они произносятся одинаково, даже если пишутся по-разному. Подходы для подобных задач называются soundex алгоритмами. Тут можно вики почитать.
🔥5👍2❤1
#cpp #highload
1. Начался CppCon и первый доклад по традиции от Bjarne Stroustrup под названием Delivering Safe C++.
Говорил про заявление правительства США в отношении C/C++ (где обсуждалось неиспользование C++ как языка из-за его небезопасности), а ещё про то, что нужно уходить от модели языка C/C++ к С++ (т.е. что плюсы это отдельный язык, который хватит причислять к C).
Немножко говорил про то, что нельзя ломать совместимость ради новых фичей, т.к. это очень больно, но тем не менее язык должен развиваться. Цитата:
> We can’t break billions of lines of existing code. I say can’t, not shouldn’t. Because we can’t.
Много рассуждал про то, что такое безопасность и про то, что язык должен становиться безопаснее, потому что это то, чего от него сейчас хотят.
И показывал разные проблемы с рассуждениями.
Как обычно довольно абстрактно имхо. Но послушать можно.
Эх, ребят. На чём мы пишем.
2. Ещё из прикольного доклад от Herb Sutter с мыслями о том, “how we can refresh C++ itself” (то есть уже надо бы его refresh🙂 ). Позиционируется как продолжение прошлогоднего доклада про Cpp2, о котором я писал тут (п.1).
Сначала он рассказал о нескольких новых фичах, которые появились за год. Например:
- chained comparisons (причём это работает только для корректных в математическом смысле слова транзитивных условий):
- named
Дальше Herb рассказывал про метапрограммирование в Cpp2, только не вот это на шаблонах, а про нормальное вроде рефлексии и всего такого (и рядом про енамы (и flag_enum) и union’ы).
И дальше рассуждал про то, как безопаснее и эффективнее всего стоит переходить на новые технологии и как этого добиться. Мне понравилось.
3. Коротенькое видео про разницу между архитектурой и дизайном. Никогда про существование разницы не думал, а ещё там местами расплывчатые формулировки, но прикольно.
4. Небольшая статья про то, зачем на самом деле (не)нужны микросервисы.
1. Начался CppCon и первый доклад по традиции от Bjarne Stroustrup под названием Delivering Safe C++.
Говорил про заявление правительства США в отношении C/C++ (где обсуждалось неиспользование C++ как языка из-за его небезопасности), а ещё про то, что нужно уходить от модели языка C/C++ к С++ (т.е. что плюсы это отдельный язык, который хватит причислять к C).
Немножко говорил про то, что нельзя ломать совместимость ради новых фичей, т.к. это очень больно, но тем не менее язык должен развиваться. Цитата:
> We can’t break billions of lines of existing code. I say can’t, not shouldn’t. Because we can’t.
Много рассуждал про то, что такое безопасность и про то, что язык должен становиться безопаснее, потому что это то, чего от него сейчас хотят.
И показывал разные проблемы с рассуждениями.
Как обычно довольно абстрактно имхо. Но послушать можно.
Эх, ребят. На чём мы пишем.
2. Ещё из прикольного доклад от Herb Sutter с мыслями о том, “how we can refresh C++ itself” (то есть уже надо бы его refresh
Сначала он рассказал о нескольких новых фичах, которые появились за год. Например:
- chained comparisons (причём это работает только для корректных в математическом смысле слова транзитивных условий):
if min <= index < max {}- named
break/continue, чтобы можно было выходить сразу из нескольких циклов по метке. Дальше Herb рассказывал про метапрограммирование в Cpp2, только не вот это на шаблонах, а про нормальное вроде рефлексии и всего такого (и рядом про енамы (и flag_enum) и union’ы).
И дальше рассуждал про то, как безопаснее и эффективнее всего стоит переходить на новые технологии и как этого добиться. Мне понравилось.
3. Коротенькое видео про разницу между архитектурой и дизайном. Никогда про существование разницы не думал, а ещё там местами расплывчатые формулировки, но прикольно.
4. Небольшая статья про то, зачем на самом деле (не)нужны микросервисы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤1
#common
Аналитика на фронте 1/2.
Часто в разных продуктах можно встретить анализ каких-то пользовательских действий на клиенте (в нашем случае фронтенде), т.е. в приложении. Позже они используются для аналитических и не только штук. Как это используется и почему это нужно делать на клиенте, я сегодня верхнеуровнево и расскажу (с примерами из Лавки).
В основном для анализа важны агрегированные и анонимизированные данные о поведении пользователей – это позволяет нам делать приложение еще лучше и удобнее. Важно понимать, что даже агрегированные данные хранятся аккуратно и без лишней информации. Хотя для рекомендаций и персонализации, например, поиска иногда нужно понимать действия конкретного покупателя, но и это означает отсутствие открытых данных пользователей.
Теперь давайте поймём, почему данных на бекенде может быть недостаточно.
Взаимодействие фронтенд-бекенд обычно выглядит как дёрнули endpoint, получили данные и что-то отобразили пользователю. После этого пользователь может совершать множество разных действий, про которые на бекенде ничего не известно. Например тот факт, что клиент (фронтенд) запросил информацию от бекенда, не означает, что пользователь увидел эти данные; или что он в приложении что-то покликал и сделал какие-то важные для бизнеса действия; или невозможно на бекенде понять, как много пользователь провёл времени в приложении.
Какие пользовательские события можно анализировать?
Из полезного можно смотреть на просмотр контента пользователем. Если смотреть на сервисы вроде instagram/tiktok (у которых контент – основной инструмент привлечения пользователя) то им важно анализировать какой контент и как долго смотрит пользователь. От этого зависят их рекомендации – если пользователь долго смотрит видео с котиками, значит ему вероятно стоит показывать такого контента больше. Хотя конечно тут есть более сильные сигналы вроде лайка/дизлайка, которые также говорят, стоит ли подобное рекомендовать (однако я слышал, что в некоторых сервисах на дизлайки почти не смотрят). Но сегодня рексистемы у таких сервисов довольно мощные, чтобы суметь распознать ваши предпочтения по просмотрам (я например нигде ничего не лайкаю, но контентом наслаждаюсь).
Аналитика на фронте 1/2.
Часто в разных продуктах можно встретить анализ каких-то пользовательских действий на клиенте (в нашем случае фронтенде), т.е. в приложении. Позже они используются для аналитических и не только штук. Как это используется и почему это нужно делать на клиенте, я сегодня верхнеуровнево и расскажу (с примерами из Лавки).
В основном для анализа важны агрегированные и анонимизированные данные о поведении пользователей – это позволяет нам делать приложение еще лучше и удобнее. Важно понимать, что даже агрегированные данные хранятся аккуратно и без лишней информации. Хотя для рекомендаций и персонализации, например, поиска иногда нужно понимать действия конкретного покупателя, но и это означает отсутствие открытых данных пользователей.
Теперь давайте поймём, почему данных на бекенде может быть недостаточно.
Взаимодействие фронтенд-бекенд обычно выглядит как дёрнули endpoint, получили данные и что-то отобразили пользователю. После этого пользователь может совершать множество разных действий, про которые на бекенде ничего не известно. Например тот факт, что клиент (фронтенд) запросил информацию от бекенда, не означает, что пользователь увидел эти данные; или что он в приложении что-то покликал и сделал какие-то важные для бизнеса действия; или невозможно на бекенде понять, как много пользователь провёл времени в приложении.
Какие пользовательские события можно анализировать?
Из полезного можно смотреть на просмотр контента пользователем. Если смотреть на сервисы вроде instagram/tiktok (у которых контент – основной инструмент привлечения пользователя) то им важно анализировать какой контент и как долго смотрит пользователь. От этого зависят их рекомендации – если пользователь долго смотрит видео с котиками, значит ему вероятно стоит показывать такого контента больше. Хотя конечно тут есть более сильные сигналы вроде лайка/дизлайка, которые также говорят, стоит ли подобное рекомендовать (однако я слышал, что в некоторых сервисах на дизлайки почти не смотрят). Но сегодня рексистемы у таких сервисов довольно мощные, чтобы суметь распознать ваши предпочтения по просмотрам (я например нигде ничего не лайкаю, но контентом наслаждаюсь).
❤1
#common
Аналитика на фронте 2/2.
В нашем случае важными действиями для рекомендаций можно считать клики на конкретные товары (если пользователь кликнул на продукт, значит ему он интересен). Но есть и более сильные сигналы вроде добавления в корзину/покупки товара (добавить в корзину != купить). Подобную информацию можно также использовать, чтобы понимать, какие товары часто покупают вместе и учитывать это при рекомендациях.
Мы ещё используем данные о кликах (CTR) для ранжирования в поиске. Как мы писали в статье, мы учитываем, как часто пользователи кликают на конкретные товары для конкретного запроса. Логика простая: если большинству пользователей на фиксированном запросе понравился конкретный товар, то возможно текущему пользователю он тоже понравится, так что надо поднять его повыше.
Также подобную информацию можно использовать для различных оффлайн процессов. Если продолжать говорить про наш поиск, мы можем взять события просмотра поисковой выдачи и достать реальные пользовательские запросы. Далее мы можем получить выдачу от нашего поискового движка на этот конкретный запрос и отправить эти данные в Толоку. После того, как в Толоке данные будут размечены на (не)релевантность, мы можем собрать разные статистики и понять, насколько хорошо мы сейчас что-то ищем (тут правда стоит понимать, что в данной метрике речь идёт про качество (precision), а не полноту (recall)), собрать примеры нерелевантной выдачи и каким-то образом их починить.
Ну или можно посмотреть, как много пользователей смотрят вашу полную выдачу/полные рекомендации, чтобы понимать, стоит ли делать выдачу больше/рекомендовать больше товаров. То есть если вы показываете пользователю 100 товаров и при этом 50% долистывают до конца, можно сделать вывод, что пользователь не нашёл то, что хотел бы купить -> можем показать ещё сто товаров.
Ну и конечно это всё используется для аналитиков. Обычно эти данные уезжают в какое-то OLAP-хранилище, где можно выполнять сложные аналитические запросы. Это позволяет исследовать какие-то гипотезы про происходившее или находить новые зависимости (что иногда позволяет понимать, какие-то боли пользователей -> решать их и делать продукт лучше).
Аналитика на фронте 2/2.
В нашем случае важными действиями для рекомендаций можно считать клики на конкретные товары (если пользователь кликнул на продукт, значит ему он интересен). Но есть и более сильные сигналы вроде добавления в корзину/покупки товара (добавить в корзину != купить). Подобную информацию можно также использовать, чтобы понимать, какие товары часто покупают вместе и учитывать это при рекомендациях.
Мы ещё используем данные о кликах (CTR) для ранжирования в поиске. Как мы писали в статье, мы учитываем, как часто пользователи кликают на конкретные товары для конкретного запроса. Логика простая: если большинству пользователей на фиксированном запросе понравился конкретный товар, то возможно текущему пользователю он тоже понравится, так что надо поднять его повыше.
Также подобную информацию можно использовать для различных оффлайн процессов. Если продолжать говорить про наш поиск, мы можем взять события просмотра поисковой выдачи и достать реальные пользовательские запросы. Далее мы можем получить выдачу от нашего поискового движка на этот конкретный запрос и отправить эти данные в Толоку. После того, как в Толоке данные будут размечены на (не)релевантность, мы можем собрать разные статистики и понять, насколько хорошо мы сейчас что-то ищем (тут правда стоит понимать, что в данной метрике речь идёт про качество (precision), а не полноту (recall)), собрать примеры нерелевантной выдачи и каким-то образом их починить.
Ну или можно посмотреть, как много пользователей смотрят вашу полную выдачу/полные рекомендации, чтобы понимать, стоит ли делать выдачу больше/рекомендовать больше товаров. То есть если вы показываете пользователю 100 товаров и при этом 50% долистывают до конца, можно сделать вывод, что пользователь не нашёл то, что хотел бы купить -> можем показать ещё сто товаров.
Ну и конечно это всё используется для аналитиков. Обычно эти данные уезжают в какое-то OLAP-хранилище, где можно выполнять сложные аналитические запросы. Это позволяет исследовать какие-то гипотезы про происходившее или находить новые зависимости (что иногда позволяет понимать, какие-то боли пользователей -> решать их и делать продукт лучше).
❤1