Используйте растровое изображение Redis для реализации эффективной функции статистики регистрации пользователей.
Используйте растровое изображение Redis для реализации эффективной функции статистики регистрации пользователей.

Предисловие

существуют современное приложение, Вход user — это обычная функция. Обычно мы используем MySQL База данных для хранения записей о регистрации пользователей. Однако,С количеством пользователей увеличивать Увеличивать,Записи в базе данных будут расти линейно со временем и количеством пользователей.,Это не только увеличивает нагрузку на хранилище,И это может повлиять на эффективность запросов. существуют стремления к более высокой эффективности хранения и производительности запросов по сценарию,MySQL Возможно, это уже не лучший вариант.

В это время,Redis из Bitmap Структура данных особенно важна. использовать Redis Bitmap,Мы не только можем значительно сократить занимаемое пространство для хранения,Он также может эффективно реализовывать сложную статистику поведения пользователей.,Например, количество последовательных дней входа в систему, статистика ежемесячных входов и т. д. Следующий,В этой статье подробно описано, какиспользовать Redis Bitmap Достичь высокой эффективности из Вход статистическая функция пользователя.

Вы готовы? Приготовьте чашку любимого кофе и чая и узнайте, прочитав эту статью.

Redis Bitmap

Redis из Bitmap,Также называется растровым изображением,это хранилищеи Обработка битов(bit)изструктура данных。существовать Redis середина,Bitmap Это не независимый тип данных, а особый способ строкового типа. Вы можете обрабатывать двоичный Кусочек в конкретном из Заказсуществовать строковые данные. Redis Максимальная длина средней строки издля 512 МБ, каждый байт имеет 8 бит, поэтому строка может хранить до 512 * 1024 * 1024 * 8 = 2^32 Единая позиция.

Bitmap Основные сценарии применения следующие:

  • Вход пользователястатистика:Каждому пользователю соответствует растровое изображение,Кусочек图серединаиз Каждый из них представляет собой определенный День из статуса регистрации.0 Указывает, что вход не выполнен,1 Показывает, что вы вошли в систему. Битовое изображение может быстро подсчитать количество последовательных дней регистрации, общее количество дней регистрации и т. д. пользователей.
  • фильтр Блума:на основе bitmap Можно реализовать фильтр Блума,bitmap Может использоваться для эффективного определения наличия элемента в наборе. Сопоставьте элементы с помощью нескольких хэш-функций, чтобы bitmap из разных позиций быстро определить наличие элементов изсуществовать.
  • Статистика активных пользователей:Может用 Bitmap Запишите, активен ли пользователь в определенный день. Например, когда пользователь посещает веб-сайт или приложение, соответствующий бит устанавливается в значение для. 1,Бит статистики позволяет быстро подсчитать количество активных пользователей.

Реализация функции статистики входов

Отображение отношений между пользователями и растровыми изображениями

Записи о входе указаны в годах.,пользователь,Соответствует растровому изображению(Bitmap),Указывает статус регистрации пользователя в течение одного года.

  • key издизайн:user:sign:%d:%d,Первый заполнитель представляет год,Второй заполнитель представляет номер пользователя.
  • bitmap Ценность дизайна: Всего за один год 365 или 366 дней, поэтому нам нужно только bitmap внутри и спереди 366 немного, это 0-365 Кусочек.

Обзор функций

Далее будут объединены Go язык и Redis Промежуточное программное обеспечение реализует следующие функции:

  • Вход пользователя
  • Запрос Вход пользователясостояние
  • Статистика совокупного количества дней заезда в этом году
  • Статистика заездов за текущий месяц

Установите зависимости Redis в программы Go

Следующей реализацией функции будет use. Go код языка для демонстрации, поэтому сначала нам нужно его установить Go Redis полагаться.

Язык кода:bash
копировать
go get github.com/redis/go-redis/v9

Вход пользователя

Для достижения Входа useriz, нам нужно использовать Redis из SETBIT Заказ.

SETBIT Заказиспользуется длянастраиватьили Прозрачный字符串ценитьсерединаизопределенный бит(bit)ценить,Использование следующее:

Язык кода:bash
копировать
SETBIT key offset value
  • key: Ключевое имя.
  • offset: Кусочек偏移量,Выразить желаниенастраиватьили Прозрачныйиз Кусочек(bit)из Кусочек置。Кусочекиз Кусочек置从 0 Начни считать.
  • value: Чтобы установить значение бита, его можно 0 или 1

Пример кода:

Язык кода:go
копировать
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go/redis-bitmap-sign/sign/main.go
package main

import (
    "context"
    "fmt"

    "github.com/redis/go-redis/v9"
)

func RedisClient() *redis.Client {
    return redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

func main() {
    rdb := RedisClient()
    if rdb == nil {
        panic("redis client is nil")
    }
    oldValue, err := rdb.SetBit(context.Background(), "user:2024:1", 0, 1).Result()
    if err != nil {
        panic(err)
    }
    if oldValue == 1 {
        fmt.Println("Повторить регистрацию")
    } else {
        fmt.Println(oldValue) // 0, что указывает на то, что этот бит («бит») является значением до установки нового значения.
    }
}

В приведенном выше примере кода мы вызываем Redis Экземпляр клиентаиз SetBit метод, будет key для user:2024:1 Переписка bitmap средний класс 0 Дизайн локациидля 1。Это означает ID для 1 изпользовательсуществовать 2024-01-01 Зарегистрировался。SetBit методиз返回ценитьдля该Кусочек(bit)одеялонастраивать新ценить之前изценить。

Запрос Вход пользователясостояние

Чтобы реализовать запрос Вход статус пользователя, нам нужно использовать Redis из GETBIT Заказ.

GETBIT Заказиспользуется для Получать字符串ценитьсерединаизопределенный бит(bit)изценить,Использование следующее:

Язык кода:bash
копировать
GETBIT key offset
  • key: Ключевое имя.
  • offset: Кусочек偏移量,Выразить желаниенастраиватьили Прозрачныйиз Кусочек(bit)из Кусочек置。Кусочекиз Кусочек置从 0 Начни считать.

Пример кода:

Язык кода:go
копировать
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go/redis-bitmap-sign/sign-in-record/main.go
package main

import (
    "context"
    "fmt"

    "github.com/redis/go-redis/v9"
)

func RedisClient() *redis.Client {
    return redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

func main() {
    rdb := RedisClient()
    if rdb == nil {
        panic("redis client is nil")
    }
    value, err := rdb.GetBit(context.Background(), "user:2024:1", 0).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println(value) // 1
}

В приведенном выше примере кода мы вызываем Redis Экземпляр клиентаиз GetBit метод, получить key для user:2024:1 Переписка bitmap серединаиз第 0 Кусочекизценитьдля 1,Это означает ID для 1 изпользовательсуществовать 2024-01-01 Уже авторизован.

Статистика совокупного количества дней заезда в этом году

Чтобы подсчитать количество чекинов за год, нам нужно использовать Redis из BITFIELD Заказ.

Redis из BITFIELD Заказэто очень мощныйиз Заказ,Это позволяет изучить различные операции на битовом уровне.,В том числе читать, устанавливать, увеличивать битовые поля. Этот заказ способен работать с битовым массивом, хранящимся в существующей строке.,и может рассматриваться как прямойсуществоватьна веревкеосуществлятьсложныйиз Кусочек操作。Использование следующее:

Язык кода:bash
копировать
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment]

Подробную информацию см.:Redis BITFIRLED Command

Пример кода:

Язык кода:go
копировать
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go/redis-bitmap-sign/cumulative-sign/main.go
package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/redis/go-redis/v9"
)

// RedisClient инициализация Redis клиент
func RedisClient() *redis.Client {
    return redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

// GetCumulativeDays Получить Указанный год из Суммарного количества дней заезда
func GetCumulativeDays(ctx context.Context, rdb *redis.Client, userID int, year int, dayOfYear int) (int, error) {
    key := fmt.Sprintf("user:%d:%d", year, userID)
    segmentSize := 63
    cumulativeDays := 0
    bitOps := make([]any, 0)

    for i := 0; i < dayOfYear; i += segmentSize {
        size := segmentSize
        if i+segmentSize > dayOfYear {
            size = dayOfYear - i
        }

        bitOps = append(bitOps, "GET", fmt.Sprintf("u%d", size), fmt.Sprintf("#%d", i))
    }

    values, err := rdb.BitField(ctx, key, bitOps...).Result()
    if err != nil {
        return 0, fmt.Errorf("failed to get bitfield: %w", err)
    }

    for idx, value := range values {
        if value != 0 {
            size := segmentSize
            if (idx+1)*segmentSize > dayOfYear {
                size = dayOfYear % segmentSize
            }
            for j := 0; j < size; j++ {
                if (value & (1 << (size - 1 - j))) != 0 {
                    cumulativeDays++
                }
            }
        }
    }
    return cumulativeDays, nil
}

func main() {
    rdb := RedisClient()
    if rdb == nil {
        log.Fatal("redis client is nil")
    }
    now := time.Now()
    // Получить текущийиз года
    year := now.Year()
    // Получить Какое текущее число в этом году?
    dayOfYear := now.YearDay()
    // Предполагаемый пользователь ID для 1
    userID := 1

    cumulativeDays, err := GetCumulativeDays(context.Background(), rdb, userID, year, dayOfYear)
    if err != nil {
        log.Fatalf("failed to get cumulative days: %v", err)
    }

    fmt.Printf("%d Совокупное количество дней регистрации в году: %d\n", year, cumulativeDays)
}

Приведенный выше код реализует функцию Статистика общего количества дней в этом году. Процесс выглядит следующим образом:

  • Получать Redis Пример клиента: использовать redis.NewClient() соединение метода Redis на сервер и Получить Экземпляр клиента。
  • Получить временной коэффициент:
    • Текущий год: проходить year := now.Year() Получать。
    • Сегодня день в этом году: проходитьdayOfYear := now.YearDay() Получать。
  • Установить идентификатор пользователя: В примере предполагается, что пользователь ID для 1
  • Создать ключ Redis:сипользовать годового пользователя ID построить только одиниз Redis Key,Форматдля пользователь:год:идентификатор пользователя
  • Определите битовые операции и размер интервала: Поскольку битовое поле Заказ BitField Из Каждая операция может обрабатываться. Максимальная длина 63 бит, определение segmentSize := 63 для пакетной обработки данных для входа. Интервал представляет 63 День из статуса регистрации.
  • Инкапсуляция BitField Заказизпараметр: проходить Цикл будет идти от начала года до текущей даты.издни(dayOfYear)разделениедля每段最多包含 63 Несколько интервалов на небе, динамическая постройка. BitField Заказизпараметр。
  • Выполните команду BitField: использовать rdb.BitField() методосуществлятьстроитьхорошийиз BitField Заказ,返回一个包含Кусочек二进制Перепискадесятичное представлениеиз int64 Тип срез.
  • Статистика совокупных дней заезда: Перебрать массив результатов,для каждого ненулевогоизрезультатиспользовать Кусочек运算(& операции и операции перемещения) для обнаружения ситуации регистрации каждый раз, когда 1 Примерно cumulativeDays Увеличивать 1

Статистика заездов за текущий месяц

Чтобы подсчитать статус регистрации в определенном месяце, нам также необходимо использовать Redis из BITFIELD Заказ.

Пример кода:

Язык кода:go
копировать
// https://github.com/chenmingyong0423/blog/blob/master/tutorial-code/go/redis-bitmap-sign/monthly-sign/main.go
package main

import (
    "context"
    "errors"
    "fmt"
    "log"
    "time"

    "github.com/redis/go-redis/v9"
)

func RedisClient() *redis.Client {
    return redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

func main() {
    rdb := RedisClient()
    if rdb == nil {
        panic("redis client is nil")
    }
    now := time.Now()
    // Получить текущийиз года
    year := now.Year()
    // Предполагаемый пользователь ID для 1
    userID := 1
    // Получить Текущий месяц из дней
    days := time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour).Day()
    // Получить Какой день является началом этого месяца и этого года?
    offset := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).YearDay()
    signOfMonth, err := GetSignOfMonth(context.Background(), rdb, userID, year, days, offset)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(signOfMonth)
}

func GetSignOfMonth(ctx context.Context, rdb *redis.Client, userID, year, days, offset int) ([]bool, error) {
    typ := fmt.Sprintf("u%d", days)
    key := fmt.Sprintf("user:%d:%d", year, userID)

    s, err := rdb.BitField(ctx, key, "GET", typ, offset).Result()
    if err != nil {
        return nil, fmt.Errorf("failed to get bitfield: %w", err)
    }

    if len(s) != 0 {
        signInBits := s[0]
        signInSlice := make([]bool, days)
        for i := 0; i < days; i++ {
            signInSlice[i] = (signInBits & (1 << (days - 1 - i))) != 0
        }
        return signInSlice, nil
    } else {
        return nil, errors.New("no result returned from BITFIELD command")
    }
}

Приведенный выше код реализует функцию Статистика заездов за текущий месяц. Процесс выглядит следующим образом:

  • Получать Redis Экземпляр клиента:использовать redis.NewClient() соединение метода至 Redis сервер и получить экземпляр клиента。
  • Получить временной коэффициент
    • текущий год:проходить year := now.Year() Получать。
    • Количество дней в текущем месяце:проходить time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, now.Location()).Add(-24 * time.Hour).Day() рассчитать.
    • Какой день является началом месяца в этом году?:проходить time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()).YearDay() Получать。
  • Настроить пользователя ID:В примере предполагается, что пользователь ID для 1
  • строить Redis key и BitField Заказизпараметр
    • сипользовать годового пользователя ID построить только одиниз Redis Key,Форматдля пользователь:год:идентификатор пользователя
    • использоватьколичество дней в месяце days строить type параметр fmt.Sprintf("u%d", days),Указывает операцию по ширине битового поля.
  • осуществлять BitField Заказ:проходить rdb.BitField() методосуществлять BitField Заказ,返回一个包含Кусочек二进制Перепискадесятичное представлениеиз int64 Тип срез.
  • Статистика заездов за текущий месяц:проходить Кусочек运算(и операциии Кусочек移操作)Тестирование каждый деньиз签到состояние,Вернуть результат как логический срез,其середина true Войти,false Указывает, что вход не выполнен.

Мы можем отобразить статус регистрации месяца на основе логического среза из элемента существующего клиента, например Календарь регистрации

краткое содержание

В этой статье подробно описано, как использовать Redis Bitmap тип Достичь высокой эффективности из Вход статистическая функция пользователя. Содержание включает в себя Redis Bitmap Краткое введение в типы данных и сценарии их применения, а также Go Языковая программа просто реализована Вход пользователяЗапрос Вход пользователясостояние и Статистика совокупного количества дней заезда в этом году а также Статистика заездов за текущий месяц из функции.

Хотя Redis bitmap Тип данных существуетstatisticsВход Пользователь имеет значительные преимущества с точки зрения ситуации, что в основном отражает следующие два момента:

  • эффективное хранение:每个пользовательиз签到信息仅占用一个Кусочек,Это существенно экономит место для хранения.
  • Быстрый запрос:Можетпроходить Кусочек操作Быстрый Запрашивать у пользователей статус регистрации и статистику дней регистрации.

Однако,Redis Bitmap Типы данных также имеют свои ограничения. Например, используйте Bitmap При хранении данных,Можно сохранить только одно состояние. Если вам нужно сохранить дополнительную информацию о конкретном времени заезда или другую соответствующую информацию,Bitmap не применяется.

В общем,Redis Bitmap Он очень подходит для реализации эффективной функции статистики регистрации, но при разработке системы необходимо взвесить ее преимущества и недостатки в соответствии с конкретными потребностями.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose