Представим что вы имеете доступ к образовательному ресурсу, где есть каталог курсов и уроков. В какой-то момент вы теряете часть данного каталога и у вас есть только ID единиц контента, наименование урока, а нумерации нет — повреждена таблица. Пишем свой велосипед.
Задача
Восстановить данные — задача №0, построить алгоритм, который поможет собирать последовательность таких уроков в любой момент, даже если автор урока не указал его нумерацию вовремя (такое бывает).
На выходе нужно получить такую таблицу (восстановив данные в колонках Курс и Урок)
|
wID |
Курс |
Урок |
Наименование |
|
34f5d3 |
1 |
1 |
Бла |
|
462g6g |
1 |
2 |
Бла Бла го |
|
f63f |
… |
N |
Бла Бла Бла |
|
wectwa |
2 |
1 |
го |
|
6vva |
2 |
2 |
го го Бла |
|
d35y34 |
2 |
… |
го го |
|
wrywyr |
2 |
M |
Бла Бла |
В теории все просто, вот только курсов море, уроков много, и восстановить нужно 1000+ записей.
Рассмотрели варианты, какие дополнительные данные могут нам помочь для решения задачи. На момент восстановления остался только log nginx в котором можно было бы найти знания о том, какие пользователи (по cookies) в какое время смотрели уроки.
Как решали задачу
Базовый вариант — анализ логов и построение последовательности на основе этих данных. Критическое ограничение — лог только за крайние 30 дней. Даже если учесть тот факт, что уроки должны пользователи смотреть последовательно, то из лога мы могли получить временной ряд: datadate, user, wid
Полный список ограничений:
-
лог за 30 дней
-
часть пользователей смотрели уроки рандомно, таких около 5%
-
статистика по первому курсу бедная так как эти уроки в текущем месяце смотрело меньше людей, так как пик просмотров по ним был 2 месяца назад и этого лога нет
-
в самих уроках нет указания номера, просто видео файл
-
бекапа нет (это для текущего кейса на Хабре, так интереснее)
Варианты решений для рассмотрения
-
Статистика. посмотреть частотность ID уроков в логе, гипотеза — более старые уроки должны иметь max частотность так как все начинают с 1 курса и 1 урока и далее. Разочарование — данных мало и самая высокая частотность у уроков, по которым в этом месяце был набор слушателей и более активная реклама
-
Логика. построить последовательность по логам, найти пользователя который просмотрел все уроки и на основе этих данных принять как данное что это корректное решение, отсортировав лог по времени. Разочарование — нет пользователей которые прошли все уроки. Более того часть пользователей в середине курса могли возвращаться к прежним более старым урокам и потом опять смотреть новое
-
Дерево. Давайте представим что урок это точка в пространстве дерева а лучи между ними — это как раз максимально частотные переходы пользователей от урока А до урока Б потом В и т.д. Далее строим корректный путь между точками. Разочарование — собранная частотность не позволяла создать дерево, результат был похож на мусор
-
Опечаточник. Представим, что один пользователь должен был посмотреть такую последовательность уроков А,B,C,D,E,F,J а по факту смотрел так А,B,C,E,D,F. Гипотеза, давайте представим что это не отдельные «буквы» а слово «abcedf» написанное с ошибкой. Разделим его на триграммы или биграммы и далее попробуем исправить опечатку, основываясь на статистике биграмм всех юзеров из лога. Разочарование — мало пользователей, которые смотрели более 60% уроков
Вариант который сработал
Гипотеза — даже если есть много пользователей которые смотрели не все уроки, но подавляющее большинство скорее всего смотрели уроки в правильной последовательности. Исключаем тех, кто смотрел часть уроков рандомно т.е. несколько раз за все время. Исключаем тех, кто смотрел только первые N минут видео, возможно это были случайные просмотры или пользователь произвольно выбирал урок или …
Собираем частотность пар, что в последовательности урок А, далее урок В смотрело N юзеров. Урок В далее С — смотрело Y и т.д. Не анализируем пары с минимальной частотностью.
Сортируем пары в порядке убывания частотности, проверяем. Увы мах частотность имеют пары уроков этого курса, который был запланирован в данном месяце, а первый курс опять где-то мимо. Предварительный результат следующий:
-
последовательность уроков внутри курса собрать получилось
-
последовательность всех уроков — нет, так как смешиваются уроки разных курсов
-
выделяем потенциальные группы уроков, которые могут стать курсами, далее нужно понять какой это курс
-
перебирая список, смотрим частотность внутри предварительного результата, сравнивая пары последовательных ID в этом списке (пара = строка n и строка n+1) . Если попадается пара у которой частотность отсутствует или минимальная, то для ID которая была n+1 присваиваем n+2 (опускаем в этом списке ниже). Если частотность выше среднего, оставляем и идем далее, сравнивая ID которая в списке под номером n+1 со строкой n+2 и т.д.
Отталкиваемся от логики, что пользователь который смотрел 2 урок из 1 курса скорее всего будет смотреть далее 3 урок из 1 курса, а не 7 урок из 2 курса, даже если частотности этих ID в списке стоят рядом.
Результат — обработано 238710 пар уроков, по данным от 3461 пользователя (на основе лога). Время формирование списка пар ~9 сек, время формирование корректной очереди менее 1.7 сек. В качестве проверки результата был взят лог с частью не поврежденного каталога уроков -100% попадание.
Задача поста на Хабре — получить от вас идеи, как вы бы решали эту задачу?
ссылка на оригинал статьи https://habr.com/ru/articles/789034/
Добавить комментарий