De la recherche Typesense avec Symfony

Utiliser Typesense dans un projet Symfony

Dans une application Web avec Symfony, la question de la mise en place d'un moteur de recherche intelligent est souvent mise sur la table.

Il est toujours pratique de disposer d'un outil qui permet de «trouver simplement» les données qui sont mises à disposition par l'outil.
Et puis, Google le fait bien, alors ça doit être facile non 😉 ?

Dès que l'on parle de recherche de données, les choses se corsent peu à peu.
En général, l'organisation des données est effectuée grâce à une base de données (MySQL, PostgreSQL) et exploitée grâce à un ORM tel que Doctrine. La mise en place d'un moteur de recherche avec ces outils se retrouve souvent limitée à la création de recherches complexes et peu performantes, qui ne donnent pas satisfaction.

De vrais outils d'indexation et de recherche dans votre application Web

Il existe un certain nombre de solutions permettant d'indexer puis de rechercher dans vos données.
Ces outils sont le complément de votre Système de base de données. Ils offrent des performances suppérieures et des fonctionnalités supplémentaires, comme par exemple :

  • des mécanismes de recherche à facettes
  • des mécanismes de recherche approchante (pour trouver malgré une faute d'ortographe par exemple)
  • des systèmes de pondération et de score des résultats

Dans ce domaine, Elasticsearch est un outil de disponible depuis de nombreuses années. Cependant, une solution basée sur Elasticsearch peut être assez «lourde» à mettre en place (en temps et en mémoire consommée), et certains aspect de la solution la rende complexe à mettre en oeuvre. Le Bundle FOSElasticaBundle permet cependant d'intégrer facilement cette solution dans vos projet.

Utiliser Typesense avec Symfony

Typesense est un moteur de recherche Open Source qui offre les fonctionnalités attendues dans ce domaine.

L'écosystème Symfony permet facilement de mettre en place Typesense dans votre projet, à l'aide du Bundle ACSEO/TypesenseBundle.

Que propose le Bundle ACSEO/TypesenseBundle

  • Définition des données à indexer par paramétrage
  • Commandes de création et d'indexation des données de Doctrine vers Typesense
  • Listener Doctrine pour maintenir les données de Typesense à jour
  • Services de recherche des données dans Typesense
  • Récupération des résultats de recherche bruts ou sous la forme d'Objets Doctrines hydratés

Mettre en place et utiliser le Bundle (en 5 minutes chronos)

⚠️ Les informations ci-dessous sont tirées de la documentation officielle du Bundle, n'hésitez pas à y jeter un oeil pour être parfaitement à jour.

Installation du Bundle

L'installation se fait de façon assez classique, à l'aide de composer.

$ composer require acseo/typesense-bundle

Une fois la dépendance installée, il ne vous reste plus qu'à activer le Bundle.

<?php
// config/bundles.php
return [
    ACSEO\TypesenseBundle\ACSEOTypesenseBundle::class => ['all' => true],

Configuration du Bundle

La configuration du Bundle permet de faire le lien entre vos Entités Doctrine et ce que vous souhaitez indexer dans Typesense

# .env
TYPESENSE_URL=localhost:8108
DATABASE_KEY=123
# config/packages/acseo_typesense.yml
acseo_typesense:
    # Typesense host settings
    typesense:
        host: '%env(resolve:TYPESENSE_URL)%'
        key: '%env(resolve:TYPESENSE_URL)%'
    # Collection settings
    collections:
        books:                                     # Typesense collection name
            entity: 'App\Entity\Book'              # Doctrine Entity class
            fields: 
                id:                                # Entity attribute name
                    name: entity_id                # Typesense attribute name
                    type: primary                  # Attribute type
                title: 
                    name: title
                    type: string
                author:
                     name: author
                     type: object                  # Object conversion with __toString()
                author.country:
                    name : author_country          # equivalent of $book->getAuthor()->getCountry()
                    type: string
                genres:
                    name : genres
                    type: collection               # Convert ArrayCollection to array of strings
                publishedAt: 
                    name : published_at
                    type: datetime
            default_sorting_field: published_at    # Default sorting field. Must be primary, int32 or float

Utilisation de Typsense

Création de l'index et indexation des données initiales

Le Bundle est livré avec des commandes utiles pour la création des collections Typsense et l'indexation initiales des données

# Creation collections structure
$ php bin/console typesense:create
# Populate collections with Doctrine entities
$ php bin/console typesense:populate

Recherche de documents

Le Bundle crééedynamiquement des finders utilisables dans vos Services ou vos Controlleurs : typesense.finder.collection_name

# config/services.yaml
services:
    App\Controller\BookController:
        arguments:
            $bookFinder: '@typesense.finder.books'    
<?php
// src/Controller/BookController.php
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use ACSEO\TypesenseBundle\Finder\TypesenseQuery;
//
class BookController extends AbstractController
{
    private $bookFinder;
    public function __construct($bookFinder)
    {
        $this->bookFinder = $bookFinder;
    }
    public function search()
    {
        $query = new TypesenseQuery('Symfony', 'title');
        // Get Doctrine Hydrated objects
        $results = $this->bookFinder->query($query)->getResults();

        // dump($results)
        // array:2 [▼
        //    0 => App\Entity\Book 
        //    1 => App\Entity\Book
        //]

        // Get raw results from Typesence
        $rawResults = $this->bookFinder->rawQuery($query)->getResults();

        // dump($rawResults)
        // array:2 [▼
        //    0 => array:3 [▼
        //        "document" => array:4 [▼
        //        "author" => "Fabien Potencier"
        //        "id" => "100"
        //        "published_at" => 1443744000
        //        "title" => "Symfony 5: The Fast Track"
        //       ]
        //       "highlights" => array:1 [▶]
        //       "seq_id" => 4
        //    ]
        //    1 => array:3 [▼
        //        "document" => array:4 [▶]
        //        "highlights" => array:1 [▶]
        //        "seq_id" => 6
        //    ]
        // ]
    }

Conclusion

Comme vous le voyez, il est très facile de pouvoir utiliser un moteur de recherche puissant dans vos projets Symfony.

Typesense constitue une très bonne alternative, moins gourmande et moins complexe à Elasticsearch, et couvre de nombreux besoins en matière d'indexation et de recherche de données.

Des experts Symfony pour votre projet

Confiez nous le développement de votre projet Symfony

Contactez-nous