Utilisation d'Elasticsearch avec Symfony et la librairie elasticsearch-php

Elastic qui édite Elasticsearch met à disposition la librairie elasticsearch-php. Cette lib simple propose un client à l'API avec toutes les options possible pour se connecter. Son avantage étant d'être léger et de laisser aux développeurs le choix de l'implémentation pour l'utiliser. C'est une très bonne alternative à la librairie Elastica et sa couche d'abstration. Pour ce blog, je l'utilise avec Twig pour gérer mon index mais aussi pour requêter l'API.

Installation et configuration

$ composer require elasticsearch/elasticsearch

Il y a beaucoup d'options de configuration, la documentation est très complète à ce sujet. N'ayant qu'un noeud dans mon cluster, ma configuration est donc très simple.

<?php 
use Elasticsearch\ClientBuilder;
 
$client = EClientBuilder::create()
    ->setHosts(['127.0.0.1:9200'])
    ->build();

M6Web propose un très bon bundle Symfony qui permet de créer le client Elasticsearch via un fichier de configuration YAML puis de récupérer le Client directement depuis le Container Symfony. Petit plus le bundle propose un datacollector pour ajouter dans la debug toolbar de Symfony les requêtes faites à Elasticsearch.

Utilisation de Twig

L'ensemble des requêtes nécessitent le nom de l'index, parfois le type et le corps de la requête. La documentation est basée sur un tableau pour le corps de la requête.

$response = $client->search([
    'index' => 'my_index',
    'type' => 'my_type',
    'body' => [
        'query' => [
            'match' => [
                'testField' => 'abc'
            ]
        ]
    ]
];

Il est également possible d'utiliser un json directement dans le corps de la requête.

$response = $client->search([
    'index' => 'my_index',
    'type' => 'my_type',
    'body' => '{"query": {"match": [{"testField": "abc"}]}}
];

Je préfère la deuxième option, je trouve que le json est plus facilement lisible et surtout je peux le copier/coller pour l'utiliser dans Kibana et debuger ma requête. Il me permet aussi d'apprendre le DSL d'Elasticsearch.

Rendre dynamique un json n'est pas des plus facile en PHP. Par contre avec Twig cela devient un jeu d'enfant.

{
    "_source": {
        "excludes": ["body", "cat_tag"]
    },
    "from": {{ from }},
    "size": {{ size }},
    "query": {
{% if catId != 0 or tagId != 0 %}
        "nested": {
            "path": "{% if catId != 0 %}category{% else %}tags{% endif %}",
            "query": {
                "term": {
                    "{% if catId != 0 %}category{% else %}tags{% endif %}.id": {% if catId != 0 %}{{ catId }}{% else %}{{ tagId }}{% endif %}
                }
            }
        }
{% else %}
        "term": {
            "lang": {
                "value": "{{ lang }}"
            }
        }
{% endif %}
    },
    "sort": [
        {
            "published_at": {
                "order": "desc"
            }
        }
    ]
}

Pour utiliser ce template est vraiment simple, j'ai juste besoin d'injecter Twig comme dépendance.

<?php
declare(strict_types=1);
 
namespace Blog\Search\Request;
 
use Elasticsearch\Client
use Twig\Environment;
 
class Search
{
    /**
     * @var Environment
     */
    private $templating;
 
    /**
     * @var Client
     */
    private $client;
 
    public function __construct(Environment $templating, Client $client)
    {
        $this->templating = $templating;
        $this->client = $client;
    }
 
    public function search(array $tplParams = []): array
    {
        return $this->client->search(
            [
                'index' => 'blog',
                'type' => 'post',
                'body' => $this->templating->render('es/search.json.twig', $tplParams)
           ]
        );
    }
}

J'utilise le même procédé pour la création d'index. Il n'y a que pour l'indexation de document que je garde le format tableau car j'ai eu des problèmes sur l'échappement des guillemets avec l'HTML.

Ajouter un commentaire