Symfony et Meilisearch : Simplifiez et accélérez vos recherches

meilisearch with symfony

Symfony & Meilisearch : une alternative légère et performante à Elasticsearch ?

Lorsqu’on développe une application avec Symfony, on se retrouve souvent face à une question importante : quelle solution de recherche utiliser pour fournir une expérience utilisateur optimale ? Symfony ne dispose pas nativement d’un moteur de recherche avancé intégré, mais plusieurs solutions externes existent, parmi lesquelles Algolia, Elasticsearch ou encore Meilisearch.

Dans mon cas, j’avais besoin d’une solution puissante mais légère, facile à mettre en œuvre, et surtout que je pourrais héberger moi-même sans engager des ressources considérables. Elasticsearch, bien que puissant, est souvent trop lourd et complexe à gérer pour des projets de taille modeste. Algolia, quant à lui, est une solution SaaS pratique, mais impose rapidement des coûts élevés dès que le trafic augmente.

Meilisearch s’est alors imposé comme le compromis idéal : rapide, léger, open-source et facile à déployer en local comme en production. Dans cet article, nous allons ensemble découvrir comment installer Meilisearch avec Symfony en local, le configurer rapidement, et réaliser nos premiers tests pour comprendre toute la puissance et la simplicité de ce moteur de recherche.

La base du projet Symfony

Pour cet exemple pratique, nous allons utiliser la toute dernière version de Symfony (7.2) avec Doctrine. Afin d’optimiser notre environnement de développement et de gagner un temps précieux, nous allons nous appuyer sur Docker Composepour orchestrer nos différents services : PostgreSQLPGAdmin et, bien sûr, notre moteur de recherche favori, Meilisearch.

Docker Compose est idéal pour créer un environnement reproductible, léger et facilement maintenable, que ce soit pour travailler seul ou en équipe. Grâce à lui, l’installation de la base de données PostgreSQL, l’interface graphique PGAdmin pour gérer facilement vos bases de données, ainsi que Meilisearch lui-même se fera en quelques commandes seulement.

Voici comment structurer votre fichier docker-compose.yml (nous y reviendrons en détail dans les prochaines étapes). Une fois configuré, il suffira de lancer la commande suivante pour télécharger les images et démarrer automatiquement vos conteneurs :

docker-compose up -d

Les données : la clé d’un moteur de recherche performant avec Symfony et Meilisearch

Un moteur de recherche, aussi performant soit-il, dépend avant tout de la qualité et de la quantité des données qu’il indexe. Pour ce faire, nous allons utiliser deux bundles incontournables : l’excellent Zenstruck Foundry Bundle, combiné au célèbre Doctrine Fixtures Bundle, afin de générer et de charger rapidement des données réalistes dans notre base de données PostgreSQL.

Pourquoi utiliser Zenstruck Foundry Bundle ?

Ce bundle facilite considérablement la création de données fictives pour votre projet Symfony grâce à son intégration poussée de Faker PHP. Ainsi, vous bénéficiez d’un outil puissant qui permet de créer des fixtures cohérentes, riches et réalistes en quelques lignes seulement.

Voici un exemple concret avec une entité classique : Article.

<?php

namespace App\Factory;

use App\Entity\Article;
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;

/**
 * @extends PersistentProxyObjectFactory<Article>
 */
final class ArticleFactory extends PersistentProxyObjectFactory
{
    /**
     * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
     *
     * @todo inject services if required
     */
    public function __construct()
    {
    }

    public static function class(): string
    {
        return Article::class;
    }

    /**
     * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
     *
     */
    protected function defaults(): array|callable
    {
        return [
            'content' => self::faker()->paragraphs(2, true),
            'createdAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()),
            'description' => self::faker()->text(),
            'title' => self::faker()->text(50),
        ];
    }

    /**
     * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
     */
    protected function initialize(): static
    {
        return $this
            // ->afterInstantiate(function(Article $article): void {})
        ;
    }
}

Dans cet exemple, Zenstruck Foundry nous permet d’obtenir facilement des articles avec un titre, une description, un contenu riche et une date de création réaliste.

Chargement des données avec Doctrine Fixtures

Une fois les données fictives générées, le chargement dans notre base PostgreSQL se fait simplement grâce au bundle Doctrine Fixtures. Une simple commande suffit :

symfony console doctrine:fixtures:load

Zenstruck Foundry et Doctrine Fixtures s’occupent alors de remplir automatiquement votre base de données avec des centaines d’articles réalistes, prêts à être indexés.

Zendstruck et Faker PHP : le duo parfait pour des fixtures réussies

La véritable force de Zenstruck Foundry réside dans son intégration étroite avec Faker PHP, garantissant ainsi une grande variété de données réalistes. De plus, la gestion des relations entre les entités (ManyToOne, OneToMany, ManyToMany…) est d’une simplicité remarquable, ce qui vous permet de créer rapidement un jeu de données complexe, adapté à vos besoins de tests et de développement.


Maintenant que nous avons un jeu de données conséquent, il est temps de passer à l’étape suivante : l’indexation avec Meilisearch !

Comprendre Meilisearch et son fonctionnement avec Symfony

Qu’est-ce qu’un index en moteur de recherche ?

Tous les moteurs de recherche, que ce soit Meilisearch, Elasticsearch ou Algolia, utilisent un principe commun : l’indexation. Mais qu’est-ce que ça signifie concrètement ? C’est simple : même si vos données existent déjà dans votre base PostgreSQL, Meilisearch n’en sait rien tant que vous ne lui avez pas explicitement indiqué quelles données il doit connaître. Eh oui, Meilisearch ne lit pas directement dans votre base de données !

L’importance de l’indexation avec Meilisearch

Pour que Meilisearch puisse répondre instantanément à vos requêtes, vous devez lui fournir un index clair et précis des données à exploiter. Autrement dit, si vous souhaitez retrouver vos articles depuis la barre de recherche de votre application Symfony, vous devez d’abord demander à Meilisearch de les indexer.

Meilisearch Symfony Bundle : l’indexation simplifiée

Heureusement, là encore, la communauté Symfony et l’équipe de Meilisearch ont pensé à tout ! Le Meilisearch Symfony Bundle simplifie considérablement cette tâche en permettant de configurer rapidement l’indexation via un simple fichier YAML. Ce fichier vous permet notamment de déterminer précisément quelles entités (et quelles propriétés) Meilisearch doit prendre en compte.

Grâce à une sérialisation très intuitive, vous pouvez même indiquer à Meilisearch exactement quelles données intégrer, et lesquelles ignorer, via des groupes de sérialisation. Ainsi, si vous ne souhaitez pas que certaines données apparaissent dans votre recherche, il suffit de ne pas les associer à un groupe spécifique, et Meilisearch les ignorera automatiquement.

=>le lien du bundle

Fichier de configuration YAML (meilisearch.yaml)

meilisearch:
    url: '%env(MEILISEARCH_URL)%'
    api_key: '%env(MEILISEARCH_API_KEY)%'
    nbResults: 12  # Nombre de résultats par page
    indices:
        # Index pour les produits
        -   name: products
            class: App\Entity\Product
            enable_serializer_groups: true

        # Index pour les articles
        -   name: articles
            class: App\Entity\Article
            enable_serializer_groups: true

Dans cette configuration, chaque entité Symfony correspond à un index distinct dans Meilisearch. L’option enable_serializer_groups permet d’utiliser des groupes de sérialisation afin de contrôler précisément quelles propriétés seront effectivement indexées.

L’entité Article : définir clairement les données à indexer

Voici l’exemple détaillé de l’entité Article configurée pour Meilisearch grâce aux attributs Symfony Serializer et aux groupes de sérialisation :

<?php

namespace App\Entity;

use App\Repository\ArticleRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;

#[ORM\Entity(repositoryClass: ArticleRepository::class)]
class Article
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Groups(['searchable'])]
    private ?string $title = null;

    #[ORM\Column(type: Types::TEXT)]
    #[Groups(['searchable'])]
    private ?string $description = null;

    #[ORM\Column(type: Types::TEXT)]
    #[Groups(['searchable'])]
    private ?string $content = null;

    #[ORM\Column]
    private ?\DateTimeImmutable $createdAt = null;

    // ... getters & setters
}

Dans cet exemple :

  • Les propriétés titledescription et content sont annotées avec #[Groups(['searchable'])]. Cela indique clairement à Meilisearch quelles propriétés doivent être indexées.
  • La propriété createdAt n’étant pas incluse dans le groupe searchable, elle ne sera pas indexée, ce qui permet d’optimiser la taille de l’index et la performance des recherches.

Lancer l’indexation avec Meilisearch depuis Symfony

Une fois configuré, il suffit simplement d’exécuter la commande suivante pour que Meilisearch indexe vos données :

php bin/console meilisearch:import

En quelques secondes, vos données Symfony sont disponibles et exploitables par Meilisearch pour des recherches instantanées et ultra-performantes !


meilisearch via docker avec Symfony 7

Conclusion: DX très fluide et fonctionnement simple

Comme nous venons de le découvrir ensemble, l’intégration de Meilisearch dans un projet Symfony 7.2 s’avère particulièrement simple et intuitive, à condition bien sûr de maîtriser les fondamentaux du framework. Grâce à des outils modernes comme Docker et Docker Compose, la mise en place d’un environnement de développement stable, rapide et évolutif devient une véritable promenade de santé.

Le Developer Experience (DX) offert par Meilisearch est particulièrement remarquable : configuration minimale, commandes intuitives et résultats instantanés. D’après mes propres tests, Meilisearch se révèle tout simplement impressionnant par sa rapidité, son efficacité, et surtout par sa simplicité d’utilisation au quotidien.

Dans mon prochain article, nous irons encore plus loin en découvrant concrètement comment développer une barre de recherche avancée sous Symfony, propulsée par Meilisearch, ainsi que la mise à jour automatique des données indexées. Eh oui, avec Meilisearch, même la gestion dynamique de vos index devient un jeu d’enfant !

Cet article t’a plu ?

Bien sur tout le code source de cet article est disponible sur mon Github de manière public pour aider le plus grand nombres.
Sinon je te laisse découvrir un autre article lié au cache L2.

Laisser un commentaire

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