<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Indexer des données - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Indexer des données - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/fr/search-labs/blog/category/index-data</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/blog/category/index-data</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/category/index-data.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 15:08:05 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Quand les TSDS rencontrent l'ILM : Concevoir des flux de données temporelles qui ne rejettent pas les données en retard]]></title>
    <description><![CDATA[Comment les limites temporelles des TSDS interagissent avec les phases de l'ILM ; et comment concevoir des politiques qui tolèrent les métriques arrivant en retard.]]></description>
    <content:encoded><![CDATA[<p>Récemment, j'ai migré le cluster de métriques d'un client d'une architecture "tout en accès direct" vers une architecture en mode "chaud/froid/gelé". J'avais pourtant effectué cette migration des dizaines de fois auparavant. Quelques minutes plus tard, Logstash a complètement cessé de transmettre les données.</p><p>Elasticsearch rejetait les métriques arrivant en retard. Ces rejets ont provoqué un retard dans le pipeline, entraînant davantage de données en retard, ce qui a déclenché encore plus de rejets. Finalement, le pipeline s'est complètement arrêté.</p><p>Nous avons dû restaurer les données à partir d'un snapshot, les réindexer et repenser le pipeline d'ingestion pour pouvoir les récupérer.</p><p>La cause principale n'était pas la gestion du cycle de vie des index (ILM) elle-même. C'étaient les flux de données temporelles (TSDS) et la manière dont ils imposent des index sous-jacents limités dans le temps.</p><p>Les TSDS peuvent réduire les besoins de stockage des métriques de 40 à 70 %, mais les modifications architecturales qui optimisent leur fonctionnement influent également sur l'évolution des index. Ces changements sont importants lors de la conception de politiques ILM ou lorsque vos pipelines d'ingestion sont susceptibles de générer des données arrivant en retard.</p><h2>RÉSUMÉ</h2><p>Lors de l'utilisation de TSDS :</p><ul><li><p>Les index sous-jacents acceptent uniquement les documents compris dans une fenêtre temporelle spécifique.</p></li><li><p>Si des données en retard arrivent après qu'un index passe en mode froid ou gelé, Elasticsearch rejette ces documents ou les achemine vers le stockage des échecs, si configuré.</p></li></ul><p>Règle de conception :</p>warm_min_age &gt; rollover_max_age + maximum_expected_lateness<h2>Qu'est-ce qu'un flux de données temporelles ?</h2><p>Un<em> flux de données temporelles</em> (TSDS) est un flux de données spécialisé optimisé pour les données de métriques. Les données sont acheminées de manière à ce que les documents associés soient situés dans les mêmes partitions, optimisant ainsi la requête et la récupération. Voici comment Elasticsearch procède :</p><p>Chaque document contient :</p><ul><li><p>Un horodatage.</p></li><li><p>Des champs dimensionnels qui identifient les séries temporelles.</p></li><li><p>Des champs de métriques qui représentent les valeurs mesurées.</p></li></ul><p>En voici quelques exemples :</p><ul><li><p>Utilisation du processeur par hôte.</p></li><li><p>Latence des requêtes par service.</p></li><li><p>Relevés de température par capteur.</p></li></ul><p>Les <em>dimensions </em>identifient ce que nous voulons mesurer, tandis que les <em>métriques </em>représentent des valeurs qui évoluent au fil du temps.</p><h3>Dimensions</h3><p>Les dimensions décrivent l'entité mesurée.</p><p>Exemples :</p>host.name
service.name
container.id<p>Nous les définissons dans les mappings avec :</p>time_series_dimension: true<h3>Des métriques</h3><p>Les métriques représentent des valeurs numériques et sont définies comme suit :</p>time_series_metric<p>Types de métriques courants :</p><ul><li><p>Jauge : valeurs qui montent et descendent.</p></li><li><p>Compteur : valeurs qui augmentent jusqu'à la réinitialisation.</p></li></ul><p>Elastic Agent collecte principalement des métriques et des données de logs, donc même si vous n'avez pas activé d'index TSDS manuellement, il est possible que vous en ayez toujours dans votre cluster.</p><h3>Le champ _tsid</h3><p>Elasticsearch génère en interne une valeur <code>_tsid</code> à partir des champs de dimensions. Cela permet d'acheminer les documents de dimensions identiques vers la même partition, ce qui améliore :</p><ul><li><p>Compression.</p></li><li><p>Localité de la requête.</p></li><li><p>Performance d'agrégation.</p></li></ul><h2>La principale différence : les index sous-jacents à durée déterminée</h2><p>Les flux de données traditionnels écrivent toujours dans l'index sous-jacent le plus récent, appelé <em>index d'écriture</em>, mais TSDS se comporte différemment.</p><p>Chaque index TSDS sous-jacent comporte une fenêtre temporelle définie et n'accepte que les documents dont les valeurs <code>@timestamp</code> se situent dans cette fenêtre :</p>GET _data_stream/my-metrics-data-stream


     "index_mode": "time_series",
     "time_series": {
       "temporal_ranges": [
         {
           "start": "2026-01-15T14:35:50.000Z",
           "end": "2026-03-16T11:34:40.000Z"
         }
       ]
     }<p>Lorsqu’un document est indexé, Elasticsearch l’achemine vers l’index sous-jacent responsable de cet horodatage, ce qui signifie que, contrairement aux index traditionnels, un TSDS peut écrire simultanément dans plusieurs index sous-jacents.</p><p>Par exemple :</p><ul><li><p>Données en temps réel → dernier index.</p></li><li><p>Données tardives → index plus ancien couvrant cette plage horaire.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b001853af30d5f8/6a17dc2cfaa9137a7d93c751/31af2bb3b3dc24db8342e791e1db77a44659ba7a-1589x502.png" alt="Chronologie montrant comment un document en retard est acheminé vers un index plus ancien, tandis qu'un document actuel est dirigé vers l'index le plus récent." /><h2>Conception pour les données arrivant en retard</h2><p>Dans la réalité, les pipelines d'ingestion fournissent rarement les métriques dans les délais impartis. Les métriques peuvent être retardées par des pannes de réseau, des accumulations de données en cours de route, l'ingestion par lots et la perte d'appareils en périphérie, qui se reconnectent ensuite et commencent à rattraper leur retard.</p><p>Les index traditionnels absorbent discrètement ces retards, ce qui n'est pas le cas des TSDS.</p><p>Si l'horodatage d'un document se situe en dehors de la plage des index de support inscriptibles, Elasticsearch le rejette, ce qui signifie que votre politique ILM doit tenir compte des données en retard.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6e8eae1b2ddad142/6a17dc2e1d1b8335a793e35c/32a103b95b20e31615c214271e27811a7ee315ae-1999x691.png" alt="Chronologie du cycle de vie des index" /><h2>La contrainte critique</h2><p>Les index sous-jacents doivent rester accessibles en écriture suffisamment longtemps pour accepter les données en retard.</p><p>Concrètement :</p>time_until_readonly &gt; maximum_expected_lateness<p>Étant donné que l'ILM mesure l'âge à partir de la substitution, la règle opérationnelle est la suivante :</p>warm_or_cold_min_age &gt; rollover_max_age + maximum_expected_lateness<p></p><p>Par exemple, si les métriques peuvent arriver jusqu'à six heures en retard, les index doivent rester inscriptibles au moins six heures après la substitution.</p><p></p><p>L'absence de prise en compte de cette contrainte est exactement ce qui a causé l'échec d'ingestion décrit précédemment. Les données arrivées en retard ont été dirigées vers un index antérieur, qui se trouvait déjà dans le niveau froid et était donc bloqué en écriture.</p><p></p><h2>Gestion des documents rejetés</h2><p>Lorsqu'un TSDS rejette un document, Elasticsearch renvoie une erreur, indiquant que l'horodatage ne se situe pas dans la plage des index inscriptibles. La façon dont votre pipeline d'ingestion gère cette erreur détermine si vous perdez des données ou si l'ingestion est bloquée.</p><p>Le principal mécanisme pour la gestion des documents rejetés est le magasin des échecs.</p><h3>Stockage des échecs (recommandé dans Elasticsearch 9.1+)</h3><p>Elasticsearch 9.1 a introduit le magasin des échecs, qui capture automatiquement les documents rejetés. Au lieu de renvoyer des erreurs aux clients, Elasticsearch écrit les échecs de documents dans un index d'échec dédié au sein du flux de données.</p><p>Vous pouvez examiner les échecs à l'aide de :</p>GET metrics-myapp::failures/_search<p>L'utilisation du stockage des échecs empêche les pipelines d'ingestion d'être bloqués par des erreurs de rejet, tout en préservant les données rejetées à des fins d'analyse ou de <a href="https://www.elastic.co/docs/manage-data/data-store/data-streams/reindex-tsds">réindexation</a>.</p><h2>Surveillance des problèmes de rejet</h2><p>Les problèmes de retard d'arrivée apparaissent généralement d'abord sous forme d'anomalies d'ingestion. Vous les remarquerez peut-être d'abord comme :</p><ul><li><p>Des chutes soudaines du taux d'indexation.</p></li><li><p>Une forte augmentation du nombre de documents rejetés.</p></li><li><p>Un nombre croissant d'entrées de stockage des échecs.</p></li><li><p>Incohérences entre les nombres d'entrées et de sorties du pipeline.</p></li></ul><p>Les alertes en fonction de ces signaux permet aux opérateurs de détecter les problèmes avant que les pipelines ne s'arrêtent. Les workflows, les tâches de machine learning et d'autres mécanismes peuvent être utilisés pour automatiser la détection et les notifications.</p><h2>Checklist de migration pour les TSDS et l'ILM</h2><p>Si vous migrez un cluster de métriques vers TSDS, introduisez une hiérarchisation ILM ou effectuez une mise à niveau vers une version d'Elasticsearch où les métriques sont TSDS par défaut, consultez d'abord ces éléments.</p><h3><strong>1. Mesurer la latence d'ingestion</strong></h3><p>Avant de modifier les politiques ILM, déterminez :</p><ul><li><p>Le délai d'ingestion normal.</p></li><li><p>Le délai maximal en cas d'incident.</p></li><li><p>Les retards dus aux pipelines de traitement par lots.</p></li></ul><p>Votre conception ILM doit prendre en compte le délai réaliste maximal.</p><h3><strong>2. Vérifier les fenêtres temporelles d'index</strong></h3><p>Vérifiez vos index sous-jacents TSDS :</p>GET _data_stream/&lt;your-stream&gt;<p>Recherchez :</p><ul><li><p><code>time_series.start_time</code></p></li><li><p><code>time_series.end_time</code></p></li></ul><p>Ces limites déterminent quels index peuvent accepter des documents. Comprendre ces délais permet de déterminer la date limite de rejet des données.</p><h3><strong>3. Dimensionner le niveau hot pour les arrivées tardives</strong></h3><p>Assurez-vous que les index sous-jacents restent modifiables suffisamment longtemps pour les données en retard.</p><p>Règle opérationnelle :</p><ul><li><p><code>warm_min_age &gt; rollover_max_age + maximum_expected_lateness</code></p></li></ul><p>N'oubliez pas que les index doivent rester accessibles en écriture pendant au moins six heures si les métriques peuvent arriver avec six heures de retard.</p><h3><strong>4. Décider comment traiter les documents rejetés</strong></h3><p>Choisissez une stratégie avant d'activer TSDS :</p><ul><li><p>Magasin des échecs (recommandé dans Elasticsearch 9.1+).</p></li><li><p>File d'attente des messages Logstash non distribuables.</p></li><li><p>Index de repli pour les arrivées tardives.</p></li><li><p>Accepter une perte de données limitée.</p></li></ul><h3><strong>5. Monitorer l'intégrité de l'ingestion</strong></h3><p>Ajoutez des alertes pour :</p><ul><li><p>Le taux d'indexation chute.</p></li><li><p>Documents refusés.</p></li><li><p>Croissance du magasin des échecs.</p></li><li><p>Incohérences entre les entrées et les sorties du pipeline.</p></li></ul><p>Les problèmes de données tardives apparaissent souvent d'abord sous forme d'anomalies d'ingestion.</p><h2>Résumé</h2><p>Les flux de données temporelles apportent des améliorations majeures en termes de stockage et de performances pour les charges de travail des métriques, mais ils introduisent un changement architectural important : les index sous-jacents sont limités dans le temps, ce qui affecte le comportement de l'ILM.</p><p>Lors de l'utilisation de TSDS :</p><ul><li><p>Les index doivent rester inscriptibles suffisamment longtemps pour accepter les données différées.</p></li><li><p>Les pipelines d'ingestion doivent gérer les documents rejetés de manière sécurisée.</p></li></ul><p>La règle essentielle à retenir est la suivante :</p>warm_min_age &gt; rollover_max_age + maximum_expected_lateness<p>Si vous concevez les politiques ILM en tenant compte de cette contrainte, TSDS fonctionne de manière optimale pour les charges de travail de métriques.</p><p>En revanche, si vous ignorez cette règle, votre pipeline d'ingestion risque de découvrir ces limites temporelles à ses dépens.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/tsds-ilm-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/tsds-ilm-elasticsearch</guid>
    <category><![CDATA[Indexer des données]]></category>
    <category><![CDATA[Base vectorielle]]></category>
    <dc:creator><![CDATA[Bret Wortman]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcacf154aeacb29d8/6a17dc30dbb4ffc7ddfb557f/e4c46e4a6f746d9c845857e80de036f5d51cd4e7-1280x720.png" length="0" type="image/png"/>
    <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elastic Open Web Crawler en tant que code]]></title>
    <description><![CDATA[Apprenez à utiliser les actions GitHub pour gérer les configurations d'Elastic Open Crawler, de sorte que chaque fois que nous apportons des modifications au référentiel, celles-ci sont automatiquement appliquées à l'instance déployée du crawler.]]></description>
    <content:encoded><![CDATA[<p>Avec <a href="https://github.com/elastic/crawler">Elastic Open Web Crawler</a> et son architecture pilotée par CLI, il est désormais assez simple d'avoir des configurations de crawler versionnées et un pipeline CI/CD avec des tests locaux.</p><p>Traditionnellement, la gestion des robots d'indexation était un processus manuel et sujet aux erreurs. Il s'agissait de modifier les configurations directement dans l'interface utilisateur et de se débattre avec le clonage des configurations de crawl, le retour en arrière, la gestion des versions, etc. Traiter les configurations des robots comme du code résout ce problème en offrant les mêmes avantages que ceux que nous attendons du développement de logiciels : répétabilité, traçabilité et automatisation.</p><p>Ce flux de travail facilite l'intégration de l'Open Web Crawler dans votre pipeline CI/CD pour les retours en arrière, les sauvegardes et les migrations, tâches qui étaient beaucoup plus délicates avec les Elastic Crawlers précédents, tels que l'Elastic Web Crawler ou l'App Search Crawler.</p><p>Dans cet article, nous allons apprendre à.. :</p><ul><li><p>Gérer nos configurations de crawl en utilisant GitHub</p></li><li><p>Disposer d'une installation locale pour tester les pipelines avant de les déployer</p></li><li><p>Créer une configuration de production pour exécuter le robot d'exploration avec de nouveaux paramètres à chaque fois que nous apportons des modifications à notre branche principale.</p></li></ul><p>Vous pouvez trouver le dépôt du projet <a href="https://github.com/llermaly/elastic-open-crawler-as-code"><em><strong>ici</strong></em></a><em><strong>. </strong></em><em>Pour l'instant, j'utilise Elasticsearch 9.1.3 et Open Web Crawler 0.4.2.</em></p><h2>Produits requis</h2><ul><li><p>Bureau Docker</p></li><li><p>Instance Elasticsearch</p></li><li><p>Machine virtuelle avec accès SSH (par exemple, AWS EC2) et Docker installé.</p></li></ul><h2>Étapes</h2><ol><li><p>Structure des dossiers</p></li><li><p>Configuration du robot</p></li><li><p>Fichier Docker-compose (environnement local)</p></li><li><p>Actions Github</p></li><li><p>Tests au niveau local</p></li><li><p>Déploiement vers prod</p></li><li><p>Modifications et redéploiement</p></li></ol><h2>Structure des dossiers</h2><p>Pour ce projet, nous aurons la structure de fichier suivante :</p>├── docker-compose.yml # Local elasticsearch + crawler
├── config/crawler-config.yml # Crawler config
├── .github/workflows/deploy.yml # GH Action to deploy changes
├── local.sh # Script to run our local crawler<h2>Configuration du robot</h2><p>Sous <code>crawler-config.yml,</code>, nous mettrons les éléments suivants :</p>output_sink: elasticsearch
output_index: web-crawl-index
max_crawl_depth: 1

elasticsearch:
  host: ${ES_HOST}
  api_key: ${ES_API_KEY}
     
domains:
  - url: https://web-scraping.dev
    seed_urls:
      - https://web-scraping.dev/product/1
      - https://web-scraping.dev/product/2
      - https://web-scraping.dev/product/3<p>Il s'agit d'une recherche à partir de <a href="https://web-scraping.dev/products">https://web-scraping.dev/products,</a> un site fictif pour les produits. Nous ne parcourrons que les trois premières pages du produit. Le paramètre <code>max_crawl_depth</code> empêchera le robot d'exploration de découvrir d'autres pages que celles définies comme <code>seed_urls</code> en n'ouvrant pas les liens qu'elles contiennent.</p><p>Elasticsearch <code>host</code> et <code>api_key</code> seront alimentés dynamiquement en fonction de l'environnement dans lequel nous exécutons le script.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7d37b966aafbd3c1/6a17ef9842022946e929f6b9/f9831034e1c4ccb554d37bdd188f2824338355a0-890x624.png" alt="La page produit pour &quot;Boîte de bonbons au chocolat&quot; provient du domaine web-scraping.dev, un site fictif pour tester le web scraping. La page affiche le titre du produit, l'image, la description et les éléments HTML pour les boutons de prix et d'achat." /><h2>Fichier Docker-compose (environnement local)</h2><p>Pour le site local <code>docker-compose.yml,</code>, nous allons déployer le crawler et un seul cluster Elasticsearch + Kibana, de sorte que nous puissions facilement visualiser nos résultats de crawling <em><strong>avant de</strong></em> les déployer en production.</p>services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:9.1.3
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
    ports:
      - "9200:9200"
    networks: [esnet]
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9200"]
      interval: 5s
      timeout: 5s
      retries: 10

  kibana:
    image: docker.elastic.co/kibana/kibana:9.1.3
    environment:
      - ELASTICSEARCH_HOSTS=http://es01:9200
    ports:
      - "5601:5601"
    networks: [esnet]
    depends_on: [es01]

  crawler:
    image: docker.elastic.co/integrations/crawler:0.4.2
    environment:
      - ES_HOST=http://es01:9200
      - CRAWLER_JRUBY_OPTS=--server
    container_name: crawler
    volumes:
      - ./config:/home/app/config
    networks: [esnet]
    entrypoint: ["/home/app/bin/crawler", "crawl", "/home/app/config/crawl-config-final.yml"]
    stdin_open: true
    tty: true

networks:
  esnet:
    driver: bridge<p>Notez que le crawler attend qu'Elasticsearch soit prêt à fonctionner.</p><h2>Actions Github</h2><p>Nous devons maintenant créer une action GitHub qui copiera les nouveaux paramètres et exécutera le crawler dans notre machine virtuelle à chaque poussée vers main. Ainsi, nous disposons toujours de la dernière configuration déployée, sans avoir à entrer manuellement dans la machine virtuelle pour mettre à jour les fichiers et exécuter le crawler. Nous allons utiliser AWS EC2 comme fournisseur de machines virtuelles.</p><p>La première étape consiste à ajouter l'hôte (<code>VM_HOST</code>), l'utilisateur de la machine (<code>VM_USER</code>), la clé RSA SSH (<code>VM_KEY</code>), l'hôte Elasticsearch (<code>ES_HOST</code>) et la clé API Elasticsearch (<code>ES_API_KEY</code>) aux secrets d'action GitHub :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb5a0fcfff9b7f997/6a17ef9a6df731d7d40a0fdf/e1075bc54151b4b94eac2a6bd2682e9997e6c709-1106x707.png" alt="Une page de configuration &quot;actions, secrets et variables&quot;, affichant les secrets du référentiel tels que VM_HOST, VM_KEY et VM_USER dans une interface web." /><p>De cette manière, l'action pourra accéder à notre serveur pour copier les nouveaux fichiers et exécuter le crawl.</p><p>Maintenant, créons notre fichier <code>.github/workflows/deploy.yml</code>:</p>name: Deploy

on:
  push:
    branches: [main]

jobs:
  Deploy:
    name: Deploy to EC2
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v5

      - name: Deploy crawler
        env:
          HOSTNAME: ${{ secrets.VM_HOST }}
          USER_NAME: ${{ secrets.VM_USER }}
          PRIVATE_KEY: ${{ secrets.VM_KEY }}
          ES_HOST: ${{ secrets.ES_HOST }}
          ES_API_KEY: ${{ secrets.ES_API_KEY }}
        run: |
          # Save private key
          echo "$PRIVATE_KEY" &gt; private_key
          chmod 600 private_key

          # Generate final config locally
          envsubst &lt; config/crawler-config.yml &gt; config/crawl-config-final.yml

          # Copy the config folder to VM
          scp -o StrictHostKeyChecking=no -i private_key -r config ${USER_NAME}@${HOSTNAME}:~/config

          # SSH into VM and run crawler
          ssh -o StrictHostKeyChecking=no -i private_key ${USER_NAME}@${HOSTNAME} &lt;&lt; EOF
            docker run --rm \
              -v ~/config:/config \
              docker.elastic.co/integrations/crawler:latest jruby \
              bin/crawler crawl /config/crawl-config-final.yml
          EOF<p>Cette action exécutera les étapes suivantes à chaque fois que des modifications seront apportées au fichier de configuration du crawler :</p><ol><li><p>Renseigner l'hôte Elasticsearch et la clé API dans la configuration yml</p></li><li><p>Copier le dossier config sur notre VM</p></li><li><p>Se connecter via SSH à notre VM</p></li><li><p>Exécuter le crawl avec la configuration que nous venons de copier depuis le repo</p></li></ol><h2>Tests au niveau local</h2><p>Pour tester notre crawler localement, nous avons créé un script bash qui remplit l'hôte Elasticsearch avec l'hôte local de Docker et démarre un crawl. Vous pouvez lancer <code>./local.sh</code> pour l'exécuter.</p>#!/bin/bash

# Exit on any error
set -e

# Load environment variables
export ES_HOST="http://es01:9200"

# Generate final crawler config
envsubst &lt; ./config/crawler-config.yml &gt; ./config/crawl-config-final.yml

# Bring everything up
docker compose up --build<p>Regardons Kibana DevTools pour confirmer que le site<code> web-crawler-index</code> a été correctement renseigné :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt989660368fe14db8/6a17ef9b9da390c79ce46562/18551635e8265866e389a9632c4e4540958e4468-990x723.png" alt="Code Kibana DevTools pour confirmer que le web-crawler-index est correctement configuré." /><h2>Déploiement vers prod</h2><p>Nous sommes maintenant prêts à pousser vers la branche principale, ce qui déploiera le crawler dans votre machine virtuelle et commencera à envoyer des logs à votre instance Serverless Elasticsearch.</p>git add .
git commit -m "First commit"
git push<p>Cela déclenchera l'action GitHub, qui exécutera le script de déploiement dans la machine virtuelle et commencera l'exploration.</p><p>Vous pouvez confirmer que l'action a été exécutée en allant sur le dépôt GitHub et en visitant l'onglet "Actions" :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt986f1a4e4f3288d2/6a17ef9c7f6f1584fdc09c10/67ba3a7164d7a8049fe5661264820826cb18ed64-667x325.png" alt="Les actions se déploient sur l'onglet EC2 dans un dépôt GitHub." /><h2>Modifications et redéploiement</h2><p>Vous avez peut-être remarqué que le site <code>price</code> de chaque produit fait partie du champ "body" du document. L'idéal serait de stocker le prix dans un champ distinct afin de pouvoir utiliser des filtres.</p><p>Ajoutons cette modification au fichier <code>crawler.yml</code> afin d'utiliser des <a href="https://github.com/elastic/crawler/blob/main/docs/features/EXTRACTION_RULES.md">règles d'extraction</a> pour extraire le prix de la classe CSS <code>product-price</code>:</p>output_sink: elasticsearch
output_index: web-crawl-index
max_crawl_depth: 1

elasticsearch:
  host: ${ES_HOST}
  api_key: ${ES_API_KEY}
     
  # Index ingest pipeline to process documents before indexing          
  pipeline_enabled: true
  pipeline: pricing-pipeline

domains:
  - url: https://web-scraping.dev
    seed_urls:
      - https://web-scraping.dev/product/1
      - https://web-scraping.dev/product/2
      - https://web-scraping.dev/product/3
    extraction_rulesets:
      - url_filters:
          - type: ends
            pattern: /product/*
        rules:
          - action: extract
            field_name: price
            selector: .product-price
            join_as: string
            source: html<p>Nous constatons également que le prix comprend un signe de dollar (<code>$</code>), que nous devons supprimer si nous voulons exécuter des requêtes de plage. Nous pouvons utiliser un pipeline d'acquisition pour cela. Notez que nous y faisons référence dans notre nouveau fichier de configuration du crawler ci-dessus :</p>PUT _ingest/pipeline/pricing-pipeline
{
  "processors": [
    {
      "script": {
        "source": """
                ctx['price'] = ctx['price'].replace("$","")
            """
      }
    }
  ]
}<p>Nous pouvons exécuter cette commande dans notre cluster Elasticsearch de production. Pour celui de développement, comme il est éphémère, nous pouvons intégrer la création du pipeline dans le fichier <code>docker-compose.yml</code> en ajoutant le service suivant. Notez que nous avons également ajouté un <code>depends_on</code> au service crawler afin qu'il démarre après la création réussie du pipeline.</p> crawler:
    image: docker.elastic.co/integrations/crawler:0.4.2
    environment:
      - ES_HOST=http://es01:9200
      - CRAWLER_JRUBY_OPTS=--server
    container_name: crawler
    volumes:
      - ./config:/home/app/config
    networks: [esnet]
    entrypoint: ["/home/app/bin/crawler", "crawl", "/home/app/config/crawl-config-final.yml"]
    depends_on:
      pipeline-init:
        condition: service_completed_successfully
    stdin_open: true
    tty: true  


  pipeline-init:
    image: curlimages/curl:latest
    depends_on:
      es01:
        condition: service_healthy
    networks: [esnet]
    entrypoint: &gt;
        sh -c "
        echo 'Creating ingest pipeline...';
        curl -s -X PUT http://es01:9200/_ingest/pipeline/pricing-pipeline \\
          -H 'Content-Type: application/json' \\
          -d '{\"processors\":[{\"script\":{\"source\":\"ctx.price = ctx.price.replace(\\\"$\\\", \\\"\\\")\"}}]}';
        echo 'Pipeline created!';
        "<p>Exécutons maintenant <code>`./local.sh`</code> pour voir les changements localement :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f390aedf67cb4fe/6a17ef9eaf47b62bd2cde05b/dc1801599344a9f69f072b07ff828c4ba3815d7b-738x473.png" alt="Exécution de `./local.sh` pour voir le prix changer localement." /><p>C'est très bien ! Poussons maintenant la modification :</p>git add crawler-config.yml
git commit -m "added price CSS selector"
git push<p>Pour confirmer que tout fonctionne, vous pouvez vérifier votre Kibana de production, qui devrait refléter les changements et afficher le prix comme un nouveau champ sans le signe du dollar.</p><h2>Conclusion</h2><p>Elastic Open Web Crawler vous permet de gérer votre crawler en tant que code, ce qui signifie que vous pouvez automatiser l'ensemble du pipeline - du développement au déploiement - et ajouter des environnements locaux éphémères et des tests sur les données explorées de manière programmatique, pour ne citer que quelques exemples.</p><p>Vous êtes invités à cloner le dépôt officiel et à commencer à indexer vos propres données à l'aide de ce flux de travail. Vous pouvez également lire <a href="https://www.elastic.co/search-labs/blog/semantic-search-open-crawler">cet article</a> pour apprendre comment effectuer une recherche sémantique sur les index produits par le crawler.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elastic-open-crawler-config-as-code</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elastic-open-crawler-config-as-code</guid>
    <category><![CDATA[Indexer des données]]></category>
    <category><![CDATA[Opérations]]></category>
    <dc:creator><![CDATA[Gustavo Llermaly]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt00e7c95012dc38cc/6a17efa0fbc5f80dad491b93/0ac41f55c85ad3f647cb0e0d750ed80bacd397f3-1036x581.png" length="0" type="image/png"/>
    <pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment afficher les champs d'un index Elasticsearch ?]]></title>
    <description><![CDATA[Apprenez à afficher les champs d'un index Elasticsearch à l'aide des API _mapping et _search, des sous-champs, de la _source synthétique et des champs d'exécution.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous verrons comment afficher les champs d'un index Elasticsearch. Cela peut être utile pour comprendre la structure de vos données, identifier des champs spécifiques et résoudre des problèmes. Nous aborderons les sujets suivants :</p><ol><li><p>Utilisation de l'API <code>_mapping</code> pour récupérer des informations sur les champs</p></li><li><p>Utilisation de l'API <code>_search</code> pour afficher les valeurs des champs</p></li><li><p>Affichage des sous-champs</p></li><li><p>Synthetic _source</p></li><li><p>Champs d'exécution</p></li></ol><h2>1. Utilisation de l'API _mapping pour récupérer des informations sur les champs</h2><p>L'API <code>_mapping</code> vous permet de récupérer la définition du mappage pour un ou plusieurs index. Il s'agit d'informations sur les champs, leurs types de données et d'autres propriétés. Pour récupérer le mappage d'un index spécifique, utilisez la requête suivante :</p>GET /&lt;index_name&gt;/_mapping<p>Par exemple, si vous avez un index nommé <code>my_index</code>, vous pouvez récupérer son mapping avec la requête suivante :</p>GET /my_index/_mapping<p>La réponse comprendra la définition du mappage pour l'index, qui contient des informations sur les champs et leurs propriétés.</p><p>Il est également possible de récupérer la cartographie d'un champ spécifique. Cela peut s'avérer utile si votre cartographie est assez vaste et que vous souhaitez vous concentrer sur un domaine spécifique. Pour récupérer la correspondance d'un champ spécifique, utilisez la requête suivante :</p>GET /my_index/_mapping/field/my_field<p>Vous pouvez également récupérer les correspondances de plusieurs champs en séparant leurs noms par des virgules, comme dans la requête suivante :</p>GET /my_index/_mapping/field/my_field_1,my_field_2,my_field_3<h2>2. Utilisation de l'API _search pour afficher les valeurs des champs</h2><p>Pour afficher les valeurs des champs d'un index Elasticsearch, vous pouvez utiliser l'API <code>_search</code>. L'API <code>_search</code> vous offre plusieurs moyens de contrôler les champs renvoyés ; les deux principaux sont les suivants :</p><ol><li><p><strong><code>_source</code></strong>: Le champ <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field"><code>_source</code></a> contient le corps du document JSON original tel qu'il a été indexé, y compris les modifications apportées par les pipelines d'ingestion ou les étapes de prétraitement. Pour afficher des champs spécifiques du document source, il faut mettre en œuvre le filtrage de la source, comme nous le verrons ci-dessous.</p></li><li><p><strong><code>fields</code></strong>: Le paramètre <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields"><code>fields</code></a> vous permet d'extraire des champs spécifiques de vos documents lors d'une recherche, sur la base du mappage de l'index. Contrairement à <code>_source</code>, <code>fields</code> peut également renvoyer des valeurs provenant de champs stockés, de valeurs documentaires ou de champs d'exécution sans faire référence à <code>_source</code>, bien que pour les champs standard sans valeurs documentaires ou paramètres stockés, il se réfère à <code>_source</code>. Cela peut apporter de nombreux avantages, notamment en termes de performances, comme nous le verrons ci-dessous.</p></li></ol><h3>Utilisation du champ _source</h3><p>Par défaut, l'API<code> _search</code> renvoie le champ <code>_source</code>, qui contient le document JSON original qui a été indexé. Pour afficher des champs spécifiques, vous pouvez ajouter des filtres dans le paramètre <code>_source </code>de la demande de recherche ; c'est ce qu'on appelle le filtrage à la source.</p><p>Voici un exemple de demande de recherche qui renvoie les valeurs des champs <code>title </code>et <code>author</code> pour les documents de l'index <code>my_index</code>:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title", "author"]
}<p>Dans cet exemple, le paramètre <code>_source</code> spécifie les champs à renvoyer.</p><p>Si vous avez besoin d'encore plus de contrôle, vous pouvez utiliser les propriétés <code>includes</code> et <code>excludes </code>de l'objet <code>_source</code>. Par exemple, la requête ci-dessous renvoie le champ de premier niveau <code>title</code> et tous les sous-champs de <code>author</code> à l'exception de <code>author.description</code>.</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": {
     “includes”: [“title”, “author.*],
     “excludes”: [“author.description”]
  }
}<p>Dans cet exemple, nous utilisons le modèle <code>author.* </code>pour récupérer tous les sous-champs directs de l'objet <code>author </code>. Nous excluons ensuite explicitement <code>author.description </code>afin que seuls les autres champs relatifs à l'auteur soient renvoyés. Notez que cela n'améliore pas les performances, puisqu'il faut toujours charger et analyser la source JSON, mais cela permet de réduire la taille de la réponse envoyée sur le réseau.</p><h3>Utilisation du paramètre champs</h3><p>Vous pouvez utiliser le paramètre <code>fields</code> pour filtrer les champs renvoyés dans la réponse de recherche. L'utilisation de <code>fields</code> par rapport à <code>_source</code> présente plusieurs avantages, notamment</p><ul><li><p><strong>Amélioration des performances : </strong><code>fields </code>peut renvoyer des valeurs directement à partir de <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-store">champs stockés</a> ou de <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/doc-values">valeurs de documents</a> sans avoir à charger l'intégralité du site <code>_source</code>, ce qui réduit la taille de la charge utile de la réponse.</p></li><li><p><strong>Sortie formatée :</strong> Pour les champs standard,<code> fields</code> peut se référer à <code>_source</code> pour récupérer les valeurs, mais il s'appuie sur le mappage de l'index pour formater correctement la sortie, comme les dates formatées, afin de les rendre cohérentes avec ce qui est utilisé pour les agrégations et les tris.</p></li><li><p><strong>Accès aux champs d'exécution :</strong> <code>fields</code> peut renvoyer des champs d'exécution qui n'existent pas sur le site original <code>_source</code>.</p></li><li><p>D'autres avantages peuvent être trouvés <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields#search-fields-param">ici.</a></p></li></ul><p>Par exemple, pour obtenir uniquement les champs <code>title</code> et <code>author</code> dans l'index <code>my_index</code>, vous pouvez utiliser la requête de recherche suivante :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author"],
  "_source": false
}<p>Dans la requête ci-dessus, nous attribuons la valeur false au champ <code>_source </code>afin de ne pas renvoyer le document source. Cela peut réduire considérablement la taille de la charge utile de la réponse, mais n'oubliez pas que cela ne fonctionne que si les champs <code>title</code> et <code>author</code> sont de type <code>keyword </code>, pour lesquels <code>doc_values</code> est activé par défaut. Si le champ n'a pas été activé par <code>doc_values</code> et que <code>_source</code> a été défini sur false, Elasticsearch n'aura aucun moyen de les récupérer et ils seront ignorés dans la réponse.</p><p>Il est important de noter que la réponse <code>fields</code> renvoie toujours un tableau de valeurs pour chaque champ, même s'il n'y a qu'une seule valeur. Cela est dû au fait qu'Elasticsearch n'a pas de type de tableau dédié, et que tout champ peut avoir plusieurs valeurs. Pour plus d'informations sur les tableaux dans Elasticsearch, cliquez <a href="http://elastic.co/docs/reference/elasticsearch/mapping-reference/array">ici.</a></p><h3>Autres moyens d'extraire des champs</h3><p>Bien que l'extraction de champs à l'aide de <code>_source</code> ou <code>fields</code> soit la méthode recommandée, il existe d'autres méthodes pour des cas d'utilisation spécifiques, comme par exemple :</p><p><strong>Champs de valeur du document :</strong> Si vous souhaitez éviter <code>_source</code>, vous pouvez effectuer une recherche en utilisant le paramètre <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields#docvalue-fields"><code>docvalue_fields</code></a> . Doc values stocke les mêmes valeurs de champ que <code>_source</code> mais dans une structure de données sur disque, optimisée pour les tris et les agrégations.</p><p>Comme il s'agit d'une valeur distincte des valeurs stockées sur <code>_source</code>, vous pouvez demander des champs spécifiques sans avoir à charger l'ensemble du site <code>_source</code>. Cette option est utile si vous interrogez des documents volumineux, mais que vous n'avez besoin que de quelques petits champs prenant en charge des valeurs de documents. Un autre cas d'utilisation de <code>docvalue_fields </code>est celui où vous souhaitez utiliser un formatage personnalisé pour les champs <code>date</code> et <code>numeric</code>, comme nous le verrons dans l'exemple ci-dessous.</p><p>Notez que cela ne fonctionne que pour les champs pour lesquels vous avez activé <code>doc_values</code> ou pour les types de champs pour lesquels cette option est activée par défaut, tels que <code>keyword</code>, <code>date</code>, les types numériques et <code>boolean</code>, et non pour <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/text"><code>text</code></a> ou <a href="https://www.elastic.co/docs/reference/elasticsearch/plugins/mapper-annotated-text-usage"><code>annotated_text</code></a>.</p><p>Dans cet exemple, nous utilisons le paramètre <code>docvalue_fields</code> pour récupérer les champs <code>title</code>, <code>author</code> et <code>published</code> sans charger le document <code>_source</code> complet :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "docvalue_fields": [
    "title",
    "author",
    {
      "field": "published",
      "format": "epoch_millis"
    }
  ],
  "_source": false
}<p>Lorsque cette requête est exécutée, Elasticsearch récupère les valeurs directement à partir de son magasin en colonnes sur disque au lieu de référencer le site <code>_source </code>pour chaque document. Le champ <code>published</code> est retourné avec le format <code>epoch_millis</code> au lieu du format par défaut, grâce au paramètre <code>format</code> fourni dans la requête.</p><p><strong>Champs stockés :</strong> Si vous avez explicitement marqué des champs spécifiques comme étant <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-store">stockés</a> dans le mappage, vous pouvez utiliser le paramètre <code>stored_fields</code> pour filtrer ces champs. C'est utile si vous voulez des réponses légères avec seulement ces champs spécifiques ou pour les champs que vous avez délibérément stockés pour les retrouver plus tard. Il est stocké séparément de <code>_source</code>, de sorte que cette méthode est également utile pour éviter de devoir charger <code>_source</code>.</p><p>Il est important de noter que cette option est désactivée par défaut et qu'elle n'est généralement pas recommandée. Utilisez plutôt le filtrage des sources pour renvoyer certains sous-ensembles du document source original.</p><p>Dans l'exemple de requête ci-dessous, nous utilisons le paramètre <code>stored_fields</code> pour récupérer le champ <code>summary</code>, dont la configuration de mappage d'index est "<code>store”: true</code>.</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "stored_fields": ["summary"]
}<p>Lorsque cette requête est exécutée, Elasticsearch vérifie si ce champ a été marqué par <code>”store”: true</code>, s'il ne le trouve pas, il l'ignore complètement.</p><h2>3. Affichage des sous-champs</h2><p>Si votre index contient des sous-champs, vous pouvez utiliser la notation point pour spécifier le chemin d'accès au champ dans le paramètre <code>fields</code>. Notez que les sous-champs sont différents du <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/nested">type de champ imbriqué</a>. Par exemple, si vous avez un sous-champ nommé <code>address.city</code>, vous pouvez l'inclure dans la réponse de recherche comme suit :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author", "address.city"],
  "_source": false
}<p>Dans cet exemple, la réponse de la recherche comprendra les valeurs des champs <code>title</code>, <code>author</code> et <code>address.city</code>.</p><h2>4. Synthétique _source</h2><p>Si vous souhaitez conserver la fonctionnalité de<code> _source</code> tout en économisant de l'espace disque, vous avez la possibilité d'utiliser le site synthétique <code>_source</code> dans votre mappage d'index. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field#synthetic-source">Synthetic </a><a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field#synthetic-source"><code>_source</code></a> est une fonctionnalité qui permet à Elasticsearch de reconstruire <code>_source</code> à partir de données existantes telles que des champs stockés et des valeurs de documents, même lorsque <code>_source</code> est désactivé. Cela vous permet d'économiser beaucoup d'espace de stockage au prix d'une vitesse légèrement inférieure au moment de l'interrogation, car la reconstruction se fait à la volée. Activez cette fonction en utilisant les valeurs ci-dessous dans vos paramètres d'index :</p>PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  }
}<p>Parmi les avantages de l'utilisation de la version synthétique de <code>_source </code>, citons : l'affichage complet du document lors de l'utilisation de l'API <code>_search</code>, le filtrage des sources et la compatibilité avec d'autres fonctionnalités et outils tels que Kibana qui s'attendent à ce que <code>_source</code> soit disponible, tout en évitant d'avoir à stocker le document <code>_source</code> dans son intégralité.</p><h2>5. Champs d'exécution</h2><p>Les champs <a href="https://www.elastic.co/docs/manage-data/data-store/mapping/runtime-fields">d'exécution</a> vous permettent de définir des champs scriptés au moment de la requête ou dans votre mappage d'index sous un bloc d'exécution. Ces champs ne sont jamais indexés, de sorte que l'ajout d'un champ d'exécution n'augmente pas la taille de l'index mais n'apparaîtra jamais dans <code>_source</code>. Les champs d'exécution définis dans le mappage sont persistants et disponibles pour toutes les requêtes, tandis que les champs d'exécution définis au moment de la requête sont temporaires et ne sont disponibles que dans cette requête de recherche.</p><p>Le principal avantage de l'utilisation des champs d'exécution est la possibilité d'ajouter des champs aux documents après les avoir ingérés, ce qui simplifie vos décisions en matière de mappage. Les champs d'exécution sont également très utiles pour enrichir vos documents avec des valeurs qui n'existent pas dans le document original mais qui sont générées à l'aide d'un script, comme le formatage d'une chaîne de caractères ou le calcul d'un score.</p><p>Il convient également de noter que les champs d'exécution peuvent nuire aux performances, car un script devra être exécuté pour chaque document de l'ensemble des résultats. Pour <a href="https://www.elastic.co/docs/manage-data/data-store/mapping/retrieve-runtime-field">récupérer un champ d'exécution</a>, vous pouvez également utiliser le paramètre <code>fields</code> de l'API <code>_search</code>.</p><h2>Conclusion</h2><p>L'affichage des champs d'un index Elasticsearch peut aller de la simple récupération des valeurs à l'aide du mappage d'index ou de <code>_source</code>, à des méthodes plus avancées utilisant <code>fields</code>, <code>docvalue_fields</code>, ou des champs d'exécution pour un meilleur contrôle et une plus grande efficacité. Il est essentiel de comprendre les compromis entre les différentes méthodes pour optimiser vos expériences de recherche. Qu'il s'agisse d'optimiser les charges utiles, d'enrichir des documents ou d'utiliser le site synthétique <code>_source</code> pour économiser de l'espace de stockage, Elasticsearch vous offre de nombreux outils et fonctionnalités pour trouver les données dont vous avez besoin, de la manière dont vous en avez besoin. Ces techniques peuvent vous aider à comprendre la structure de vos données, à identifier des champs spécifiques et à résoudre des problèmes.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-index-show-fields</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-index-show-fields</guid>
    <category><![CDATA[Indexer des données]]></category>
    <category><![CDATA[Mappings]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd041e871a8935448/6a17de320b0bedf404dd34ab/23b96aaa1a38b1f4747b4a87695d816f24c0cf70-720x421.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 06 Aug 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Scripting Ruby dans Logstash]]></title>
    <description><![CDATA[Découvrez le plugin Logstash Ruby filter pour une transformation avancée des données dans votre pipeline Logstash.]]></description>
    <content:encoded><![CDATA[<p>Logstash est un pipeline de traitement de données qui ingère des données provenant de sources multiples, les transforme et les envoie vers les destinations de votre choix. Les plugins de filtrage sont essentiels pour ce processus ; ils effectuent des opérations spécifiques sur vos données lorsqu'elles passent par le pipeline.</p><p>Logstash comprend plusieurs filtres intégrés pour les tâches courantes telles que l'analyse, l'enrichissement et la modification des données. Mais parfois, vous rencontrerez des scénarios qui nécessiteront une logique personnalisée allant au-delà de ce que ces filtres standard peuvent fournir. C'est là qu'intervient le <a href="https://www.elastic.co/docs/reference/logstash/plugins/plugins-filters-ruby">plugin Ruby filter</a>.</p><p><strong>Le plugin Ruby filter vous permet d'exécuter du code Ruby personnalisé directement dans votre pipeline Logstash.</strong> Lorsque les filtres standard ne suffisent pas, le filtre Ruby vous permet de gérer des transformations de données complexes, de mettre en œuvre une logique commerciale personnalisée ou d'intégrer des systèmes externes.</p><p>Dans ce blog, nous allons explorer comment utiliser les filtres Ruby, de l'utilisation basique à l'utilisation avancée.</p><h2>Quand utiliser le filtre Ruby ?</h2><p>En tant qu'architecte consultant d'Elastic, je vois souvent des clients utiliser Logstash pour le pipeline de traitement des données, même s'il ne s'agit pas aujourd'hui d'un moteur de traitement des données à la pointe de la technologie. Ils se heurtent souvent aux limites des filtres standard lorsqu'il s'agit de manipuler des données complexes ou d'appliquer une logique personnalisée. Dans ce cas, le filtre Ruby peut aider à surmonter ces difficultés.</p><p>Le filtre Ruby est utile lorsque les filtres standard de Logstash ne peuvent pas répondre à vos besoins spécifiques. Voici quelques cas d'utilisation courants :</p><ul><li><p><strong>Manipulation de données imbriquées en profondeur</strong>: Modifier des structures JSON complexes, des tableaux dans des tableaux, ou restructurer dynamiquement des données en fonction de leur contenu.</p></li><li><p><strong>Traitement avancé des chaînes de caractères</strong>: Analyse et extraction de données structurées à partir de textes non structurés</p></li><li><p><strong>Mise en œuvre d'une logique d'entreprise complexe</strong>: Créer des transformations personnalisées qui nécessitent une logique conditionnelle, des boucles ou des calculs complexes.</p></li></ul><h2>Utilisation de base</h2><p>Commençons par un exemple simple pour comprendre le fonctionnement du filtre Ruby.</p><h3>Configuration du filtre Ruby</h3><p>Lorsque vous créez un pipeline Logstash, vous devez placer le fichier de configuration dans le répertoire <code>/etc/logstash/conf.d</code>. Alternativement, vous pouvez utiliser l'option <code>-f</code> pour spécifier le chemin vers le fichier de configuration lorsque vous démarrez Logstash manuellement, afin que vous puissiez expérimenter vos pipelines facilement.</p>$ ./bin/logstash -f /path/to/your_pipeline.conf<p>Le fichier de configuration doit avoir une extension <code>.conf</code>.</p><p>Pour utiliser le filtre Ruby, définissez un filtre <code>ruby</code> dans la section filter de votre fichier de configuration du pipeline Logstash (*.conf). Voici un exemple de base :</p>filter {
  ruby {
    code =&gt; "
      event.set('new_field', 'Hello from Ruby!')
    "
  }
}<p>Ce filtre Ruby en ligne définit une instance de filtre Ruby dans votre configuration Logstash. Le paramètre <code>code</code> fournit le script Ruby en ligne que Logstash exécutera pour chaque événement traité par ce filtre. Dans ce script, il existe une variable <code>event</code> qui représente l'événement lui-même. L'objet événement contient les données originales envoyées à Logstash et tous les champs supplémentaires créés lors des étapes de filtrage de Logstash. Vous pouvez accéder à ces champs via l'API Logstash Event telle que <code>event.get()</code> et <code>event.set()</code>. Dans cet exemple de code, <code>event.set('new_field', 'Hello from Ruby!')</code> attribue à un nouveau champ nommé <code>new_field</code> la valeur de chaîne <code>Hello from Ruby!</code>. Vous pouvez ajouter tout autre code dans ce bloc <code>code</code> si nécessaire.</p><p>Notez que cet objet <code>event</code> n'est pas un objet de hachage Ruby habituel, bien qu'il agisse comme un conteneur de données de type clé-valeur. Consultez <a href="https://www.elastic.co/docs/reference/logstash/event-api">la documentation officielle</a> pour en savoir plus sur l'API des événements.</p><h3>Externaliser le script Ruby</h3><p>Pour les transformations simples, le code Ruby en ligne est pratique. Mais pour une logique complexe ou des fonctions réutilisables, il est recommandé de déplacer le code dans un script Ruby externe. Cela permet d'améliorer la maintenabilité et de conserver une configuration propre du pipeline Logstash.</p><p>Tout d'abord, créez un script Ruby et enregistrez-le sous <code>my_ruby_script.rb</code>. Le script doit définir une méthode <code>filter</code> qui traite l'événement. Elle prend en argument un objet événement qui représente l'événement en cours de traitement. La méthode <code>filter</code> doit renvoyer un tableau d'événements à émettre. Pour supprimer l'événement, renvoyer un tableau vide.</p><p>Par exemple, le script suivant lit la rubrique <code>message</code>, calcule sa longueur et stocke le résultat dans une nouvelle rubrique appelée <code>message_length</code>.</p>def register(params)
  # This method is called when the plugin is loaded.
  # You can use it to initialize any instance variables or perform setup tasks.
end

def filter(event)
  message = event.get('message')

  if message
    event.set('message_length', message.length)
  end

  return [event]
end<p>Ensuite, définissez la configuration du filtre Ruby pour qu'il fasse référence au script à l'aide de l'option <code>path</code>. Cela indique à Logstash de charger et d'exécuter le script externe. Lors de l'utilisation de scripts externes, assurez-vous que le fichier existe et que les autorisations sont correctes.</p>filter {
  ruby {
    path =&gt; "/path/to/my_ruby_script.rb"
  }
}<p>Maintenant, chaque événement est transmis à la méthode <code>filter</code> dans <code>my_ruby_script.rb</code> et est traité par elle.</p><p>Cette approche vous permet de gérer plus efficacement une logique complexe, ce qui facilite les tests, le débogage et la réutilisation de votre code Ruby.</p><h2>Utilisation avancée</h2><p>Dans cette section, nous allons explorer quelques exemples avancés d'utilisation du filtre Ruby dans Logstash. Ces exemples montrent comment effectuer des transformations de données, enrichir des événements et mettre en œuvre une logique personnalisée à l'aide de Ruby.</p><h3>Manipulation de structures de données imbriquées</h3><p>Un événement Logstash est la structure de données centrale que Logstash traite. Il peut contenir différents champs, y compris des structures de données imbriquées telles que des tableaux et des hachages. Le filtre Ruby permet de manipuler facilement ces structures imbriquées.</p><p>Le filtre Ruby peut gérer des structures de données imbriquées, telles que des hachages et des tableaux, ce qui permet de modifier ou d'ajouter des champs dans ces structures. Cette fonction est utile lorsqu'il s'agit de traiter des formats de données complexes tels que JSON.</p>input {
  generator {
    lines =&gt; [
      '{"nested": {"key1": "value1", "key2": "value2"}}'
    ]
    count =&gt; 1
    codec =&gt; "json"
    ecs_compatibility =&gt; "disabled"
  }
}

filter {
  ruby {
    code =&gt; "
      nested_data = event.get('nested')

      if nested_data.is_a?(Hash)
        nested_data['key3'] = 'value3'
        event.set('nested', nested_data)
      end
    "
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Cet exemple inclut un objet JSON imbriqué dans les données d'entrée. Le filtre Ruby modifie les données imbriquées en ajoutant une nouvelle paire clé-valeur. Ce type de manipulation des données imbriquées n'est pas possible avec les filtres Logstash standard, ce qui fait du filtre Ruby une option pratique pour les structures de données complexes.</p><h3>Diviser un événement unique en plusieurs événements</h3><p>Les filtres Ruby peuvent également être utilisés pour diviser un événement unique en plusieurs événements. Ceci est utile lorsque vous avez un événement unique contenant un tableau d'éléments et que vous souhaitez créer des événements distincts pour chaque élément.</p><p>Notez que ni le pipeline d'acquisition d'Elasticsearch ni les processeurs de Beats/Elastic Agent ne prennent en charge le fractionnement des événements. C'est l'un des cas d'utilisation les plus importants pour Logstash.</p><h4>Avec filtre divisé</h4><p>Vous pouvez utiliser le filtre <code>split</code> pour diviser un événement en plusieurs événements sur la base d'un champ spécifié. Toutefois, si vous devez effectuer des transformations ou des opérations logiques supplémentaires pendant le fractionnement, vous pouvez utiliser le filtre Ruby en combinaison avec le filtre de fractionnement.</p><p>Dans l'exemple suivant, nous avons un flux RSS sous la forme d'une seule ligne de texte XML. Il contient plusieurs éléments <code>&lt;item&gt;</code>. Le filtre Ruby est utilisé pour extraire les éléments <code>&lt;item&gt;</code> du XML et les stocker dans un nouveau champ appelé <code>items</code>. Le filtre de division est ensuite utilisé pour diviser l'événement en plusieurs événements sur la base du champ <code>items</code>.</p>input {
  generator {
    lines =&gt; [
      '&lt;rss version="2.0"&gt;&lt;channel&gt;&lt;title&gt;Sample RSS&lt;/title&gt;&lt;item&gt;&lt;title&gt;Article 1&lt;/title&gt;&lt;link&gt;http://example.com/1&lt;/link&gt;&lt;description&gt;Desc 1&lt;/description&gt;&lt;/item&gt;&lt;item&gt;&lt;title&gt;Article 2&lt;/title&gt;&lt;link&gt;http://example.com/2&lt;/link&gt;&lt;description&gt;Desc 2&lt;/description&gt;&lt;/item&gt;&lt;/channel&gt;&lt;/rss&gt;'
    ]
    count =&gt; 1
    codec =&gt; "plain"
    ecs_compatibility =&gt; "disabled"
  }
}

filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    code =&gt; "event.set('items', event.get('[rss][channel][item]')) if event.get('[rss][channel][item]')"
  }
  split {
    field =&gt; "items"
  }
  ruby {
    code =&gt; "
      item = event.get('items')
      event.set('title', item['title']) if item['title']
      event.set('link', item['link']) if item['link']
      event.set('description', item['description']) if item['description']
    "
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Le résultat sera le suivant :</p>{
          "title" =&gt; "Article 1",
           "link" =&gt; "http://example.com/1",
    "description" =&gt; "Desc 1"
}
{
          "title" =&gt; "Article 2",
           "link" =&gt; "http://example.com/2",
    "description" =&gt; "Desc 2"
}<p>Comme vous l'avez peut-être remarqué, le filtre <code>ruby</code> n'est pas indispensable dans ce cas. Le filtre <code>split</code> peut être utilisé pour diviser l'événement en plusieurs événements sur la base du champ <code>items</code>, et le filtre <code>mutate</code> peut être utilisé pour supprimer les champs inutiles. Toutefois, si vous devez effectuer des transformations ou des opérations logiques supplémentaires pendant le fractionnement, vous pouvez utiliser le filtre Ruby.</p><h4>Utiliser un script Ruby en ligne</h4><p>Vous pouvez également utiliser un script Ruby en ligne pour diviser un événement unique en plusieurs événements en utilisant la méthode <code>event.clone</code> et la méthode <code>new_event_block variable</code>, telle que <code>new_event_block.call(new_event)</code>. Cela vous permet de créer de nouveaux événements basés sur l'événement original tout en préservant ses données.</p><p>Voici un exemple d'utilisation du filtre Ruby pour diviser un événement unique en plusieurs événements. L'entrée et la sortie sont les mêmes que dans l'exemple précédent.</p>filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    code =&gt; "
      items = event.get('[rss][channel][item]')
      if items.is_a?(Array)
        items.each do |item|
          new_event = event.clone
          new_event.set('title', item['title'])
          new_event.set('link', item['link'])
          new_event.set('description', item['description'])
          new_event_block.call new_event
        end
        event.cancel
      elsif items.is_a?(Hash)
        event.set('title', items['title'])
        event.set('link', items['link'])
        event.set('description', items['description'])
      end
    "
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}<h4>Utiliser un script Ruby externe</h4><p>Vous pouvez également utiliser un script Ruby externe pour diviser un événement unique en plusieurs événements.</p><p>Fichier de configuration :</p>filter {
  xml {
    source =&gt; "message"
    target =&gt; "rss"
    store_xml =&gt; true
    force_array =&gt; false
  }
  ruby {
    path =&gt; "path/to/ruby/split_event.rb"
  }
  mutate {
    remove_field =&gt; ["@timestamp", "@version", "sequence", "host", "event", "message", "rss", "items"]
  }
}<p>Le script Ruby doit être externalisé en tant que <code>split_event.rb</code>:</p>def filter(event)
  items = event.get('[rss][channel][item]')
  events = []
  if items.is_a?(Array)
    items.each do |item|
      new_event = event.clone
      new_event.set('title', item['title'])
      new_event.set('link', item['link'])
      new_event.set('description', item['description'])
      events &lt;&lt; new_event
    end
    return events
  elsif items.is_a?(Hash)
    event.set('title', items['title'])
    event.set('link', items['link'])
    event.set('description', items['description'])
    return [event]
  else
    return []
  end
end<p>N'oubliez pas que la méthode <code>filter</code> doit renvoyer un tableau d'événements. Vous pouvez renvoyer plusieurs événements en clonant un objet événement entrant et en l'ajoutant au tableau, ou vous pouvez renvoyer un seul événement sous la forme d'un tableau à un seul élément.</p>return events
# or
# return [event]<p>Cela vous permet de diviser un événement unique en plusieurs événements.</p><h3>Exécuter des commandes externes et analyser leurs résultats</h3><p>Le plugin Logstash exec input vous permet d'exécuter des commandes externes et leur sortie sera un événement de Logstash. La sortie de la commande sera stockée dans le champ <code>message</code> de l'événement.</p><p>Habituellement, la sortie des commandes système est lisible par l'homme, mais n'est pas structurée en JSON ou dans d'autres formats que Logstash peut facilement analyser. Pour ce faire, vous pouvez utiliser le filtre Ruby pour analyser la sortie et en extraire les informations.</p><p>Voici un exemple d'utilisation du plugin d'entrée <code>exec</code> pour exécuter la commande <code>ps -ef</code>, qui répertorie tous les processus en cours d'exécution sur un système de type Unix. La sortie sera analysée par le filtre Ruby afin d'extraire les informations pertinentes sur chaque processus.</p>input {
  exec {
    command =&gt; "ps -ef"
    interval =&gt; 60
  }
}

filter {
  ruby {
    code =&gt; '
      processes = []
      lines = event.get("message").split("\n")  
      lines.each_with_index do |line, index|
        # Skip header line and empty lines
        next if index == 0 || line.strip.empty?
        entry = nil
        
        # Use regex to match the ps -ef output format more flexibly
        # This pattern accounts for variable spacing and different time formats
        if line =~ /^\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\d:]+\.?\d*)\s+(.+)$/
          uid, pid, ppid, c, stime, tty, time, cmd = $1, $2, $3, $4, $5, $6, $7, $8
          
          entry = {
            "UID" =&gt; uid,
            "PID" =&gt; pid,
            "PPID" =&gt; ppid,
            "C" =&gt; c,
            "STIME" =&gt; stime,
            "TTY" =&gt; tty,
            "TIME" =&gt; time,
            "CMD" =&gt; cmd.strip
          }
        elsif line =~ /^\s*(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(.+)$/
          # Fallback pattern for lines that might not match the exact format
          # Split the remaining part more carefully
          uid, pid, ppid, c, remainder = $1, $2, $3, $4, $5
          
          # Split remainder into STIME, TTY, TIME, CMD
          parts = remainder.strip.split(/\s+/, 4)
          if parts.length &gt;= 4
            stime, tty, time, cmd = parts[0], parts[1], parts[2], parts[3]
            
            entry = {
              "UID" =&gt; uid,
              "PID" =&gt; pid,
              "PPID" =&gt; ppid,
              "C" =&gt; c,
              "STIME" =&gt; stime,
              "TTY" =&gt; tty,
              "TIME" =&gt; time,
              "CMD" =&gt; cmd
            }
          end
        end
        if entry &amp;&amp; entry["UID"] == "0"
          original_line = line.strip
          entry["original_line"] = original_line if original_line.length &gt; 0
          processes.push(entry)
        end
      end
      event.set("processes", processes)
      event.remove("message")
      event.remove("event")
    '
  }
}

output {
  stdout { codec =&gt; rubydebug }
}<p>Cet exemple utilise le plugin d'entrée <code>exec</code> pour exécuter la commande <code>ps -ef</code> toutes les 60 secondes. Le filtre Ruby traite la sortie, en extrayant les champs pertinents tels que UID, PID, PPID, l'utilisation du CPU (C), l'heure de démarrage (STIME), TTY, le temps total du CPU (TIME), et la commande (CMD) exécutée. Cela fonctionne bien dans mon environnement macOS, mais il se peut que vous deviez ajuster les motifs des expressions rationnelles pour qu'ils correspondent au format de sortie de la commande <code>ps -ef</code> sur votre système.</p><h3>Utiliser les bibliothèques intégrées</h3><p>Le plugin de filtrage Ruby vous permet d'utiliser des bibliothèques Ruby intégrées, qui peuvent s'avérer très utiles pour diverses tâches. Par exemple, vous pouvez utiliser la bibliothèque <code>json</code> pour analyser les chaînes JSON ou la bibliothèque <code>date</code> pour manipuler les dates.</p><p>Voici un exemple d'utilisation de la bibliothèque <code>json</code> pour analyser une chaîne JSON stockée dans un champ :</p>require 'json'

def filter(event)
  json_string = event.get('message')
  parsed_json = JSON.parse(json_string)
  event.set('parsed_json', parsed_json)
  return [event]
end<p>Pour éviter d'avoir besoin de la bibliothèque à chaque fois, vous devriez externaliser votre code Ruby afin d'utiliser l'instruction <code>require</code> au début de votre script de filtrage Ruby. Cela chargera la bibliothèque une fois et la rendra disponible pour une utilisation dans votre script.</p><p>Pour vérifier quelles sont les bibliothèques disponibles dans votre environnement, vous pouvez dresser la liste des bibliothèques intégrées en exécutant le code suivant dans le filtre Ruby :</p>Gem.loaded_specs.sort_by { |name, _| name }.each do |name, spec|
  puts "#{name}: #{spec.version}"
end<p><strong>Note : </strong>Les bibliothèques intégrées ne sont pas officiellement supportées par Logstash, et leur comportement peut changer ou elles peuvent ne pas être disponibles dans les versions futures. Utilisez-les à vos risques et périls.</p><h2>Conclusion</h2><p>Le filtre Logstash Ruby vous permet de personnaliser et d'étendre les capacités de vos pipelines Logstash. Dans ce billet, nous avons couvert les bases de l'utilisation du filtre Ruby et fourni des exemples d'utilisation avancée.</p><p>En tirant parti du filtre Ruby, vous pouvez effectuer des tâches de traitement de données complexes qui nécessitent une logique personnalisée ou des manipulations avancées. Que vous travailliez avec des structures de données imbriquées, que vous fractionniez des événements ou que vous analysiez et convertissiez du texte complexe/non structuré en JSON structuré, le filtre Ruby offre la flexibilité nécessaire pour répondre à vos besoins spécifiques.</p><p>Nous espérons que ce guide vous a apporté les connaissances et l'inspiration nécessaires pour explorer tout le potentiel du filtre Logstash Ruby. Bonne lecture !</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ruby-scripting-logstash</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ruby-scripting-logstash</guid>
    <category><![CDATA[Indexer des données]]></category>
    <category><![CDATA[Ruby]]></category>
    <dc:creator><![CDATA[Dai Sugimori]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt503d18396642e73e/6a17f62aaf47b68527cde121/b1bcd63c033ccbde102c20ba3085f165f9289a71-1600x1000.png" length="0" type="image/png"/>
    <pubDate>Tue, 24 Jun 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Affichage des champs dans un index Elasticsearch]]></title>
    <description><![CDATA[Exploration des techniques d'affichage des champs dans un index Elasticsearch.
]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous verrons comment afficher des champs dans un index Elasticsearch. Cela peut être utile pour comprendre la structure de vos données, identifier des champs spécifiques et résoudre des problèmes. Nous aborderons les sujets suivants :</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#1.-using-the--mapping-api-to-retrieve-field-information">Utilisation de l'</a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#1.-using-the--mapping-api-to-retrieve-field-information"><code>_mapping</code></a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#1.-using-the--mapping-api-to-retrieve-field-information"> API pour récupérer des informations sur les champs</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#2.-using-the--search-api-to-display-field-values">Utilisation de l'</a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#2.-using-the--search-api-to-display-field-values"><code>_search</code></a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#2.-using-the--search-api-to-display-field-values"> API pour afficher les valeurs des champs</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#3.-filtering-fields-using-the-fields-parameter">Filtrage des champs à l'aide du </a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#3.-filtering-fields-using-the-fields-parameter"><code>fields</code></a><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#3.-filtering-fields-using-the-fields-parameter"> paramètre</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index#4.-displaying-nested-fields">Affichage des champs imbriqués</a></p></li></ol><h2>1. Utilisation de l'API _mapping pour récupérer des informations sur les champs</h2><p>L'API <code>_mapping</code> vous permet de récupérer la définition du mappage pour un ou plusieurs <a href="https://opster.com/guides/elasticsearch/glossary/elasticsearch-index/">index.</a> Il s'agit d'informations sur les champs, leurs types de données et d'autres propriétés. Pour récupérer le mappage d'un index spécifique, utilisez la requête suivante :</p>GET /&lt;index_name&gt;/_mapping<p>Par exemple, si vous avez un index nommé <code>my_index</code>, vous pouvez récupérer son mapping avec la requête suivante :</p>GET /my_index/_mapping<p>La réponse comprendra la définition du mappage pour l'index, qui contient des informations sur les champs et leurs propriétés.</p><p>Il est également possible de récupérer la cartographie d'un champ spécifique. Cela peut s'avérer utile si votre cartographie est assez vaste et que vous souhaitez vous concentrer sur un domaine spécifique. Pour récupérer la correspondance d'un champ spécifique, utilisez la requête suivante :</p>GET /my_index/_mapping/field/my_field<p>Vous pouvez également récupérer les correspondances de plusieurs champs en séparant leurs noms par des virgules, comme dans la requête suivante :</p>GET /my_index/_mapping/field/my_field_1,my_field_2,my_field_3<h2>2. Utilisation de l'API _search pour afficher les valeurs des champs</h2><p>Pour afficher les valeurs des champs d'un index Elasticsearch, vous pouvez utiliser l'API <code>_search</code>. Par défaut, l'API <code>_search</code> renvoie le champ <code>_source</code>, qui contient le document JSON original qui a été indexé. Pour n'afficher que des champs spécifiques, vous pouvez utiliser le paramètre <code>_source</code> dans la requête de recherche.</p><p>Voici un exemple de demande de recherche qui renvoie les valeurs des champs <code>title</code> et <code>author</code> pour les documents de l'index <code>my_index</code>:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title", "author"]
}<p>Dans cet exemple, le paramètre <code>_source</code> spécifie les champs à renvoyer.</p><h2>3. Filtrer les champs à l'aide du paramètre fields</h2><p>Vous pouvez également utiliser le paramètre <code>fields</code> pour filtrer les champs renvoyés dans la réponse de recherche. Cela peut être utile si vous n'avez besoin que de champs spécifiques et que vous souhaitez réduire la taille de la réponse. Le paramètre <code>fields</code> accepte un tableau de noms de champs ou de caractères génériques.</p><p>Par exemple, pour obtenir uniquement les champs <code>title</code> et <code>author</code> pour les documents de l'index <code>my_index</code>, vous pouvez utiliser la requête de recherche suivante :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author"],
  "_source": false
}<p>Notez que le paramètre <code>_source</code> est fixé à false afin de ne pas renvoyer le document source.</p><p>Pour obtenir tous les champs dont le type de données est <code>text</code>, vous pouvez utiliser un motif joker comme celui-ci :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["*.text"],
  "_source": false
}<h2>4. Affichage des champs imbriqués</h2><p>Si votre index contient des champs imbriqués, vous pouvez utiliser la notation point pour spécifier le chemin du champ imbriqué dans le paramètre <code>fields</code>. Par exemple, si vous disposez d'un champ imbriqué nommé <code>address.city</code>, vous pouvez l'inclure dans la réponse de recherche comme suit :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author", "address.city"],
  "_source": false
}<p>Dans cet exemple, la réponse de la recherche comprendra les valeurs des champs <code>title</code>, <code>author</code> et <code>address.city</code>.</p><h2>Conclusion</h2><p>En conclusion, l'affichage des champs dans un index Elasticsearch peut être réalisé en utilisant l'API <code>_mapping</code> pour récupérer les informations sur les champs et l'API <code>_search</code> pour afficher les valeurs des champs. Vous pouvez filtrer les champs renvoyés dans la réponse de recherche à l'aide des paramètres <code>_source</code> ou <code>fields</code> et afficher les champs imbriqués à l'aide de la notation par points. Ces techniques peuvent vous aider à comprendre la structure de vos données, à identifier des champs spécifiques et à résoudre des problèmes.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/displaying-fields-in-an-elasticsearch-index</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Kofi Bartlett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3a1fcc771a2504e5/6a17f817abe0f23038dfebca/fa386d7bbaeab6855e62897ace8d7dca91a060b4-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 26 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Exclusion des champs Elasticsearch de l'indexation]]></title>
    <description><![CDATA[Apprenez comment configurer Elasticsearch pour exclure des champs, les principales raisons d'exclure des champs de l'indexation, et les bonnes pratiques à suivre.]]></description>
    <content:encoded><![CDATA[<p>Dans Elasticsearch, l'indexation fait référence au processus de stockage et d'organisation des données de manière à les rendre facilement consultables. Si l'indexation de tous les champs d'un document peut s'avérer utile dans certains cas, il peut arriver que vous souhaitiez exclure certains champs de l'indexation. Cela permet d'améliorer les performances, de réduire les coûts de stockage et de minimiser la taille globale de votre index Elasticsearch.</p><p>Dans cet article, nous examinerons les raisons d'exclure des champs de l'indexation, comment configurer Elasticsearch pour exclure des champs spécifiques et quelques bonnes pratiques à suivre pour ce faire.</p><h2>Raisons d'exclure des champs de l'indexation</h2><ol><li><p><strong>Performance : </strong>L'indexation de tous les champs d'un document peut augmenter le temps d'indexation et ralentir les performances de recherche. En excluant les champs qui ne sont pas nécessaires à la recherche ou à l'agrégation, vous pouvez améliorer les performances globales de votre cluster Elasticsearch.</p></li><li><p><strong>Stockage : </strong>L'indexation des champs consomme de l'espace de stockage. L'exclusion des champs qui ne sont pas nécessaires à la recherche ou à l'agrégation peut contribuer à réduire les besoins en stockage de votre cluster Elasticsearch.</p></li><li><p><strong>Taille de l'index : </strong>La taille d'un index Elasticsearch est directement liée au nombre de champs indexés. En excluant les champs inutiles, vous pouvez réduire la taille de votre index, ce qui permet d'accélérer les performances de recherche et d'indexation.</p></li></ol><h2>Configurer Elasticsearch pour exclure des champs</h2><p>Pour exclure un champ de l'indexation dans Elasticsearch, vous pouvez utiliser la propriété "index" dans le mappage du champ. En définissant la propriété "index" à "false", Elasticsearch n'indexera pas le champ, et il ne sera pas consultable ni disponible pour les agrégations.</p><p>Voici un exemple d'exclusion d'un champ de l'indexation à l'aide du mappage Elasticsearch :</p>PUT /my_index
{
  "mappings": {
    "properties": {
      "field_to_exclude": {
        "type": "text",
        "index": false
      }
    }
  }
}<p>Dans cet exemple, nous créons un nouvel index appelé "my_index" avec un seul champ appelé "field_to_exclude". En définissant la propriété "index" à "false", nous indiquons à Elasticsearch de ne pas indexer ce champ. Le champ reste cependant disponible dans le document source.</p><h2>Meilleures pratiques pour exclure des champs de l'indexation</h2><ol><li><p><strong>Analysez vos données : </strong>Avant d'exclure des champs de l'indexation, il est essentiel d'analyser vos données et de comprendre quels champs sont nécessaires à la recherche et à l'agrégation. Cela vous aidera à prendre des décisions éclairées sur les champs à exclure.</p></li><li><p><strong>Testez vos modifications : </strong>Lorsque vous excluez des champs de l'indexation, il est essentiel de tester vos modifications pour vous assurer que vos fonctionnalités de recherche et d'agrégation fonctionnent toujours comme prévu. Cela peut vous aider à éviter des problèmes inattendus ou des problèmes de performance.</p></li><li><p><strong>Contrôlez les performances :</strong> Après avoir exclu des champs de l'indexation, surveillez les performances de votre cluster Elasticsearch pour vous assurer que vos modifications ont eu l'effet escompté. Cela peut vous aider à identifier les optimisations supplémentaires qui pourraient être nécessaires.</p></li><li><p><strong>Utiliser le filtrage à la source :</strong> Si vous avez besoin de stocker un champ dans Elasticsearch mais que vous ne souhaitez pas qu'il soit consultable ou disponible pour les agrégations, envisagez d'utiliser le filtrage des sources. Cela vous permet de stocker le champ dans le champ _source mais de l'exclure de l'index.</p></li></ol><h2>Conclusion</h2><p>L'exclusion de champs de l'indexation dans Elasticsearch peut contribuer à améliorer les performances, à réduire les coûts de stockage et à minimiser la taille globale de votre index. En analysant soigneusement vos données et en comprenant quels champs sont nécessaires à la recherche et à l'agrégation, vous pouvez prendre des décisions éclairées sur les champs à exclure. Testez toujours vos modifications et surveillez les performances de votre cluster Elasticsearch pour vous assurer que vos optimisations ont l'effet escompté.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/excluding-elasticsearch-fields-from-indexing</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/excluding-elasticsearch-fields-from-indexing</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Kofi Bartlett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt399bcc5a2e55bfe0/6a1708b45091684557e1ba3c/3aa0b481994d2445ba979d3c79fff64c5ee6676a-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Modèles d'index dans Elasticsearch : Comment utiliser les modèles composables]]></title>
    <description><![CDATA[Découvrez comment créer des modèles d'index composables et de composants dans Elasticsearch pour garantir des mapping cohérents et automatiser la configuration de l'index.]]></description>
    <content:encoded><![CDATA[<p>Un index Elasticsearch peut être configuré par le biais de mappages, de paramètres et d'alias : </p><ul><li><p>Les définitions de mappage spécifient le schéma de données.</p></li><li><p>Les paramètres définissent la taille du groupe et les taux de rafraîchissement. </p></li><li><p>Les alias sont utilisés pour donner d'autres noms à l'index.</p></li></ul><p>Lorsque nous indexons un document pour la première fois ou que nous créons un index vide à l'aide de l'API Create Index, l'index est créé avec les paramètres par défaut, sans schéma de données et sans alias. Ces valeurs par défaut fonctionnent assez bien dans les environnements de développement et de test, mais il se peut que nous devions personnaliser nos indices pour les environnements de production.</p><p>L'utilisation des mappages et des paramètres par défaut en production peut entraîner des performances médiocres en matière d'indexation et de recherche. L'instanciation manuelle des indices est un processus fastidieux et chronophage. Recréer de tels index dans chaque environnement est particulièrement peu pratique si nous disposons d'un schéma de correspondance élaboré ainsi que de paramètres et d'alias personnalisés.</p><p>Heureusement, Elasticsearch met à notre disposition un outil permettant d'appliquer automatiquement une configuration prédéfinie lors de la création d'index sous la forme de  <em>modèles d' index.</em></p><h2>Modèles d'index</h2><p>Les modèles d'index nous permettent de créer des index avec une configuration définie par l'utilisateur. Lors de son instanciation, un index peut tirer la configuration de ces modèles, par exemple un nombre déterminé de shards et de réplicas ou des mappages de champs. Un modèle sera défini avec un modèle de nom et une certaine configuration. Si le nom de l'index correspond au modèle de dénomination du modèle, le nouvel index sera créé avec la configuration définie dans le modèle.</p><p>Elasticsearch a mis à jour sa fonctionnalité de modèle dans la version 7.8 avec des modèles composables. Cette nouvelle version permet de réutiliser beaucoup plus de modèles d'index, comme le montre cet article.</p><h3>Types de modèles d’index</h3><p>Les modèles d'index peuvent être classés en deux catégories :</p><ul><li><p><strong>Modèles d'index (ou modèles d'index composables)</strong>: Les modèles d'index composables peuvent exister seuls ou être composés d'un ou de plusieurs modèles de composants (voir la deuxième catégorie).</p></li><li><p><strong>Modèles de composants :</strong> Le modèle de composant est un modèle <em>réutilisable</em> qui définit la configuration requise. En général, le modèle de composant doit être associé à un modèle d'index. Chaque modèle de composant peut être associé à un ou plusieurs modèles d'index. </p></li></ul><p>Comme vous pouvez le voir dans l'image ci-dessous, les modèles d'index A et B partagent des modèles de composants (dans ce cas, un seul - le modèle 3) entre eux. Un modèle d'index peut être constitué d'un ou de plusieurs modèles de composants et chacun des modèles de composants peut être associé à un ou plusieurs modèles d'index. Les deux types de modèles peuvent exister seuls, mais les modèles de composants ne sont d'aucune utilité s'ils ne sont pas rattachés à un modèle d'index.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7fca132e0eb86c50/6a17f5b7ec0f8982a65a678c/96c0aac29d3992e54a79be34e14cf909e0ca2ea9-1202x556.png" alt="Modèles d'index dans Elasticsearch et leurs composants." /><p>L'idée générale est de développer un catalogue de modèles de composants qu'une organisation peut utiliser pour divers besoins (par exemple, en spécifiant les différents modèles de composants pour des environnements individuels) et de les attacher à divers index via les modèles d'index composables.</p><h2>Comment créer des modèles composables (index)</h2><p>Elasticsearch fournit un point de terminaison _index_template pour gérer les modèles d'index. L'utilisateur fournit tous les mappages, paramètres et alias nécessaires ainsi qu'un modèle de nom d'index dans ce modèle. Prenons l'exemple de la création d'un modèle pour une application de microservice, <em>customer-order-service</em>, qui est responsable de la logique de génération des commandes. </p><p>Supposons que nous ayons besoin de créer un modèle pour les commandes des clients, représenté par un motif comportant des caractères génériques : *commandes. Ce modèle est censé contenir certains mappages et paramètres, tels que le champ order_date, ainsi que les numéros de shards et de réplicas.</p><p>Tout index qui est associé à ce modèle lors de sa création hérite des configurations définies dans ce modèle. Par exemple, un index black_friday_orders aura le champ order_date, les shards seront fixés à 5 et les réplicas à 2. En outre, <em>tous les</em> index créés à partir de ce modèle héritent également d'un nom d'<a href="https://opster.com/guides/elasticsearch/glossary/elasticsearch-alias/">alias</a> unique ! Créons ce modèle orders_template avec un modèle d'index défini comme *orders et avec un schéma de correspondance consistant en un seul champ oder_date avec un format de date prédéfini dd-MM-yyyy. Le code ci-dessous montre comment créer ce modèle d'index.</p>PUT _index_template/orders_template
{
  "index_patterns": ["*orders"],
  "priority": 300,
  "template": {
    "mappings": {
      "properties": {
        "order_date": {
          "type": "date",
          "format":"dd-MM-yyyy"
        }
      }
    },
    "settings":{
      "number_of_shards":5,
      "number_of_replicas":2
    },
    "aliases":{
      "all_orders":{}
    }
  }
}<p>Lorsque vous exécutez cette requête dans les DevTools de Kibana, le modèle est créé avec le modèle d'index *orders ainsi que le mappage prédéfini, les paramètres et un alias. L'index_patterns est un tableau de motifs de correspondance ; tout index correspondant à ce motif sera dérivé de la configuration du modèle. Vous pouvez exécuter ce qui suit pour récupérer le modèle persisté qui devrait réitérer ce que nous avons fait :</p>GET _index_template/orders_template <p>Il existe également une priorité, un nombre positif, définie lors de la création de l'attribut de modèle défini sur le modèle : chaque modèle est défini avec une priorité de sorte que toute modification conflictuelle provenant de différents modèles sera résolue en utilisant cette valeur, la priorité étant donnée à la valeur de priorité la plus élevée. Nous nous pencherons plus en détail sur la priorité des modèles ci-dessous.</p><h2>Création d'un index avec le modèle</h2><p>Maintenant que nous disposons d'un modèle - un schéma directeur pour la création d'index - l'étape suivante consiste à créer un index. Lorsque le nom de l'index correspond au modèle donné, les configurations modèles sont appliquées automatiquement. Pour le prouver, comme le montre le code ci-dessous, créons un tout nouvel index nommé : blackfriday_orders :</p>PUT blackfriday_orders<p>Comme le nom de l'index (blackfriday_orders) correspond au modèle de dénomination défini dans le modèle (c'est-à-dire *orders), l'index doit obtenir toute la configuration dérivée du modèle. Récupérons cet index fraîchement créé et vérifions si c'est bien le cas en exécutant le code suivant :</p>GET blackfriday_orders<p>Il doit revenir :</p>{
  "blackfriday_orders" : {
    "aliases" : {
      "all_orders" : { }
    },
    "mappings" : {
      "properties" : {
        "order_date" : {
          "type" : "date",
          "format" : "dd-MM-yyyy"
        }
      }
    },
    "settings" : {
      "index" : {
         ...
        "number_of_shards" : "5",
        "number_of_replicas" : "2"
      }
    }
  }
}<p>Comme l'indique la réponse, la configuration de blackfriday_orders a été héritée du modèle. Nous pouvons essayer diverses combinaisons d'indices qui hériteront avec succès de la configuration modèle :</p>PUT blackfriday_orders
PUT americaorders
PUT cancelled--orders
PUT undefined101orders<p>Cependant, les indices suivants n'hériteront pas de la configuration car leur nom ne correspond pas au modèle :</p>PUT blackfriday_orders2
PUT open_orders_
PUT allorders_total<p>Il est important de se rappeler que tous les indices dérivés d'un modèle ont le même alias - all_orders - dans ce cas. L'avantage d'un tel alias est qu'il permet d'effectuer des requêtes sur cet alias unique plutôt que sur plusieurs indices.</p>GET blackfriday_orders,americaorders,undefined101orders/_search
GET all_orders/_search 
{
  "query": {
    "range": {
      "order_date": {
        "gte": "01-12-2021",
        "lte": "31-12-2021"
      }
    }
  }
}<p>Si nous créons un modèle pour les *commandes, tout index correspondant est censé adopter la configuration du modèle. En général, sciemment ou non, les équipes peuvent créer quelques modèles supplémentaires pour diverses raisons. Cela signifie que le nom de l'index peut parfois correspondre à deux modèles différents ! Elasticsearch doit décider quelles configurations de ces modèles il doit appliquer. Heureusement, ce dilemme peut être résolu en utilisant le modèle de priorité.</p><h2>Comment créer des modèles de composants</h2><p>Nous avons appris à connaître les modèles d'index dans la première partie de cet article. La création de modèles avec la configuration intégrée présente quelques inconvénients, notamment le fait que la configuration n'est pas exportable pour d'autres modèles. Si nous souhaitons disposer d'une configuration similaire, par exemple pour les modèles liés aux clients (*customers), nous devrons peut-être recréer l'ensemble du modèle. Cela signifie que nous pouvons en créer des dizaines dans une organisation typique (et vous pouvez en avoir quelques autres en fonction de l'environnement).</p><p>Comme nous cherchons toujours à faciliter la réutilisation, Elasticsearch a redessiné les modèles en gardant à l'esprit la réutilisation. Les modèles de composants répondent à cette exigence. Si vous venez d'un milieu DevOps, il est fort probable que vous ayez besoin de créer des indices avec une configuration prédéfinie pour chacun des environnements. Plutôt que d'appliquer manuellement chacune de ces configurations, vous pouvez créer un modèle de composant pour chacun des environnements.</p><p>Un modèle de composant n'est rien d'autre qu'un bloc réutilisable de configurations que nous pouvons utiliser pour créer d'autres modèles d'index. Notez que les modèles de composants n'ont aucune valeur s'ils ne sont pas associés à des modèles d'index. Ils sont exposés via un point de terminaison _component_template. Voyons comment tout cela s'articule.</p><h3>Paramètres dans un modèle d’index</h3><p>Extrayons les paramètres que nous avons définis dans notre modèle d'index plus tôt et créons un modèle de composant à partir de celui-ci. Le modèle settings_component_template est censé comporter cinq shards primaires avec deux réplicas par shard primaire. La première étape, comme le montre le code ci-dessous, consiste à déclarer et à exécuter un modèle de composant avec cette configuration.</p>PUT _component_template/settings_component_template
{
  "template":{
    "settings":{
      "number_of_shards":5,
      "number_of_replicas":2
    }
  }
}<p>Comme le montre le code ci-dessus, nous utilisons le point de terminaison _component_template pour créer un modèle de composant. Le corps de la demande contient les informations relatives au modèle dans un objet modèle. Le modèle settings_component_template peut désormais être utilisé ailleurs dans les modèles d'index. Une différence notable est que ce modèle ne définit aucun modèle d'index ; il s'agit simplement d'un bloc de code qui configure certaines propriétés pour nous.</p><h3>Modèle de correspondance</h3><p>De la même manière, créons un autre modèle. Cette fois, nous allons extraire le schéma de correspondance que nous avons défini précédemment dans les modèles d'index autonomes. Le code ci-dessous illustre le script :</p>PUT _component_template/mappings_component_template
{
  "template": {
    "mappings": {
      "properties": {
        "order_date": {
          "type": "date",
          "format":"dd-MM-yyyy"
        }
      }
    }
  }
}<h3>Modèle d'alias</h3><p>Dans le même ordre d'idées, nous pouvons également avoir un modèle de composant avec les alias - deux alias (all_orders et sales_orders) :</p>PUT _component_template/aliases_component_template
{
  "template": {
    "aliases": {
      "all_orders": {},
      "sales_orders":{}
    }
  }
}<h3>Modèle d'index composable</h3><p>Maintenant que nous disposons de ces trois modèles de composants, la prochaine étape consiste à les utiliser. Nous pouvons le faire en laissant un modèle d'index pour, par exemple, christmas_orders, l'utiliser :</p>PUT _index_template/composed_orders_template
{
  "index_patterns": [
    "*orders"
  ],
  "priority": 500,
  "composed_of": [
    "settings_component_template",
    "mappings_component_template",
    "aliases_component_template"
  ]
}<p>La balise composed_of est une collection de tous les modèles de composants qui constituent ce modèle. Dans ce cas, nous choisissons les paramètres, les mappings et les alias des modèles de composants. Nous avons également relevé le niveau de priorité afin que ce modèle l'emporte sur tous les autres. Une fois le modèle prêt, tous les indices correspondant au motif *orders hériteront de la configuration de ces trois modèles de composants.</p><p>Cela dit, si nous souhaitons créer un nouveau modèle, par exemple clients, avec un seul des modèles existants (settings_component_template) et un modèle alias nouvellement créé (aliases_component_template - voir ci-dessous), nous pouvons le faire à l'aide de :</p>PUT _component_template/aliases_component_template2
{
  "template": {
    "aliases": {
      "all_customers": {}
    }
  }
}<p>Le modèle d'index se présente comme suit :</p>PUT _index_template/composed_customers_template
{
  "index_patterns": [
    "*customers*"
  ],
  "priority": 200,
  "composed_of": [
    "settings_component_template",
    "aliases_component_template2"
  ]
}<p>Avez-vous vu que le modèle settings_component_template a été (ré)utilisé dans deux modèles différents ? C'est la force des modèles de composants.</p><h2>Priorité du modèle d’index</h2><p>Il est possible que les développeurs créent plusieurs modèles d'index sans tenir compte du stock existant. Il est important de définir une priorité pour chacun de ces modèles afin que celui qui a la priorité la plus élevée soit utilisé. Par exemple, le modèle my_orders_template_1 remplace le modèle my_orders_template_2 dans l'extrait de code suivant :</p>PUT _index_template/my_orders_template_1
{
  "index_patterns": ["*orders"],
  "priority": 1000,
  "template": { ... }
}
PUT _index_template/my_orders_template2
{
  "index_patterns": ["*orders"],
  "priority": 300,
  "template": { ... }
}<p>Lorsque plusieurs modèles correspondent aux index créés, Elasticsearch applique toutes les configurations de tous les modèles correspondants, mais remplace tout ce qui a une priorité plus élevée.</p><h2>Préséance des modèles</h2><p>Enfin, vous vous interrogez peut-être sur la préséance des modèles : la configuration définie dans le modèle de composant est-elle prioritaire par rapport à celle définie dans le modèle d'index principal lui-même ? Ou l'inverse ? Il y a des règles à respecter :</p><ul><li><p>Un index créé avec des configurations explicites a la priorité sur tout le reste - cela signifie que si vous créez un index avec des configurations explicites, ne vous attendez pas à ce qu'elles soient remplacées par les modèles.</p></li><li><p>Les anciens modèles (modèles créés avant la version 7.8) ont une priorité inférieure à celle des modèles composables.</p></li></ul><h2>Résumé</h2><ul><li><p>Un index contient des mappings, des paramètres et des alias : les mappings définissent le schéma des champs, les paramètres définissent les paramètres de l'index tels que le nombre de shards et de réplicas, et les alias donnent des noms alternatifs à l'index.</p></li><li><p>Les modèles permettent de créer des indices avec des configurations prédéfinies. Le fait de nommer un index avec un nom qui correspond au modèle d'index défini dans un modèle spécifique configurera automatiquement cet index conformément au modèle.</p></li><li><p>Elasticsearch a introduit les modèles d'index composables dans la version 7.8. Les modèles d'index composables permettent la modularité et le changement de version des modèles.</p></li><li><p>Les modèles composables sont constitués d'au moins un modèle de composant.</p></li><li><p>Un modèle d'index peut également avoir sa propre configuration.</p></li><li><p>Un modèle de composant est un modèle réutilisable avec une configuration prédéfinie, tout comme un modèle d'index composable.</p></li><li><p>Toutefois, les modèles de composants sont censés faire partie d'un modèle d'index ; ils sont inutiles s'ils ne sont pas "composés" dans un modèle d'index.</p></li><li><p>Les modèles de composants n'ont pas de modèle d'index défini, ce qui est une autre raison pour laquelle ils sont "censés" faire partie d'un modèle d'index.</p></li><li><p>Chaque modèle a une priorité - un nombre positif. Plus le nombre est élevé, plus l'application du modèle est prioritaire.</p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/index-composable-templates</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/index-composable-templates</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Kofi Bartlett]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt98737a72caa74fe4/6a17f5b84b055d278d43236a/510750708df50bf79463586a1bbf35bf94acfa30-1200x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 02 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Airbyte ?]]></title>
    <description><![CDATA[Utilisation d'Airbyte pour ingérer des données dans Elasticsearch. Nous aborderons les conditions préalables, la configuration d'Airbyte et l'intégration étape par étape.]]></description>
    <content:encoded><![CDATA[<p>Airbyte est un outil d'intégration de données qui vous permet de déplacer des informations de différentes sources vers différentes destinations de manière automatisée et évolutive. Il vous permet d'extraire des données à partir d'API, de bases de données et d'autres systèmes et de les charger dans des plateformes telles qu'Elasticsearch, qui offre des fonctions de recherche avancée et d'analyse efficace.</p><p>Dans cet article, nous expliquerons comment configurer Airbyte pour ingérer des données dans Elasticsearch, en abordant les concepts clés, les conditions préalables et l'intégration étape par étape.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt99eabff95c587c00/6a17e300e8fbce2d303a18a9/ea7af907dfd4c0b7e8673164467ee236623282d2-1360x802.png" alt="Configurer Airbyte pour ingérer des données dans Elasticsearch" /><h2>Concepts fondamentaux de l'airbyte</h2><p>L'utilisation d'Airbyte repose sur plusieurs concepts essentiels. Nous en présentons ci-dessous les principales :</p><ul><li><p>Sources : Définit l'origine des données qui seront extraites.</p></li><li><p>Destinations : Définit l'endroit où les données seront envoyées et stockées.</p></li><li><p>Connexions : Configure la relation entre la source et la destination, y compris la fréquence de synchronisation.</p></li></ul><h2>Intégration d'Airbyte avec Elasticsearch</h2><p>Dans cette démonstration, nous allons réaliser une intégration où les données stockées dans un bucket S3 seront migrées vers un index Elasticsearch. Nous allons montrer comment configurer la source (S3) et la destination (Elasticsearch) dans Airbyte.</p><h3>Produits requis</h3><p>Pour suivre cette démonstration, les conditions suivantes doivent être remplies :</p><ol><li><p>Créez un godet dans AWS, où les fichiers JSON contenant les données seront stockés.</p></li><li><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart">Installez Airbyte localement</a> à l'aide de Docker.</p></li><li><p>Créer un cluster Elasticsearch dans Elastic Cloud pour stocker les données ingérées.</p></li></ol><p>Nous détaillons ci-dessous chacune de ces étapes.</p><h4>Installation d'Airbyte</h4><p>Airbyte peut être exécuté localement à l'aide de Docker ou dans le nuage, où des coûts sont associés à l'utilisation. Pour cette démonstration, nous utiliserons la version locale avec Docker.</p><p>L'installation peut prendre quelques minutes. Après avoir suivi les instructions d'installation, Airbyte sera disponible à l'adresse suivante : http://localhost:8000.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f9149be887b5500/6a17e302abe0f2b1c6dfe956/66147b5121413ad9baecb10c6886288e917f7c09-1600x1102.png" alt="Installation d'Airbyte" /><p></p><p>Après s'être connecté, nous pouvons commencer à configurer l'intégration.</p><h4>Création du seau</h4><p>Dans cette étape, vous aurez besoin d'un compte AWS pour créer un seau S3. En outre, il est essentiel de définir les autorisations correctes en créant une politique et un utilisateur IAM pour permettre l'accès au seau.</p><p>Dans le seau, nous téléchargerons des fichiers JSON contenant différents enregistrements de journaux, qui seront ensuite migrés vers Elasticsearch. Les fichiers journaux ont ce contenu :</p>{
   "timestamp": "2025-02-15T14:00:12Z",
   "level": "INFO",
   "service": "data_pipeline",
   "message": "Pipeline execution started",
   "details": {
       "pipeline_id": "abc123",
       "source": "MySQL",
       "destination": "Elasticsearch"
   }
}<p>Vous trouverez ci-dessous les fichiers chargés dans le seau :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbf769c5e9bdb5dfe/6a17e3043e9e45a360ba13f7/f3e7f5889002e3a804121a880d97f1d93044e2f7-1600x680.png" alt="Fichiers chargés dans le seau en Airbyte" /><h4>Configuration de l'Elastic Cloud</h4><p>Pour faciliter la démonstration, nous utiliserons Elastic Cloud. Si vous n'avez pas encore de compte, vous pouvez créer un compte d'essai gratuit ici : <a href="https://cloud.elastic.co/registration">Enregistrement Elastic Cloud</a>.</p><p>Après avoir configuré le déploiement dans Elastic Cloud, vous devrez obtenir :</p><ul><li><p>L'URL du serveur Elasticsearch.</p></li><li><p>Un utilisateur pour accéder à Elasticsearch.</p></li></ul><p>Pour obtenir l'URL, allez sur Deployments &gt; My deployment, dans application, trouvez Elasticsearch et cliquez sur 'Copy endpoint'.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltddfaaf863168e2bb/6a17e305faa913e29793c7e4/2e38c0bfb2cea83d9ef90dba0e673559fe358199-1368x1056.png" alt="Configuration de l'Elastic Cloud" /><p>Pour créer l'utilisateur, suivez les étapes ci-dessous :</p><ol><li><p>Accès à Kibana &gt; Gestion de la pile &gt; Utilisateurs.</p></li><li><p>Créer un nouvel utilisateur avec le rôle de superutilisateur.</p></li><li><p>Remplissez les champs pour créer l'utilisateur.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca15b0d3084f4c67/6a17e3073e9e4507e2ba13fb/54d098805087a2d60772475cbb31784083a38c25-1600x1026.png" alt="Création d'utilisateurs dans Elastic Cloud" /><p>Maintenant que tout est en place, nous pouvons commencer à configurer les connecteurs dans Airbyte.</p><h3>Configuration du connecteur source</h3><p>Dans cette étape, nous allons créer le connecteur source pour S3. Pour ce faire, nous accédons à l'interface Airbyte et sélectionnons l'option Source dans le menu. Ensuite, nous rechercherons le connecteur S3. Nous détaillons ci-dessous les étapes nécessaires à la configuration du connecteur :</p><ol><li><p>Accédez à Airbyte et allez dans le menu Sources.</p></li><li><p>Rechercher et sélectionner le connecteur S3.</p></li><li><p>Configurez les paramètres suivants :</p><ol><li><p>Source Name (Nom de la source) : Définir un nom pour la source de données.</p></li><li><p>Méthode de livraison : Sélectionnez Replicate Records (recommandé pour les données structurées).</p></li><li><p>Format des données : Choisissez le format JSON.</p></li><li><p>Stream Name (Nom du flux) : Définir le nom de l'index dans Elasticsearch.</p></li><li><p>Bucket Name : Saisissez le nom du réservoir dans AWS.</p></li><li><p>Clé d'accès AWS et clé secrète AWS : Saisissez les informations d'accès.</p></li></ol></li></ol><p>Cliquez sur Set up source et attendez la validation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdca1fb8d8f5d034f/6a17e30963baff75bc741bb2/f83566ab5ebad07ad9fd61dc20353ca5a95c8c92-1600x1099.png" alt="Attendre la validation pour l'ingestion des données Airbyte et Elasticsearch" /><h3>Connecteur de destination de la configuration</h3><p>Dans cette étape, nous allons configurer le connecteur de destination, qui sera Elasticsearch. Pour ce faire, nous accédons au menu et sélectionnons l'option Destination. Ensuite, nous rechercherons Elasticsearch et cliquerons sur le résultat obtenu. Nous allons maintenant procéder à la configuration de cette connexion :</p><ol><li><p>Accédez à Airbyte et allez dans le menu Destinations.</p></li><li><p>Recherchez et sélectionnez le connecteur Elasticsearch.</p></li><li><p>Configurez les paramètres suivants :</p><ol><li><p>Méthode d'authentification : Choisissez Nom d'utilisateur/Mot de passe.</p></li><li><p>Nom d'utilisateur et mot de passe : utilisez les informations d'identification créées dans Kibana.</p></li><li><p>Server Endpoint : Collez l'URL copiée depuis Elastic Cloud.</p></li></ol></li></ol><p>Cliquez sur <strong>Configurer la destination</strong> et attendez la validation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72056179d048e027/6a17e30b033c8d5d9d6bb115/f9246b54cc77e0589c0bf658ffc274fd28f766d5-1600x941.png" alt="Créer une destination dans Elastic Cloud pour l'ingestion de données Airbyte" /><h3>Création de la connexion source et de la connexion destination</h3><p>Une fois la source et la destination créées, la connexion entre elles sera créée, achevant ainsi la création de l'intégration. </p><p>Vous trouverez ci-dessous les instructions pour créer la connexion :</p><p>1. Dans le menu, allez dans Connexions et cliquez sur Créer une première connexion.</p><p>2. Dans l'écran suivant, vous pouvez sélectionner une source existante ou en créer une nouvelle. Comme nous avons déjà créé une source, nous allons sélectionner la source S3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7f1e01215a7a328/6a17e30c63baff53d7741bb6/14937ccb2686bbde7cb99ffe7e13f7f4e35d7a31-1600x393.png" alt="Sélectionner une source existante ou en créer une nouvelle dans Airbyte" /><p>3. L'étape suivante consiste à sélectionner la destination. Comme nous avons déjà créé le connecteur Elasticsearch, il sera sélectionné pour finaliser la configuration.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltece5c720f28eee00/6a17e30d505ac3dc68ad8aa3/d10962bc175f9ce0b2745ea913d739d3c40ba3b6-1600x431.png" alt="Sélectionner la destination dans Airbyte" /><p>Dans l'étape suivante, il sera nécessaire de définir le mode de synchronisation et le schéma qui sera utilisé. Étant donné que seul le schéma d'enregistrement a été créé, il s'agit de la seule option disponible pour la sélection.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7cbcccad9cfd5a8d/6a17e30f414c64d32d9450e9/d5d3a2e20038d17ef701822fe7ccc38d6e175c50-1600x805.png" alt="Définir le mode de synchronisation dans Airbyte" /><p>4. Nous allons passer à l'étape de la configuration de la connexion. Ici, nous pouvons définir le nom de la connexion et la fréquence d'exécution de l'intégration. La fréquence peut être configurée de trois manières :</p><ul><li><p><strong>Cron</strong>: Exécute les synchronisations en fonction de l'expression cron définie par l'utilisateur (par exemple 0 0 15 * * ?, à 15:00 tous les jours) ;</p></li><li><p><strong>Planifié</strong>: Exécute les synchronisations à l'intervalle de temps spécifié (par ex. toutes les 24 heures, toutes les 2 heures) ;</p></li><li><p><strong>Manuel</strong>: Exécuter les synchronisations manuellement.</p></li></ul><p>Pour cette démonstration, nous sélectionnerons l'option Manuel.</p><p>Enfin, en cliquant sur <strong>Établir la connexion</strong>, la connexion entre la source et la destination sera établie.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4f5fc0e51035b733/6a17e311af47b67ac8cddeff/1a0470f6dff341cb90e6ecfd8ae87a7d2243cbf4-1600x626.png" alt="Cliquer sur Établir la connexion dans Airbyte" /><h3>Synchronisation des données de S3 vers Elasticsearch</h3><p>Lorsque vous revenez à l'écran Connexions, vous pouvez voir la connexion qui a été créée. Pour exécuter le processus, il suffit de cliquer sur Sync. À partir de ce moment, la migration des données de S3 vers Elasticsearch commencera.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b0ad7a7446f9d58/6a17e3121d1b83b4c593e3c3/c1ce54b129eafb2533b638e4df2b96f3a266ad62-1600x347.png" alt="Synchronisation des données de S3 vers Elasticsearch sur Airbyte" /><p>Si tout se passe bien, vous obtiendrez l'état de synchronisation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857cdad5bd7fe03f/6a17e313be608646e00046b9/6fe9d5826787066bd8bf0f5e17905df9f8d698e6-1600x361.png" alt="Synchronisation des statuts de S3 vers Elasticsearch dans Airbyte" /><h3>Visualisation des données dans Kibana</h3><p>Nous allons maintenant aller dans Kibana pour analyser les données et vérifier si elles ont été indexées correctement. Dans la section Kibana Discovery, nous allons créer une vue de données appelée logs. Ainsi, nous pourrons explorer les données existant uniquement dans l'index des journaux, qui a été créé après la synchronisation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bc137f7c04e50ee/6a17e3151480094f2eb486cf/6b6909647ac3187d0fee477cfd732741314f82cf-1600x566.png" alt="Visualiser les données dans Kibana : Airbyte et Elastic" /><p>Nous pouvons maintenant visualiser les données indexées et les analyser. De cette manière, nous avons validé l'ensemble du flux de migration en utilisant Airbyte, où nous avons chargé les données présentes dans le seau et les avons indexées dans Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8c0a36a83ee4bb1/6a17e317b1e1135ea679f20e/ca8e9b3d7f7112291af58acf514f4573b44037e8-1600x806.png" alt="Airbyte et Elastic : visualisez les données indexées et effectuez des analyses sur celles-ci dans Kibana" /><h2>Conclusion : Airbyte &amp; Intégration d'Elasticsearch</h2><p>Airbyte s'est avéré être un outil efficace pour l'intégration des données, nous permettant de connecter plusieurs sources et destinations de manière automatisée. Dans ce tutoriel, nous avons montré comment ingérer des données d'un bucket S3 vers un index Elasticsearch, en mettant en évidence les principales étapes du processus.</p><p>Cette approche facilite l'ingestion de grands volumes de données et permet des analyses au sein d'Elasticsearch, telles que des recherches complexes, des agrégations et des visualisations de données.</p><h2>Références</h2><p><strong>Démarrage rapide Airbyte :</strong></p><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart#part-1-install-abctl">https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart#part-1-install-abctl</a></p><p><strong>Concepts de base :</strong></p><p><a href="https://docs.airbyte.com/using-airbyte/core-concepts/">https://docs.airbyte.com/using-airbyte/core-concepts/</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/airbyte-elasticsearch-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/airbyte-elasticsearch-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5defe5e12935b233/6a17e318505ac3ed7fad8aa7/dce2bad9949006163af95ed05b5a1eacf5393dc7-1200x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 14 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via LlamaIndex]]></title>
    <description><![CDATA[Une étape par étape sur la façon d'ingérer des données et de faire des recherches en utilisant RAG avec LlamaIndex.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous allons mettre en place un moteur de recherche pour les FAQ en utilisant LlamaIndex pour indexer les données. Elasticsearch servira de base de données vectorielle, permettant une recherche vectorielle, tandis que RAG (Retrieval-Augmented Generation) enrichira le contexte, fournissant des réponses plus précises.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5895fbc057ffc1b/6a17f4cf3e9e45288bba15ef/7ac65a686bdd76c145e903f5c3110c62875a525f-972x501.png" alt="LlamaIndex &amp; Elasticsearch : Ingestion de documents et construction d'une recherche de FAQ" /><h2>Qu'est-ce que le LlamaIndex ?</h2><p>LlamaIndex est un cadre qui facilite la création d'agents et de flux de travail alimentés par de grands modèles linguistiques (LLM) pour interagir avec des données spécifiques ou privées. Il permet l'intégration de données provenant de diverses sources (API, PDF, bases de données) avec les LLM, permettant des tâches telles que la recherche, l'extraction d'informations et la génération de réponses contextualisées.</p><p><strong>Concepts clés :</strong></p><ul><li><p>Agents : Assistants intelligents qui utilisent des LLM pour effectuer des tâches, allant de simples réponses à des actions complexes.</p></li><li><p>Flux de travail : Processus en plusieurs étapes qui combinent des agents, des connecteurs de données et des outils pour des tâches avancées.</p></li><li><p>Augmentation du contexte : Une technique qui enrichit le LLM avec des données externes, en surmontant ses limites de formation.</p></li></ul><p>Intégration de<strong>LlamaIndex</strong> <strong>avec Elasticsearch :</strong></p><p>Elasticsearch peut être utilisé de différentes manières avec LlamaIndex :</p><ul><li><p>Source de données : Utilisez le lecteur Elasticsearch pour extraire les documents.</p></li><li><p>Modèle d'encastrement : Encoder les données en vecteurs pour les recherches sémantiques.</p></li><li><p>Stockage vectoriel : Utilisez Elasticsearch comme référentiel pour la recherche de documents vectorisés.</p></li><li><p>Stockage avancé : Configurez des structures telles que des résumés de documents ou des graphes de connaissances.</p></li></ul><h2>Utiliser LlamaIndex et Elasticsearch pour construire une recherche de FAQ </h2><h3>Préparation des données</h3><p>Nous utiliserons la <a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">FAQ du service Elasticsearch</a> comme exemple. Chaque question a été extraite du site web et enregistrée dans un fichier texte individuel. Vous pouvez utiliser n'importe quelle approche pour organiser les données ; dans cet exemple, nous avons choisi d'enregistrer les fichiers localement.</p><p>Exemple de fichier :</p>File Name: what-is-elasticsearch-service.txt
Content: Elasticsearch Service is hosted and managed Elasticsearch and Kibana brought to you by the creators of Elasticsearch. Elasticsearch Service is part of Elastic Cloud and ships with features that you can only get from the company behind Elasticsearch, Kibana, Beats, and Logstash. Elasticsearch is a full text search engine that suits a range of uses, from search on websites to big data analytics and more.<p>Après avoir enregistré toutes les questions, le répertoire ressemblera à ceci :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt43467eb9c5579103/6a17f4d02f4a5cc60bfa8a62/1f367d57f2e650334671a2c03156ef4412c0c615-962x704.png" alt="" /><h3>Installation des dépendances</h3><p>Nous allons mettre en œuvre l'ingestion et la recherche en utilisant le langage Python, la version que j'ai utilisée étant la 3.9. Comme prérequis, il sera nécessaire d'installer les dépendances suivantes :</p>llama-index-vector-stores-elasticsearch
llama-index
openai<p>Elasticsearch et Kibana seront créés avec Docker, configurés via docker-compose.yml pour exécuter la version 8.16.2. Cela facilite la création de l'environnement local.</p>version: '3.8'
services:

 elasticsearch:
   image: docker.elastic.co/elasticsearch/elasticsearch:8.16.2
   container_name: elasticsearch-8.16.2
   environment:
     - node.name=elasticsearch
     - xpack.security.enabled=false
     - discovery.type=single-node
     - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
   ports:
     - 9200:9200
   networks:
     - shared_network

 kibana:
   image: docker.elastic.co/kibana/kibana:8.16.2
   container_name: kibana-8.16.2
   restart: always
   environment:
     - ELASTICSEARCH_URL=http://elasticsearch:9200
   ports:
     - 5601:5601
   depends_on:
     - elasticsearch
   networks:
     - shared_network

networks:
 shared_network:<h3>L'ingestion de documents à l'aide de LlamaIndex</h3><p>Les documents seront indexés dans Elasticsearch à l'aide de LlamaIndex. Tout d'abord, nous chargeons les fichiers avec <strong>SimpleDirectoryReader</strong>, qui permet de charger des fichiers à partir d'un répertoire local. Après avoir chargé les documents, nous les indexons à l'aide du <strong>VectorStoreIndex</strong>.</p>documents = SimpleDirectoryReader("./faq").load_data()

storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)<p>Les magasins de vecteurs de LlamaIndex sont responsables du stockage et de la gestion des incorporations de documents. LlamaIndex supporte différents types de Vector Stores, et dans ce cas, nous utiliserons Elasticsearch. Dans le StorageContext, nous configurons l'instance Elasticsearch. Le contexte étant local, aucun paramètre supplémentaire n'a été requis. Pour les configurations dans d'autres environnements, se référer à la documentation pour vérifier les paramètres nécessaires : <a href="https://docs.llamaindex.ai/en/stable/examples/vector_stores/ElasticsearchIndexDemo/#configuring-elasticsearchstore">ElasticsearchStore Configuration</a>.</p><p>Par défaut, LlamaIndex utilise le modèle OpenAI <strong>text-embedding-ada-002</strong> pour générer des embeddings. Toutefois, dans cet exemple, nous utiliserons le modèle <strong>text-embedding-3-small</strong>. Il est important de noter qu'une clé API OpenAI sera nécessaire pour utiliser le modèle.</p><p>Vous trouverez ci-dessous le code complet pour l'ingestion de documents.</p>import openai
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.vector_stores.elasticsearch import ElasticsearchStore

openai.api_key = os.environ["OPENAI_API_KEY"]

es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200"
)

def format_title(filename):
   filename_without_ext = filename.replace('.txt', '')
   text_with_spaces = filename_without_ext.replace('-', ' ')
   formatted_text = text_with_spaces.title()

   return formatted_text


embed_model = OpenAIEmbedding(model="text-embedding-3-small")

documents = SimpleDirectoryReader("./faq").load_data()

for doc in documents:
   doc.metadata['title'] = format_title(doc.metadata['file_name'])

storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)<p>Après l'exécution, les documents seront indexés dans l'index <strong>faq</strong> comme indiqué ci-dessous :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt391ae1bfc1daefbf/6a17f4d22f4a5c9887fa8a66/d59b85ed1f57bf80e84d6cb0d6d722a2d12ae4c0-1600x745.png" alt="" /><h3>Recherche avec RAG</h3><p>Pour effectuer des recherches, nous configurons le client <strong>ElasticsearchStore</strong>, en définissant les champs <strong>index_name</strong> et <strong>es_url</strong> avec l'URL d'Elasticsearch. Dans <strong>retrieval_strategy</strong>, nous avons défini la <strong>stratégie AsyncDenseVectorStrategy</strong> pour les recherches vectorielles. D'autres stratégies, telles que <strong>AsyncBM25Strategy</strong> (recherche par mots-clés) et <strong>AsyncSparseVectorStrategy</strong> (vecteurs épars), sont également disponibles. Plus de détails peuvent être trouvés dans la <a href="https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/elasticsearch/">documentation officielle</a>.</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)<p>Ensuite, un objet <strong>VectorStoreIndex</strong> sera créé, où nous configurerons le <strong>vector_store</strong> en utilisant l'objet ElasticsearchStore. Avec la méthode <strong>as_retriever</strong>, nous recherchons les documents les plus pertinents pour une requête, en fixant le nombre de résultats renvoyés à 5 par le biais du paramètre <strong>similarity_top_k.</strong></p>   index = VectorStoreIndex.from_vector_store(vector_store=es)
   retriever = index.as_retriever(similarity_top_k=5)
   results = retriever.retrieve(query)<p>L'étape suivante est le GCR. Les résultats de la recherche vectorielle sont incorporés dans une invite formatée pour le LLM, permettant une réponse contextualisée basée sur les informations récupérées.</p><p>Dans le PromptTemplate, nous définissons le format de l'invite, qui inclut :</p><ul><li><p>Contexte ({context_str}) : documents récupérés par le chercheur.</p></li><li><p>Query ({query_str}) : la question de l'utilisateur.</p></li><li><p>Instructions : lignes directrices permettant au modèle de répondre en fonction du contexte, sans s'appuyer sur des connaissances externes.</p></li></ul>qa_prompt = PromptTemplate(
   "You are a helpful and knowledgeable assistant."
   "Your task is to answer the user's query based solely on the context provided below."
   "Do not use any prior knowledge or external information.\n"
   "---------------------\n"
   "Context:\n"
   "{context_str}\n"
   "---------------------\n"
   "Query: {query_str}\n"
   "Instructions:\n"
   "1. Carefully read and understand the context provided.\n"
   "2. If the context contains enough information to answer the query, provide a clear and concise answer.\n"
   "3. Do not make up or guess any information.\n"
   "Answer: "
)<p>Enfin, le LLM traite l'invite et renvoie une réponse précise et contextuelle.</p>llm = OpenAI(model="gpt-4o")
context_str = "\n\n".join([n.node.get_content() for n in results])
response = llm.complete(
   qa_prompt.format(context_str=context_str, query_str=query)
)

print("Answer:")
print(response)<p>Le code complet se trouve ci-dessous :</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)


def print_results(results):
   for rank, result in enumerate(results, start=1):
       title = result.metadata.get("title")
       score = result.get_score()
       text = result.get_text()
       print(f"{rank}. title={title} \nscore={score} \ncontent={text}")


def search(query: str):
   index = VectorStoreIndex.from_vector_store(vector_store=es)

   retriever = index.as_retriever(similarity_top_k=10)
   results = retriever.retrieve(QueryBundle(query_str=query))
   print_results(results)

   qa_prompt = PromptTemplate(
       "You are a helpful and knowledgeable assistant."
       "Your task is to answer the user's query based solely on the context provided below."
       "Do not use any prior knowledge or external information.\n"
       "---------------------\n"
       "Context:\n"
       "{context_str}\n"
       "---------------------\n"
       "Query: {query_str}\n"
       "Instructions:\n"
       "1. Carefully read and understand the context provided.\n"
       "2. If the context contains enough information to answer the query, provide a clear and concise answer.\n"
       "3. Do not make up or guess any information.\n"
       "Answer: "
   )

   llm = OpenAI(model="gpt-4o")
   context_str = "\n\n".join([n.node.get_content() for n in results])
   response = llm.complete(
       qa_prompt.format(context_str=context_str, query_str=query)
   )

   print("Answer:")
   print(response)


question = "Elastic services are free?"
print(f"Question: {question}")
search(question)<p>Nous pouvons maintenant effectuer notre recherche, par exemple, "Les services Elastic sont gratuits ?" et obtenir une réponse contextualisée basée sur les données de la FAQ elle-même.</p>Question: Elastic services are free?
Answer:
Elastic services are not entirely free. However, there is a 14-day free trial available for exploring Elastic solutions. After the trial, access to features and services depends on the subscription level.<p>Les documents suivants ont été utilisés pour élaborer cette réponse :</p>1. title=Can I Try Elasticsearch Service For Free 
score=1.0 
content=Yes, sign up for a 14-day free trial. The trial starts the moment a cluster is created.
During the free trial period get access to a deployment to explore Elastic solutions for Enterprise Search, Observability, Security, or the latest version of the Elastic Stack.

2. title=Do You Offer Elastic S Commercial Products 
score=0.9941274512218439 
content=Yes, all Elasticsearch Service customers have access to basic authentication, role-based access control, and monitoring.
Elasticsearch Service Gold, Platinum and Enterprise customers get complete access to all the capabilities in X-Pack: Security, Alerting, Monitoring, Reporting, Graph Analysis &amp; Visualization. Contact us to learn more.

3. title=What Is Elasticsearch Service 
score=0.9896776845746571 
content=Elasticsearch Service is hosted and managed Elasticsearch and Kibana brought to you by the creators of Elasticsearch. Elasticsearch Service is part of Elastic Cloud and ships with features that you can only get from the company behind Elasticsearch, Kibana, Beats, and Logstash. Elasticsearch is a full text search engine that suits a range of uses, from search on websites to big data analytics and more.

4. title=Can I Run The Full Elastic Stack In Elasticsearch Service 
score=0.9880631561979476 
content=Many of the products that are part of the Elastic Stack are readily available in Elasticsearch Service, including Elasticsearch, Kibana, plugins, and features such as monitoring and security. Use other Elastic Stack products directly with Elasticsearch Service. For example, both Logstash and Beats can send their data to Elasticsearch Service. What is run is determined by the subscription level.

5. title=What Is The Difference Between Elasticsearch Service And The Amazon Elasticsearch Service 
score=0.9835054890793161 
content=Elasticsearch Service is the only hosted and managed Elasticsearch service built, managed, and supported by the company behind Elasticsearch, Kibana, Beats, and Logstash. With Elasticsearch Service, you always get the latest versions of the software. Our service is built on best practices and years of experience hosting and managing thousands of Elasticsearch clusters in the Cloud and on premise. For more information, check the following Amazon and Elastic Elasticsearch Service comparison page.
Please note that there is no formal partnership between Elastic and Amazon Web Services (AWS), and Elastic does not provide any support on the AWS Elasticsearch Service.<h2>Conclusion</h2><p>En utilisant LlamaIndex, nous avons démontré comment créer un système efficace de recherche de FAQ avec le support d'Elasticsearch comme base de données vectorielle. Les documents sont ingérés et indexés à l'aide d'enchâssements, ce qui permet d'effectuer des recherches vectorielles. Grâce à un PromptTemplate, les résultats de la recherche sont intégrés dans le contexte et envoyés au LLM, qui génère des réponses précises et contextualisées sur la base des documents récupérés.</p><p>Ce flux de travail intègre la recherche d'informations et la génération de réponses contextualisées afin de fournir des résultats précis et pertinents.</p><h2>Références</h2><p><a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html</a></p><p><a href="https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/">https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/</a></p><p><a href="https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/">https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/</a></p><p><a href="https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/">https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/</a></p><p><a href="https://www.elastic.co/search-labs/integrations/llama-index">https://www.elastic.co/search-labs/integrations/llama-index</a></p><p></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-llamaindex-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-llamaindex-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf9f88afa92e90390/6a17f4d33e03d7987d4f2dd0/b8b760bfd8694df43fd74ba90ae5fc1edbe4ce76-1150x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 28 Feb 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Apache Airflow]]></title>
    <description><![CDATA[Apprenez à ingérer des données dans Elasticsearch grâce à Apache Airflow.]]></description>
    <content:encoded><![CDATA[<h2>Qu'est-ce que le flux d'air Apache ?</h2><p>Apache Airflow est une plateforme conçue pour créer, planifier et contrôler les flux de travail. Il est utilisé pour orchestrer les processus ETL, les pipelines de données et d'autres flux de travail complexes, en offrant flexibilité et évolutivité. Son interface visuelle et ses capacités de suivi en temps réel rendent la gestion des pipelines plus accessible et plus efficace, vous permettant de suivre la progression et les résultats de vos exécutions. Ses quatre principaux piliers sont décrits ci-dessous :</p><ul><li><p><strong>Dynamique : </strong>Les pipelines sont définis en Python, ce qui permet de générer des flux de travail dynamiques et flexibles.</p></li><li><p><strong>Extensible :</strong> Airflow peut être intégré dans une variété d'environnements, des opérateurs personnalisés peuvent être créés et un code spécifique peut être exécuté selon les besoins.</p></li><li><p><strong>Élégant :</strong> Les pipelines sont rédigés de manière claire et explicite.</p></li><li><p><strong>Évolutif :</strong> Son architecture modulaire utilise une file d'attente de messages pour orchestrer un nombre arbitraire de travailleurs.</p></li></ul><p>Dans la pratique, Airflow peut être utilisé dans des scénarios tels que</p><ul><li><p><strong>Importation de données : </strong>Orchestrer l'ingestion quotidienne de données dans une base de données telle qu'Elasticsearch.</p></li><li><p><strong>Surveillance des journaux :</strong> Gérer la collecte et le traitement des fichiers journaux, qui sont ensuite analysés dans Elasticsearch pour identifier les erreurs ou les anomalies.</p></li><li><p><strong>Intégration de sources de données multiples :</strong> Combinez des informations provenant de différents systèmes (API, bases de données, fichiers) en une seule couche dans Elasticsearch, ce qui simplifie la recherche et la création de rapports.</p></li></ul><h2>Comprendre les DAG (Directed Acyclic Graphs) dans Airflow</h2><p>Dans Airflow, les flux de travail sont représentés par des DAG (Directed Acyclic Graphs). Un DAG est une structure qui définit la séquence d'exécution des tâches. Les principales caractéristiques des DAG sont les suivantes</p><ul><li><p><strong>Composition par tâches indépendantes :</strong> Chaque tâche représente une unité de travail et est conçue pour être exécutée de manière indépendante.</p></li><li><p><strong>Séquencement : </strong>L'ordre dans lequel les tâches sont exécutées est explicitement défini dans le DAG.</p></li><li><p><strong>Réutilisation :</strong> Les DAG sont conçus pour être exécutés de manière répétée, ce qui facilite l'automatisation des processus.</p></li></ul><h2>Composants du flux d'air</h2><p>L'écosystème Airflow est composé de plusieurs éléments qui fonctionnent ensemble pour orchestrer les tâches :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25a23489b8725b3e/6a17dfcfe8fbceba103a1846/bacd83aff625026d62f023e0434baa5782a2761a-1046x628.png" alt="Composants principaux du flux d'air" /><ul><li><p><strong>Ordonnanceur :</strong> Responsable de la programmation des DAG et de l'envoi des tâches à exécuter par les travailleurs.</p></li><li><p><strong>Exécutant :</strong> Il gère l'exécution des tâches et les délègue aux travailleurs.</p></li><li><p><strong>Serveur Web :</strong> Fournit une interface graphique permettant d'interagir avec les DAG et les tâches.</p></li><li><p><strong>Dossier Dags :</strong> Dossier dans lequel nous stockons les DAGs écrits en Python.</p></li><li><p><strong>Métadonnées :</strong> Base de données qui sert de référentiel pour l'outil, utilisée par le planificateur et l'exécuteur pour stocker l'état d'exécution.</p></li></ul><h2>Apache Airflow et Elasticsearch</h2><p>Nous démontrerons l'utilisation d'Apache Airflow et d'Elasticsearch pour orchestrer des tâches et indexer les résultats dans Elasticsearch. L'objectif de cette démonstration est de créer un pipeline de tâches pour mettre à jour les enregistrements dans un index Elasticsearch. Cet index contient une base de données de films, où les utilisateurs peuvent évaluer et attribuer des notes. Imaginons un scénario avec des centaines d'évaluations quotidiennes, il est nécessaire de maintenir l'enregistrement des évaluations à jour. Pour ce faire, un DAG sera développé et exécuté quotidiennement, chargé de récupérer les nouvelles notations consolidées et de mettre à jour les enregistrements dans l'index.</p><p>Dans le flux DAG, nous aurons une tâche pour récupérer les classements, suivie d'une tâche pour valider les résultats. Si les données n'existent pas, le DAG sera dirigé vers une tâche d'échec. Sinon, les données seront indexées dans Elasticsearch. L'objectif est de mettre à jour le champ de classement des films dans un index en récupérant les classements par le biais d'une méthode avec le mécanisme responsable du calcul des scores.</p><h2>Utiliser Apache Airflow et Elasticsearch avec Docker</h2><p>Pour créer un environnement conteneurisé, nous utiliserons Apache Airflow avec Docker. Suivez les instructions du guide <a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">"Running Airflow in Docker"</a> pour configurer Airflow de manière pratique.</p><p>En ce qui concerne Elasticsearch, j'utiliserai un cluster sur Elastic Cloud, mais si vous préférez, vous pouvez également configurer Elasticsearch avec Docker. Un index a déjà été créé, contenant un catalogue de films, avec les données des films indexées. Le champ "rating" de ces films sera mis à jour.</p><h2>Création du DAG</h2><p>Après l'installation via Docker, une structure de dossiers sera créée, y compris le dossier dags, où nous devons placer nos fichiers DAG pour qu'Airflow les reconnaisse.</p><p>Avant cela, nous devons nous assurer que les dépendances nécessaires sont installées. Voici les dépendances pour ce projet :</p>pip install apache-airflow apache-airflow-providers-elasticsearch<p>Nous allons créer le fichier <code>update_ratings_movies.py</code> et commencer à coder les tâches.</p><p>Maintenant, importons les bibliothèques nécessaires :</p>from airflow import DAG
from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook<p>Nous utiliserons <a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html"><strong>ElasticsearchPythonHook</strong></a>, un composant qui simplifie l'intégration entre Airflow et un cluster Elasticsearch en abstrayant la connexion et l'utilisation d'API externes.</p><p>Nous définissons ensuite le DAG en précisant ses principaux arguments :</p><ul><li><p><strong><code>dag_id</code></strong>le nom du DAG.</p></li><li><p><strong><code>start_date</code></strong>: quand le DAG démarrera.</p></li><li><p><strong><code>schedule</code></strong>: définit la périodicité (quotidienne dans notre cas).</p></li><li><p><strong><code>doc_md</code></strong>La documentation : la documentation qui sera importée et affichée dans l'interface Airflow.</p></li></ul><h2>Définition des tâches</h2><p>Définissons maintenant les tâches du DAG. La première tâche consistera à récupérer les données relatives à la classification des films. Nous utiliserons l'<strong>opérateur Python</strong> avec l'adresse <code>task_id</code> fixée à <code>'get_movie_ratings'</code>. Le paramètre <code>python_callable</code> appellera la fonction responsable de la recherche des classements.</p>get_ratings_operator = PythonOperator(
   task_id='get_movie_ratings',
   python_callable=get_movie_ratings_task
)<p>Ensuite, nous devons vérifier si les résultats sont valables. Pour cela, nous utiliserons une conditionnelle avec un <strong>BranchPythonOperator</strong>. L'adresse <code>task_id</code> sera <code>'validate_result'</code>, et l'adresse <code>python_callable</code> appellera la fonction de validation. Le paramètre <code>op_args</code> sera utilisé pour transmettre le résultat de la tâche précédente, <code>'get_movie_ratings'</code>, à la fonction de validation.</p>validate_result = BranchPythonOperator(
   task_id='validate_result',
   python_callable=validate_result,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Si la validation est réussie, nous prendrons les données de la tâche <code>'get_movie_ratings'</code> et les indexerons dans Elasticsearch. Pour ce faire, nous allons créer une nouvelle tâche, <code>'index_movie_ratings'</code>, qui utilisera l'<strong>opérateur Python.</strong> Le paramètre <code>op_args</code> transmet les résultats de la tâche <code>'get_movie_ratings'</code> à la fonction d'indexation.</p>index_ratings_operator = PythonOperator(
   task_id='index_movie_ratings',
   python_callable=index_movie_ratings_task,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Si la validation indique un échec, le DAG passe à une tâche de notification d'échec. Dans cet exemple, nous nous contentons d'imprimer un message, mais dans un scénario réel, nous pourrions configurer des alertes pour signaler les défaillances.</p>failed_get_rating_operator = PythonOperator(
   task_id='failed_get_rating_operator',
   python_callable=lambda: print('Ratings were False, skipping indexing.')
)<p>Enfin, nous définissons les dépendances des tâches, en veillant à ce qu'elles s'exécutent dans le bon ordre :</p>get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<p>Voici maintenant le code complet de notre DAG :</p>"""
DAG update Rating Movies
"""
import ast
import random

from airflow import DAG
from datetime import datetime

from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook


def index_movie_ratings_task(movies):
   es_hook = ElasticsearchPythonHook(hosts=None,
                                     es_conn_args={
                                         "cloud_id": "cloud_id"
                                         "api_key": "api-key"
                                     })
   es_client = es_hook.get_conn
   actions = []
   for movie in ast.literal_eval(movies):
       actions.append(
           {
               "update": {
                   "_id": movie["id"],
                   "_index": "movies"
               }
           }
       )
       actions.append(
           {
               "doc": {
                   "rating": movie["rating"]
               },
               "doc_as_upsert": True
           }
       )
   result = es_client.bulk(operations=actions)
   print(f"Ingestion completed.")
   print(result)
   return True


def get_movie_ratings_task():
   movies = [
       {"id": i, "rating": round(random.uniform(1, 10), 1)}
       for i in range(1, 100)
   ]
   return movies

def validate_result(result):
   if not result:
       return 'failed_get_rating_operator'
   else:
       return 'index_movie_ratings'


with DAG(
       dag_id="update_ratings_movies_2024",
       start_date=datetime(2024, 12, 29),
       schedule="@daily",
       doc_md=__doc__,
):
   get_ratings_operator = PythonOperator(
       task_id='get_movie_ratings',
       python_callable=get_movie_ratings_task
   )

   validate_result = BranchPythonOperator(
       task_id='validate_result',
       python_callable=validate_result,
       op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"],
       provide_context=True
   )

   index_ratings_operator = PythonOperator(
       task_id='index_movie_ratings',
       python_callable=index_movie_ratings_task,
       op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
   )

   failed_get_rating_operator = PythonOperator(
       task_id='failed_get_rating_operator',
       python_callable=lambda: print('Ratings were False, skipping indexing.')
   )

get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<h2>Visualisation de l'exécution du DAG</h2><p>Dans l'interface Apache Airflow, nous pouvons visualiser l'exécution des DAGs. Il suffit d'aller sur l'onglet "DAGs" et de localiser le DAG que vous avez créé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9c5de210a5a264ad/6a17dfd00b0bed0290dd34cf/905b9191c4e3191e8b5608174d4c555370bf25eb-1600x760.png" alt="Visualiser l'exécution des DAGs dans l'interface Apache Airflow avec Elasticsearch" /><p>Ci-dessous, nous pouvons visualiser les exécutions des tâches et leurs statuts respectifs. En sélectionnant une exécution pour une date spécifique, nous pouvons accéder aux journaux de chaque tâche. Notez que dans la tâche <strong><code>index_movie_ratings</code></strong>, nous pouvons voir les résultats de l'indexation dans l'index, et qu'elle s'est déroulée avec succès.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0beddf311a808d24/6a17dfd2033c8d76de6bb0ba/73c3f738d27500cf153377bedf1aa2b67a94a8c8-1600x648.png" alt="visualiser les exécutions des tâches et leurs statuts dans Apache Airflow avec Elasticsearch" /><p>Dans les autres onglets, il est possible d'accéder à des informations supplémentaires sur les tâches et le GDA, ce qui facilite l'analyse et la résolution des problèmes potentiels.</p><h2>Conclusion</h2><p>Dans cet article, nous avons montré comment intégrer Apache Airflow à Elasticsearch pour créer une solution d'ingestion de données. Nous avons montré comment configurer le DAG, définir les tâches responsables de la récupération, de la validation et de l'indexation des données des films, ainsi que contrôler et visualiser l'exécution de ces tâches dans l'interface Airflow.</p><p>Cette approche peut être facilement adaptée à différents types de données et de flux de travail, ce qui fait d'Airflow un outil utile pour orchestrer les pipelines de données dans divers scénarios.</p><h2>Références</h2><p>Apache AirFlow</p><p><a href="https://airflow.apache.org/">https://airflow.apache.org/</a></p><p>Installer Apache Airflow avec Docker</p><p><a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html</a></p><p>Elasticsearch Python Hook</p><p><a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html">https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html</a></p><p>Opérateur Python</p><p><a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/python.html">https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/python.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/apache-airflow-elasticsearch-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/apache-airflow-elasticsearch-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt28475ace97d1d989/6a1704c9286714d6dd93e1ec/5d4b47ac5d2ba453fc19dcc15efa2aed5f55d88b-1440x1355.png" length="0" type="image/png"/>
    <pubDate>Fri, 17 Jan 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Kafka ?]]></title>
    <description><![CDATA[Un guide pas à pas pour intégrer Apache Kafka avec Elasticsearch pour une ingestion, une indexation et une visualisation efficaces des données en utilisant Python, Docker Compose et Kafka Connect.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous montrons comment intégrer Apache Kafka avec Elasticsearch pour l'ingestion et l'indexation des données. Nous donnerons un aperçu de Kafka, de son concept de producteurs et de consommateurs, et nous créerons un index de logs où les messages seront reçus et indexés par Apache Kafka. Le projet est mis en œuvre en Python, et le code est disponible sur <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a>.</p><h3><strong>Produits requis</strong></h3><ul><li><p>Docker et Docker Compose : Assurez-vous que Docker et Docker Compose sont installés sur votre machine.</p></li><li><p>Python 3.x : Pour exécuter les scripts du producteur et du consommateur.</p></li></ul><h3><strong>Introduction à Apache Kafka</strong></h3><p>Apache Kafka est une plateforme de diffusion en continu distribuée qui permet une évolutivité et une disponibilité élevées, ainsi qu'une tolérance aux pannes. Dans Kafka, la gestion des données s'effectue par le biais des principaux composants :</p><ul><li><p><strong>Courtier</strong>: responsable du stockage et de la distribution des messages entre les producteurs et les consommateurs.</p></li><li><p><strong>Zookeeper</strong>: gère et coordonne les courtiers Kafka, en contrôlant l'état de la grappe, les chefs de partition et les informations sur les consommateurs.</p></li><li><p><strong>Sujets</strong>: canaux où les données sont publiées et stockées pour être consommées.</p></li><li><p><strong>Consommateurs et producteurs</strong>: tandis que les producteurs envoient des données aux thèmes, les consommateurs récupèrent ces données.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4aae32304d7417f6/6a17f7be577262b47c1bcdac/89a37243baec48bbdfa85e3298fc91082322ed4e-1600x868.png" alt="Diagramme Apache Kafka" /><p>Ces composants fonctionnent ensemble pour former l'écosystème Kafka, qui fournit un cadre robuste pour la diffusion de données en continu.</p><h3><strong>Structure du projet</strong></h3><p>Pour comprendre le processus d'ingestion des données, nous l'avons divisé en plusieurs étapes :</p><ul><li><p><strong>Provisionnement de l'infrastructure</strong>: mise en place de l'environnement Docker pour prendre en charge Kafka, Elasticsearch et Kibana.</p></li><li><p><strong>Création du producteur</strong>: mise en œuvre du producteur Kafka, qui envoie des données au sujet des journaux.</p></li><li><p><strong>Création du consommateur</strong>: développement du consommateur Kafka pour lire et indexer les messages dans Elasticsearch.</p></li><li><p><strong>Validation de l'ingestion</strong>: vérification et validation des données envoyées et consommées.</p></li></ul><h3><strong>Configuration de l'infrastructure avec Docker Compose</strong></h3><p>Nous avons utilisé Docker Compose pour configurer et gérer les services nécessaires. Vous trouverez ci-dessous le code Docker Compose qui met en place chaque service nécessaire à l'intégration d'Apache Kafka, Elasticsearch et Kibana, en assurant un processus d'ingestion des données.</p>version: "3"

services:

  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    container_name: zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181

  kafka:
    image: confluentinc/cp-kafka:latest
    container_name: kafka
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
      - "9094:9094"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST:${HOST_IP}:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.1
    container_name: elasticsearch-8.15.1
    environment:
      - node.name=elasticsearch
      - xpack.security.enabled=false
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./elasticsearch:/usr/share/elasticsearch/data
    ports:
      - 9200:9200

  kibana:
    image: docker.elastic.co/kibana/kibana:8.15.1
    container_name: kibana-8.15.1
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
      ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]'<p>Vous pouvez accéder au fichier directement depuis le repo <a href="https://github.com/andreluiz1987/elasticsearch-labs/tree/supporting-blog/elasticsearch-apache-kafka/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a> d'Elasticsearch Labs.</p><h3><strong>Envoi de données avec le producteur Kafka</strong></h3><p>Le producteur est responsable de l'envoi des messages au sujet des journaux. L'envoi de messages par lots augmente l'efficacité de l'utilisation du réseau et permet d'optimiser les paramètres <code>batch_size</code> et <code>linger_ms</code>, qui contrôlent respectivement la quantité et la latence des lots. La configuration <code>acks='all'</code> garantit que les messages sont stockés durablement, ce qui est essentiel pour les données d'enregistrement importantes.</p>producer = KafkaProducer(
   bootstrap_servers=['localhost:9092'],  # Specifies the Kafka server to connect
   value_serializer=lambda x: json.dumps(x).encode('utf-8'),  # Serializes data as JSON and encodes it to UTF-8 before sending
   batch_size=16384,     # Sets the maximum batch size in bytes (here, 16 KB) for buffered messages before sending
   linger_ms=10,         # Sets the maximum delay (in milliseconds) before sending the batch
   acks='all'            # Specifies acknowledgment level; 'all' ensures message durability by waiting for all replicas to acknowledge
)


def generate_log_message():
   levels = ["INFO", "WARNING", "ERROR", "DEBUG"]
   messages = [
       "User login successful",
       "User login failed",
       "Database connection established",
       "Database connection failed",
       "Service started",
       "Service stopped",
       "Payment processed",
       "Payment failed"
   ]
   log_entry = {
       "level": random.choice(levels),
       "message": random.choice(messages),
       "timestamp": time.time()
   }
   return log_entry

def send_log_batches(topic, num_batches=5, batch_size=10):
   for i in range(num_batches):
       logger.info(f"Sending batch {i + 1}/{num_batches}")
       for  in range(batch_size):
           log_message = generate_log_message()
           producer.send(topic, value=log_message)
       producer.flush()


if __name__ == "__main__":
   topic = "logs"
   send_log_batches(topic)
   producer.close()<p>Lors du démarrage du producteur, les messages sont envoyés par lots au sujet, comme indiqué ci-dessous :</p>INFO:kafka.conn:Set configuration …
INFO:log_producer:Sending batch 1/5 
INFO:log_producer:Sending batch 2/5
INFO:log_producer:Sending batch 3/5
INFO:log_producer:Sending batch 4/5<h3><strong>Consommation et indexation des données avec le consommateur Kafka</strong></h3><p>Le consommateur est conçu pour traiter efficacement les messages, en consommant des lots à partir du sujet des journaux et en les indexant dans Elasticsearch. Avec <code>auto_offset_reset='latest'</code>, il s'assure que le consommateur commence à traiter les messages les plus récents, en ignorant les plus anciens, et <code>max_poll_records=10</code> limite le lot à 10 messages. Avec <code>fetch_max_wait_ms=2000</code>, le consommateur attend jusqu'à 2 secondes pour accumuler suffisamment de messages avant de traiter le lot.</p><p>Dans sa boucle principale, le consommateur consomme les messages du journal, traite et indexe chaque lot dans Elasticsearch, assurant ainsi une ingestion continue des données.</p>consumer = KafkaConsumer(
   'logs',                               
   bootstrap_servers=['localhost:9092'],
   auto_offset_reset='latest',            # Ensures reading from the latest offset if the group has no offset stored
   enable_auto_commit=True,               # Automatically commits the offset after processing
   group_id='log_consumer_group',         # Specifies the consumer group to manage offset tracking
   max_poll_records=10,                   # Maximum number of messages per batch
   fetch_max_wait_ms=2000                 # Maximum wait time to form a batch (in ms)
)

def create_bulk_actions(logs):
   for log in logs:
       yield {
           "_index": "logs",
           "_source": {
               'level': log['level'],
               'message': log['message'],
               'timestamp': log['timestamp']
           }
       }

if __name__ == "__main__":
   try:
       print("Starting message processing…")
       while True:

           messages = consumer.poll(timeout_ms=1000)  # Poll receive messages

           # process each batch messages
           for _, records in messages.items():
               logs = [json.loads(record.value) for record in records]
               bulk_actions = create_bulk_actions(logs)
               response = helpers.bulk(es, bulk_actions)
               print(f"Indexed {response[0]} logs.")
   except Exception as e:
       print(f"Erro: {e}")
   finally:
       consumer.close()
       print(f"Finish")<h3><strong>Visualisation des données dans Kibana</strong></h3><p>Avec Kibana, nous pouvons explorer et valider les données ingérées depuis Kafka et indexées dans Elasticsearch. En accédant à <strong>Dev Tools</strong> dans Kibana, vous pouvez visualiser les messages indexés et confirmer que les données sont conformes aux attentes. Par exemple, si notre producteur Kafka a envoyé 5 lots de 10 messages chacun, nous devrions voir un total de 50 enregistrements dans l'index.</p><p>Pour vérifier les données, vous pouvez utiliser la requête suivante dans la section <strong>Outils de développement :</strong></p>GET /logs/_search
{
  "query": {
    "match_all": {}
  }
}<p>Réponse :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc15fb278fe6f984e/6a17f7c0b1e1131ac279f404/f44f95fc27bba50991412d5c7e7728519b9bdec4-688x1024.png" alt="Réponse vérifier les données - Kafka &amp; Elasticsearch​" /><p>En outre, Kibana permet de créer des visualisations et des tableaux de bord qui peuvent rendre l'analyse plus intuitive et interactive. Vous trouverez ci-dessous quelques exemples de tableaux de bord et de visualisations que nous avons créés, qui illustrent les données sous différents formats, améliorant ainsi notre compréhension des informations traitées.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltabc2856c9feedc47/6a17f7c13e9e4522bfba1651/a18e0ebb543e929136d4786651bc6cee32fa69bc-1600x470.png" alt="Visualisation Kibana - Kafka &amp; Elasticsearch​" /><h3><strong>Ingestion de données avec Kafka Connect</strong></h3><p>Kafka Connect est un service conçu pour faciliter l'intégration entre les sources de données et les destinations (puits), telles que les bases de données ou les systèmes de fichiers. Il fonctionne avec des connecteurs prédéfinis qui gèrent automatiquement les mouvements de données. Dans notre cas, Elasticsearch fait office de puits de données.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" alt="Ingestion de données avec Kafka Connect" /><p>En utilisant Kafka Connect, nous pouvons simplifier le processus d'ingestion de données, en éliminant la nécessité d'implémenter manuellement le workflow d'ingestion de données dans Elasticsearch. Avec le connecteur approprié, Kafka Connect permet aux données envoyées à un sujet Kafka d'être directement indexées dans Elasticsearch avec une configuration minimale et sans codage supplémentaire.</p><h4><strong>Travailler avec Kafka Connect</strong></h4><p>Pour mettre en œuvre Kafka Connect, nous allons ajouter le<a href="https://github.com/andreluiz1987/es-apache-kafka/blob/main/docker-compose.yml#L31"> service kafka-connect </a>à notre installation Docker Compose. Un élément clé de cette configuration est l'installation du connecteur Elasticsearch, qui se chargera de l'indexation des données.</p><p>Après avoir configuré le service et créé le conteneur Kafka Connect, un fichier de configuration pour le connecteur Elasticsearch sera nécessaire. Ce fichier définit des paramètres essentiels tels que</p><ul><li><p><code>connection.url</code>: URL de connexion pour Elasticsearch.</p></li><li><p><code>topics</code>: Le sujet Kafka que le connecteur surveillera (dans ce cas, "logs").</p></li><li><p><code>type.name</code>: Type de document dans Elasticsearch (typiquement _doc).</p></li><li><p><code>value.converter</code>: Convertit les messages Kafka au format JSON.</p></li><li><p><code>value.converter.schemas.enable</code>: Spécifie si le schéma doit être inclus.</p></li><li><p><code>schema.ignore</code> et <code>key.ignore</code>: Paramètres permettant d'ignorer les schémas et les clés Kafka lors de l'indexation.</p></li></ul><p>Voici la commande <code>curl</code> pour créer le connecteur Elasticsearch dans Kafka Connect :</p>curl --location '{{url}}/connectors' \
--header 'Content-Type: application/json' \
--data '{
    "name": "elasticsearch-sink-connector",
    "config": {
        "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
        "topics": "logs",
        "connection.url": "http://elasticsearch:9200",
        "type.name": "_doc",
        "value.converter": "org.apache.kafka.connect.json.JsonConverter",
        "value.converter.schemas.enable": "false",
        "schema.ignore": "true",
        "key.ignore": "true"
    }
}'<p>Avec cette configuration, Kafka Connect commencera automatiquement à ingérer les données envoyées au sujet "logs" et à les indexer dans Elasticsearch. Cette approche permet d'automatiser entièrement l'ingestion et l'indexation des données sans nécessiter de codage supplémentaire, ce qui simplifie l'ensemble du processus d'intégration.</p><h3><strong>Conclusion</strong></h3><p>L'intégration de Kafka et d'Elasticsearch crée un pipeline puissant pour l'ingestion et l'analyse de données en temps réel. Ce guide fournit une approche fondamentale pour construire une architecture d'ingestion de données robuste, avec une visualisation et une analyse transparentes dans Kibana, prête à s'adapter à des exigences plus complexes à l'avenir.</p><p>En outre, l'utilisation de Kafka Connect rend l'intégration entre Kafka et Elasticsearch encore plus rationnelle, en éliminant le besoin de code supplémentaire pour traiter et indexer les données. Kafka Connect permet aux données envoyées à un sujet spécifique d'être automatiquement indexées dans Elasticsearch avec une configuration minimale.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-apache-kafka-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-apache-kafka-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" length="0" type="image/png"/>
    <pubDate>Tue, 24 Dec 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Apache Camel ?]]></title>
    <description><![CDATA[Apprenez à ingérer des données dans Elasticsearch via Apache Camel à l'aide d'un exemple pratique.]]></description>
    <content:encoded><![CDATA[<p>L'ingestion de données dans Elasticsearch à l'aide d'Apache Camel est un processus qui combine la robustesse d'un moteur de recherche et la flexibilité d'un cadre d'intégration. Dans cet article, nous allons voir comment Apache Camel peut simplifier et optimiser l'ingestion de données dans Elasticsearch. Pour illustrer cette fonctionnalité, nous allons mettre en œuvre une application d'introduction qui démontre, étape par étape, comment configurer et utiliser Apache Camel pour envoyer des données à Elasticsearch.</p><h2>Qu'est-ce qu'Apache Camel ?</h2><p>Apache Camel est un cadre d'intégration open-source qui simplifie la connexion de divers systèmes, permettant aux développeurs de se concentrer sur la logique commerciale sans se préoccuper des complexités de la communication entre les systèmes. Le concept central de Camel est "routes," qui définit le chemin suivi par un message de l'origine à la destination, en incluant éventuellement des étapes intermédiaires telles que des transformations, des validations et des filtrages.</p><h3>Architecture d'Apache Camel</h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" alt="Architecture d'Apache Camel" /><p>Camel utilise les composants "" pour se connecter à différents systèmes et protocoles, tels que les bases de données et les services de messagerie, et les points d'extrémité "" pour représenter les points d'entrée et de sortie des messages. Ces concepts offrent une conception modulaire et flexible, facilitant la configuration et la gestion d'intégrations complexes de manière efficace et évolutive.</p><h2>Utilisation d'Elasticsearch et d'Apache Camel</h2><p>Nous allons montrer comment configurer une application Java simple qui utilise Apache Camel pour ingérer des données dans un cluster Elasticsearch. Les processus de création, de mise à jour et de suppression de données dans Elasticsearch à l'aide de routes définies dans Apache Camel seront également abordés.</p><h3>1. Ajout de dépendances</h3><p>La première étape de la configuration de cette intégration consiste à ajouter les dépendances nécessaires au fichier <code>pom.xml</code> de votre projet. Cela inclut les bibliothèques Apache Camel et Elasticsearch. Nous utiliserons la nouvelle bibliothèque Java API Client, nous devons donc importer le composant <code>camel-elasticsearch</code> et la version doit être la même que celle de la bibliothèque <code>camel-core</code>.</p><p>Si vous souhaitez utiliser le Java Low level Rest Client, vous devez utiliser le composant Elasticsearch Low level Rest Client.</p>&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-core&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-elasticsearch&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-jackson&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;co.elastic.clients&lt;/groupId&gt;
   &lt;artifactId&gt;elasticsearch-java&lt;/artifactId&gt;
   &lt;version&gt;8.14.3&lt;/version&gt;
&lt;/dependency&gt;
<h3>2. Configuration et exécution du contexte Camel</h3><p>La configuration commence par la création d'un nouveau contexte Camel à l'aide de la classe <code>DefaultCamelContext</code>, qui sert de base à la définition et à l'exécution des itinéraires. Ensuite, nous configurons le composant Elasticsearch, qui permettra à Apache Camel d'interagir avec un cluster Elasticsearch. L'instance <code>ESlasticsearchComponent</code> est configurée pour se connecter à l'adresse <code>localhost:9200</code>, qui est l'adresse par défaut d'un cluster Elasticsearch local. Dans le cas d'un environnement nécessitant une authentification, il convient de lire la documentation relative à la configuration du composant et à l'activation de l'authentification de base, appelée <strong>". Configurer le composant et activer l'authentification de base"</strong>.</p>public class ESComponent {

    public static ElasticsearchComponent getInstance() {
        var elasticsearch = new ElasticsearchComponent();
        elasticsearch.setHostAddresses("localhost:9200");
        return elasticsearch;
    }

    public static String getName() {
        return "elasticsearch";
    }
}
<p>Ce composant est ensuite ajouté au contexte Camel, ce qui permet aux routes définies d'utiliser ce composant pour effectuer des opérations dans Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationBulkRoute());
   context.start();
}
<p>Ensuite, les itinéraires sont ajoutés au contexte. Nous allons créer des itinéraires pour l'indexation, la mise à jour et la suppression de documents en masse.</p><h3>3. Configuration des itinéraires Camel</h3><h4>Indexation des données</h4><p>La première route que nous allons configurer est destinée à l'indexation des données. Nous utiliserons un fichier JSON contenant un catalogue de films. La route sera configurée pour lire le fichier situé à l'adresse <a href="https://gist.github.com/andreluiz1987/40756874b5fbea0a29586f9376d7f1f4"><code>src/main/resources/movies.json</code></a>, désérialiser le contenu JSON en objets Java, puis appliquer une stratégie d'agrégation pour combiner plusieurs messages en un seul, permettant ainsi des opérations par lots dans Elasticsearch. La taille de 500 éléments par message a été configurée, c'est-à-dire que le bulk indexera 500 films à la fois.</p><p>Route Elasticsearch Operation Bulk</p>String URI_BULK_OPERATION = String
       .format("elasticsearch://elasticsearch?operation=%s&amp;indexName=%s",
               IndexOperationConfig.BULK_OPERATION,
               INDEX_NAME);
public class OperationBulkRoute extends RouteBuilder {
   private static final Log log = LogFactory.getLog(OperationBulkRoute.class);
   private static final int BULK_SIZE = 500;

   @Override
   public void configure() {
       from("file:src/main/resources?fileName=movies.json&amp;noop=true")
               .routeId("route-bulk-ingest")
               .unmarshal().json()
               .split(body())
               .aggregate(constant(true), new BulkAggregationStrategy())
               .completionSize(BULK_SIZE)
               .to(URI_BULK_OPERATION)
               .process(exchange -&gt; {
                   var body = exchange.getIn().getBody(String.class);
                   log.info(String.format("Response: %s", body));
               })
               .end();
   }
}
<p>Le lot de documents sera envoyé au point de terminaison de l'opération en bloc d'Elasticsearch. Cette approche garantit l'efficacité et la rapidité du traitement de grands volumes de données.</p><h4>Mise à jour des données</h4><p>La prochaine étape consistera à mettre à jour les documents. Nous avons indexé quelques films dans l'étape précédente et nous allons maintenant créer de nouvelles routes pour rechercher un document par code de référence et mettre à jour le champ "rating".</p><p>Nous mettons en place un contexte Camel <code>(DefaultCamelContext)</code>, dans lequel un composant Elasticsearch est enregistré et une route personnalisée IngestionRoute est ajoutée. L'opération commence par l'envoi du code du document par le ProducerTemplate, qui lance la route à partir du point de terminaison direct:update-ingestion.</p>try (var context = new DefaultCamelContext()) {
    context.addComponent(ESComponent.getName(), ESComponent.getInstance());
    context.addRoutes(new IngestionRoute());
    context.start();
    ProducerTemplate producerTemplate = context.createProducerTemplate();
    producerTemplate.sendBody("direct:update-ingestion", documentCode);
    Thread.sleep(5000);
}
<p>Ensuite, nous avons l'IngestionRoute, qui est le point d'entrée de ce flux. La route effectue plusieurs opérations en pipeline. Tout d'abord, une recherche dans Elasticsearch est effectuée pour localiser le document par code <code>(direct:search-by-id)</code>, où le SearchByCodeProcessor assemble la requête sur la base du code. Ensuite, le document récupéré est traité par l'UpdateRatingProcessor, qui convertit le résultat en objets Movie, met à jour la classification du film avec une valeur spécifique et prépare le document mis à jour à renvoyer à Elasticsearch pour la mise à jour.</p>public class IngestionRoute extends RouteBuilder {
    private static final Log log = LogFactory.getLog(IngestionRoute.class);

    @Override
    public void configure() throws Exception {

        from("direct:update-ingestion")
                .pipeline()
                .to("direct:search-by-id")
                .to(URI_SEARCH_OPERATION)
                .to("direct:update-rating")
                .to(URI_UPDATE_OPERATION)
                .process(exchange -&gt; {
                    var body = exchange.getIn().getBody(String.class);
                    log.info(String.format("Response: %s", body));
                })
                .end();

        from("direct:search-by-id")
                .process(new SearchByCodeProcessor());

        from("direct:update-rating")
                .process(new UpdateRatingProcessor());
    }
}
<p>Le processeur <code>SearchByCodeProcessor</code> a été configuré uniquement pour exécuter la requête de recherche :</p>public class SearchByCodeProcessor implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        var code = exchange.getIn().getBody();

        String query = "{\n" +
                "  \"query\": {\n" +
                "   \"term\": {\n" +
                "     \"code\": {\n" +
                "       \"value\":" + code + "\n" +
                "     }\n" +
                "   }\n" +
                "  }\n" +
                "}";
        exchange.setProperty("document_code", code);
        exchange.getIn().setBody(query);
    }
}
<p>Le processeur <code>UpdateRatingProcessor</code> est responsable de la mise à jour du champ "rating".</p>public class UpdateRatingProcessor implements Processor {

    private final ObjectMapper objectMapper;

    public UpdateRatingProcessor() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public void process(Exchange exchange) throws Exception {

        HitsMetadata response = exchange.getIn().getBody(HitsMetadata.class);
        var code = Long.parseLong(exchange.getProperty("document_code").toString());

        if (response != null &amp;&amp; response.hits() != null) {

            var documents = parseToMovies(response);

            var optionalMovie = documents.stream()
                    .filter(document -&gt; code == (document.getSource().getCode())).findAny();

            optionalMovie.ifPresent(document -&gt; {
                document.getSource().setRating(13.0);
                Map&lt;String, Object&gt; updateMap = new HashMap&lt;&gt;();
                updateMap.put("doc", document.getSource());
                exchange.getIn().setHeader("indexId", document.getId());
                exchange.getIn().setBody(updateMap);
            });
        }
    }
<h4>Suppression des données</h4><p>Enfin, l'itinéraire de suppression des documents est configuré. Ici, nous allons supprimer un document en utilisant son ID. Dans Elasticsearch, pour supprimer un document, il faut connaître l'identifiant du document, l'index dans lequel le document est stocké et exécuter une requête Delete. Dans Apache Camel, nous effectuerons cette opération en créant une nouvelle route, comme indiqué ci-dessous.</p><p>L'itinéraire part du point d'arrivée direct:op-delete, qui sert de point d'entrée. Lorsqu'un document doit être supprimé, son identifiant <code>(_id)</code> est reçu dans le corps du message. La route définit ensuite l'en-tête indexId avec la valeur de cet identifiant en utilisant le simple<code>("${body}")</code>, qui extrait l'_id du corps du message.</p>public class OperationDeleteRoute extends RouteBuilder {
   private static final Log log = LogFactory.getLog(OperationDeleteRoute.class);

   @Override
   public void configure() {
       from("direct:op-delete")
               .routeId("route-delete")
               .setHeader("indexId", simple("${body}"))
               .to(URI_DELETE_OPERATION)
               .process(exchange -&gt; {
                   var body = exchange.getIn().getBody(String.class);
                   log.info(String.format("Response: %s", body));
               })
               .end();
       ;
   }
}
String URI_DELETE_OPERATION = String
       .format("elasticsearch://elasticsearch?operation=%s&amp;indexName=%s",
               IndexOperationConfig.DELETE_OPERATION,
               INDEX_NAME);
<p>Enfin, le message est dirigé vers le point de terminaison spécifié par URI_DELETE_OPERATION, qui se connecte à Elasticsearch pour effectuer l'opération de suppression du document dans l'index correspondant.
Maintenant que nous avons créé la route, nous pouvons créer un contexte Camel <code>(DefaultCamelContext)</code>, qui est configuré pour inclure le composant Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationDeleteRoute());
   context.start();
   ProducerTemplate producerTemplate = context.createProducerTemplate();
   producerTemplate.sendBody("direct:op-delete", documentId);
}
<p>Ensuite, la route de suppression, définie par la classe <code>OperationDeleteRoute</code>, est ajoutée au contexte. Une fois le contexte initialisé, une adresse <code>ProducerTemplate</code> est utilisée pour transmettre l'identifiant du document à supprimer à l'adresse <code>direct:op-delete</code>, qui déclenche la procédure de suppression.</p><h2>Conclusion</h2><p>L'intégration entre Apache Camel et Elasticsearch permet une ingestion robuste et efficace des données, en tirant parti de la flexibilité de Camel pour définir des itinéraires capables de gérer différents scénarios de manipulation des données, tels que l'indexation, la mise à jour et la suppression. Grâce à cette configuration, vous pouvez orchestrer et automatiser des processus complexes de manière évolutive, en veillant à ce que vos données soient gérées efficacement dans Elasticsearch. Cet exemple montre comment ces outils peuvent être utilisés ensemble pour créer une solution efficace et adaptable pour l'ingestion de données.</p><h2>Références</h2><ul><li><p><a href="https://camel.apache.org/manual/">Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/manual/architecture.html">Architecture d'Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/eips/aggregate-eip.html">Agrégation Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/file-component.html">Composant du dossier</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/elasticsearch-component.html">Composant Elasticsearch</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-apache-camel-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-apache-camel-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" length="0" type="image/png"/>
    <pubDate>Mon, 09 Sep 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>