Comment enregistrer les vues uniques dans votre projet Laravel avec Redis?

Salut les ami(e)s ! Nous revoilà pour un nouvel article. Cette fois-ci, nous allons voir comment enregistrer les vues uniques pour un modèle dans notre projet Laravel avec Redis grâce à l’algorithme HyperLogLog.

1- Qu’est-ce que l’algorithme HyperLogLog?

HyperLogLog (HLL) est un algorithme probabiliste de dénombrement d’éléments uniques dans un ensemble. Il fournit une réponse approchée du vrai résultat. HyperLogLog est une amélioration de l’algorithme LogLog.

Son implémentation dans Redis nous permettra d’enregistrer en base des vues uniques pour nos modèles eloquent.

2- Configuration de la connexion à Redis

Pour pouvoir utiliser Redis dans notre projet Laravel, nous allons devoir configurer la connexion au serveur Redis dans notre projet Laravel. Pour cela, nous allons devoir renseigner des variables d’environnement :

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null

REDIS_PORT=6379

Vous devez renseigner les bonnes valeurs pour ces trois variables. Dans mon cas, les valeurs sont correctes.

3- Enregistrer les vues uniques dans Redis en utilisant l’algorithme HyperLogLog

Pour pouvoir enregistrer une vue unique, nous avons besoin d’un élément qui va permettre d’identifier un utilisateur de façon unique. Ici, nous allons utiliser l’adresse IP de l’utilisateur.

Après cela, pour enregistrer une valeur dans Redis en utilisant l’algorithme HyperLogLog, nous allons utiliser la commande PFADD. Cette commande attend en paramètre une clé unique et l’élément ou la valeur à associer à cette clé. Dans notre cas, la valeur sera l’adresse IP de l’utilisateur et la clé unique sera composée à notre guise. Nous allons prendre ici l’exemple d’article dont nous voulons compter le nombre de vues uniques. Nous pourrions par exemple composer la clé en faisant ceci :

articl.id

Pour utiliser la commande PFADD à partir de la cli de redis voici ce que nous pouvons faire:

PFADD articles.1 127.0.0.1

Pour avoir la cardinalité lié à une clé nous devons utiliser la commande PFCOUNT comme ceci:

PFCOUNT articles.1

3- Créer un Trait pour enregistrer les vues et les compter

Nous allons créer un trait PHP qui va compter deux fonctions. La première pour enregistrer la vue dans Redis et la deuxième pour récupérer le nombre total de vues. Voici à quoi doit ressembler notre trait :

<?php

namespace App\Traits;

use Illuminate\Support\Facades\Redis;

trait LogView
{
   public  function logView()
   {
       Redis::pfAdd(sprintf('articles.%s.',$this->id),[request()->ip()]);
   }

   public function getViewCount()
   {
     return Redis::pfCount(sprintf('articles.%s.',$this->id));
   }
}

Ensuite pour utiliser le trait il suffit juste de l’ajouter à notre modèle Article en ajoutant use LogView. Sur chaque instance du modèle Article nous pouvons donc utiliser les méthode logView() et getViewCount().

4- Persister en base de donnée le nombre de vues

Redis est une base de données in-memory, du coup si nous mettons sous-tension notre serveur nous allons perdre toute nos données. Pour nos nombre de vues nous pouvons créer une colonne view_count par exemple pour enregistrer le nombre de vue par article.

Pour ce fait nous allons créer une commande qui va s’exécuter chaque minute et qui se chargera de parcourir chaque clé, ensuite enregistrera le nombre de vue en base de données.

Pour créer une commande exécutez la commande suivante:

php artisan make:command SyncViewCount

Modifier le contenu de votre méthode handle par ceci:

 public function handle()
    {
        $views = Article::select('id')->pluck('id')->map(function ($id){
           return ['id' => $id, 'view_count' => Redis::pfCount(sprintf('articles.%s.',$id))]; 
        });
    
}

Avec ce block de code nous recupérons le nombre de vue enregistré en utilisant l’algorithme HyperLogLog dans redis par article. La suite consistera à faire une mise à jour de masse en base de données. Pour ce fait nous allons utiliser un package assez pratique. Pour l’installer utilisez cette commande:

composer require mavinoo/laravel-batch

Après l’installation du package nous pouvons compléter notre code et nous obtenons le résultat suivant:

 public function handle()
    {
        $views = Article::select('id')->pluck('id')->map(function ($id){
           return ['id' => $id, 'view_count' => Redis::pfCount(sprintf('articles.%s.',$id))];
        });
        batch()->update(new Article(),$views,'id');
    
}

Voici le contenu finale de notre commande:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;

class SyncViewCount extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sync:views';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $views = Article::select('id')->pluck('id')->map(function ($id){
           return ['id' => $id, 'view_count' => Redis::pfCount(sprintf('articles.%s.',$id))];
        });
        batch()->update(new Article(),$views,'id');
    }
}

Pour finir dans le fichier Kernel.php contenu dans le dossier Console nous allons ajouter une ligne de code qui va exécuter notre commande chaque minute pour mettre à jour le nombre de vues:

$schedule->command('sync:views')->everyMinute();

Pour plus de détails sur comment automatiser des tâches dans un projet Laravel, il existe un article dans ce blog qui traite de cela ici.

Voilà! C’est tout. Vous venez d’utiliser Redis et l’algorithme HyperLogLog pour enregistrer les vues uniques dans votre projet Laravel. J’espère que cet article vous a été utile. On se retrouve la semaine prochaine pour un autre article sur une autre thématique.

Leave a Reply

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *