Skip to content

Tsvetov/analys_users

Repository files navigation

Это приложение для django(1.8).

Идея такая:

    1. Денормализовать исходные данные.
        Исходная таблица:
            IpTable:
                user_id
                ip_address
                date

        Таблица денормализации:
            UserIp:
                user_id
                ips
                users

        Где ips - это массив ip пользователя, а
        users - это рекурсивная связь Многие-ко-многим,
        куда сохраняем уже посчитанные отношения между пользователями


    2. Синхронизировать данные в бд с помощью тригера SQL(
        текcт триггрера находиться в миграции 0002_auto_20150818_2011.py)
        При записи(INSERT) новой пары IpTable.user_id-IpTable.ip_address в таблицу
        UserIp записывается информация о паре user-ips(если такой еще нет).

    3. Поставить индекс на колонку UserIp.user_id. ORM django ставит индекс на
    колонку первичного ключа по умолчанию, однако это b-дерево, а нужно Hash, поэтому ставим hash-индекс в миграции
    (0002_auto_20150818_2011.py)

    4. После вышеупомянутых манипуляций,вытащить из базы нужные нам
        данные и посчитать результат не состовляет труда.

        1. Проверяем рекурсивную связь users => если у пользователей есть эта связь, то они взаимосвязаны.
        2. Берем списоки ip пользователей, преобразуем во множество и пересекаем, если пересечение <= 1 следовательно
        пользователи не взаимосвязаны.
        3. Множество получившийся из шага 2 мы преобразуем с помощью функции imap(аналог map), в список подсетей,
        затем во множество подсетей, если это размер множества <= 1 следовательно, пользователи не взаимосвязаны.
        4. Если условные операторы 2 и 3 шага не сработали, следовательно пользователи взаимосвязаны(перед тем как вернуть True,
        нужно записать связь users)

Примерный результат тестов:
    1000 user_id ~ 0.74 ms
    10000 user_id ~1.3 ms
    1000000 user_id ~2.5 ms
    10000000 user_id ~2.7 ms

    Надо добавить что количество user - это колличество уникальных пользователей.
    Т.Е. записей в исходной таблице было в ~3~4 раза больше.

    ТЕсты проводились как на положительный так и на отрицательный результат.


TODO(возможные улучшения):
    1. Передавать данные по json(решение, передавать данные в сессии при редиректе, наверное не самое лучшее)
    и вообще переработать интерфейс.


У меня было несколько вариантов решений. Остановился на нем - потому как:
    - из всех моих решений максимальная скорость.
    - при увеличении данных скорость практически не меняется.
    - простота кода.

Минусы данного подхода:
    - перекладывая часть расчетов на момент записи исходных данных в таблицу(trigger), мы можем потерять в скорости
    сервисов(которые эти данные пишут)
    - Много SQL-кода.
    - Может быть такая ситуация - когда у одного пользователя раздувается список ip(их всего может быть не больше ~2000000 для класса С).
    При этом скорость работы у таких пользователей проседала раза в 5-6(что на самом деле не очень критично, при таком увеличении данных).

Для запуска, нужно прописать в settings.install_apps название приложения analys_users, и прописать urls:
    url(r'^', include('analys_users.urls'))

About

analys_users

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published