#cpp
Немножко про оптимизации и C++ 2/2.
2. Про RVO/NRVO писал ранее: t.me/thisnotes/198.
Рядом с этой темой можно посмотреть доклад про move-only C++ design.
3. Про девиртуализацию писал Женя: t.me/cxx95/88.
==============================
4. strlen elision.
Как известно, функция strlen работает за длину строки. Соответственно, если вы используете её в циклах:
Вы автоматом ловите квадрат в асимптотике. Потому хорошей практикой является выносить вот эту границу справа в отдельную переменную:
По-хорошему так делать и для итераторов, потому что операция получения end() у вашего контейнера может быть довольно тяжёлой (но ещё лучше понимать ограничения вашего контейнера и выбирать из конкретной ситуации). Но компиляторы не глупые: сами умеют иногда подобные вещи оптимизировать. Самый простой пример, это когда код вроде:
компилятор сделает вам:
Ну это база.
Недавно на собесе меня попросили написать
Как писали на каком-то сабреддите:
Optimize strlen by not using it.
Немножко про оптимизации и C++ 2/2.
2. Про RVO/NRVO писал ранее: t.me/thisnotes/198.
Рядом с этой темой можно посмотреть доклад про move-only C++ design.
3. Про девиртуализацию писал Женя: t.me/cxx95/88.
==============================
4. strlen elision.
Как известно, функция strlen работает за длину строки. Соответственно, если вы используете её в циклах:
for (int i = 0; i < strlen(str); ++i) {…}Вы автоматом ловите квадрат в асимптотике. Потому хорошей практикой является выносить вот эту границу справа в отдельную переменную:
for (int i = 0, end = strlen(str); i < end; ++i) {}По-хорошему так делать и для итераторов, потому что операция получения end() у вашего контейнера может быть довольно тяжёлой (но ещё лучше понимать ограничения вашего контейнера и выбирать из конкретной ситуации). Но компиляторы не глупые: сами умеют иногда подобные вещи оптимизировать. Самый простой пример, это когда код вроде:
int main() {
return std::strlen(“hi”);
}компилятор сделает вам:
main: # @main
mov eax, 2
retНу это база.
Недавно на собесе меня попросили написать
strlen. Потом ещё каким-то образом попросили это дело поускорять. Кек, что таким ещё занимаются. Хотя конечно, если погуглить, можно найти что-нибудь вроде такого или такого. Так что может и не без оснований, но лучше я вкину вот такую статью про полезность собеседований подобного рода. Как писали на каком-то сабреддите:
Optimize strlen by not using it.
👍11❤2🔥2
this->notes.
#cpp Немножко отдельных фактов из одного доклада с C++ Russia. 1. Посмотрим на такой код: delete [] { return new int; }(); Скомпилируется ли этот код? Ответ: нет . А почему? Семантически этот код можно считать корректным. Мы вызываем лямбду, которая возвращает…
Доклад Константина теперь доступен по ссылке: https://www.youtube.com/watch?v=lc3UkIZ4zOY&t=110s
Категорически рекомендую.
Категорически рекомендую.
❤2
#highload
Пару ссылочек.
1. What I Wish I Had Known Before Scaling Uber to 1000 Services.
У uber есть вот такая статья про domain-oriented архитектуру. Ключевая идея — объединять сервисы в домены по бизнесовому назначению и ходить в домены снаружи исключительно через gateway (там конечно ещё много всяких тонкостей и сложностей), что позволяет навести некоторый порядок в вашей архитектуре и том, как ваши бекенды взаимодействуют.
2. What is a Vector Database?
Хорошая и понятная статья про хранение векторов.
==========================
Оч устал за последнее время. Отваливаюсь отдыхать на пару недель.
Пару ссылочек.
1. What I Wish I Had Known Before Scaling Uber to 1000 Services.
У uber есть вот такая статья про domain-oriented архитектуру. Ключевая идея — объединять сервисы в домены по бизнесовому назначению и ходить в домены снаружи исключительно через gateway (там конечно ещё много всяких тонкостей и сложностей), что позволяет навести некоторый порядок в вашей архитектуре и том, как ваши бекенды взаимодействуют.
2. What is a Vector Database?
Хорошая и понятная статья про хранение векторов.
==========================
Оч устал за последнее время. Отваливаюсь отдыхать на пару недель.
🔥8❤1
#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