<?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[Lorenzo Dematte - 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[Lorenzo Dematte - 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/author/lorenzo-dematte</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/author/lorenzo-dematte</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/author/lorenzo-dematte.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 05 Oct 2026 13:17:41 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Comment nous avons construit Elasticsearch simdvec pour faire de la recherche vectorielle l'une des plus rapides au monde]]></title>
    <description><![CDATA[Comment nous avons conçu Elasticsearch simdvec, la bibliothèque de noyaux SIMD optimisée manuellement qui alimente chaque requête de recherche vectorielle dans Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch simdvec est le moteur de calcul de distance vectorielle dans Elasticsearch. Il fournit des noyaux AVX-512 et NEON ajustés manuellement pour chaque type de vecteur pris en charge par Elasticsearch. Son architecture de calcul par lots masque la latence mémoire grâce à un prefetching explicite sur x86 et un chargement entrelacé sur ARM, surpassant jusqu'à 4 fois les performances de bibliothèques comme FAISS et jvector lorsque le volume de données dépasse la capacité du cache du processeur. Dans cet article, nous expliquons les raisons de sa création, son fonctionnement interne et comment il contribue à faire de la recherche vectorielle d'Elasticsearch l'une des plus rapides au monde.</p><h2>Comment nous avons conçu Elasticsearch simdvec</h2><p>Chaque requête de recherche vectorielle dans Elasticsearch, qu'il s'agisse d'un balayage transversal <a href="https://arxiv.org/abs/1603.09320">Hierarchical Navigable Small World (HNSW)</a>, d'un balayage de fichier inversé (IVF) ou d'une passe de reclassement, se résume au même problème : calculer les distances entre les vecteurs, des millions de fois par requête. Elasticsearch prend en charge un large éventail de types de données et de stratégies de quantification, de float32 à int8, bfloat16, binaire et quantification binaire améliorée (BBQ). Chacune présente des compromis différents entre mémoire, débit et rappel. Derrière tout cela se cache un moteur unique : simdvec.</p><p>Nous avons conçu simdvec pour rendre chaque calcul de distance aussi rapide que le permet le matériel. Dans cet article, nous expliquons pourquoi nous l'avons conçu, ce qu'il contient et où il a le plus d'impact.</p><h3>Construit comme une voiture de course</h3><p>En tant que passionnés de Formule 1 (l'un d'entre nous a travaillé pour l'écurie Ferrari), nous constatons un parallèle évident. Une Formule 1 est conçue dans un seul but : réaliser le meilleur temps au tour. La puissance du moteur, l'aérodynamisme et la conception du châssis n'ont d'importance que dans la mesure où ils contribuent à cet objectif. Il en va de même pour une base vectorielle, où le débit d'indexation, la latence des requêtes et le rappel sont les facteurs déterminants de sa performance.</p><p>Bien que le résultat final soit ce qui compte, atteindre les plus hauts niveaux de performance nécessite que chaque composant contribue de façon optimale. Il ne doit pas être simplement <em>suffisant</em>, mais <em>le meilleur </em>de sa catégorie. Simdvec est conçu dans cet esprit, en se concentrant sur une partie critique du système : le moteur. C'est une bibliothèque de noyaux dédiée, optimisée pour le <a href="https://en.wikipedia.org/wiki/Single_instruction,_multiple_data">Single Instruction Multiple Data</a> (SIMD), qui fournit des fonctions de distance C++ natives optimisées et appelées depuis Java via l'interface de fonction étrangère (FFI) <a href="https://openjdk.org/projects/panama/">Panama</a>. Il prend en charge le scoring en lots, le prefetching des lignes de cache et tous les types et mises en page de vecteurs utilisés dans Elasticsearch.</p><p>C'est le moteur derrière chaque requête.</p><h3>Pourquoi nous avons créé le nôtre</h3><p>Nous avons commencé en 2023 avec l'API Panama Vector dans Apache Lucene. Elle fonctionnait bien pour les produits scalaires de nombres flottants 32 bits, mais les besoins d'Elasticsearch ont rapidement dépassé ses capacités. Elasticsearch prend en charge une large gamme de types de vecteurs quantifiés : int8, int4, bfloat16, mono-bit et BBQ asymétrique. Chacun possède des stratégies SIMD, des compositions de packs et des exigences d'accumulateur différents. Au-delà de la couverture des types, les méthodes de scoring d'Elasticsearch exigent un débit supérieur à celui d'une simple paire : HNSW doit évaluer plusieurs voisins du graphe en une seule passe, IVF nécessite un scoring en lots de milliers de candidats avec prefetching, et le scoring sur disque doit fonctionner directement sur la mémoire mappée en mémoire sans copie. Nous avons examiné les solutions disponibles, mais aucune ne couvrait l'ensemble des besoins.</p><p>Nous avons donc développé simdvec : des noyaux C++ natifs optimisés manuellement, appelés depuis Java via FFI, avec scoring par lots, prefetching et prise en charge de tous les types vectoriels utilisés par Elasticsearch. En étant propriétaires de la bibliothèque, nous maîtrisons l'intégralité de la pile. Lorsque nous ajoutons un nouveau type de quantification comme BBQ, il bénéficie d'un noyau SIMD optimisé intégré à l'ensemble du système. Nous n'attendons pas qu'une bibliothèque tierce le prenne en charge et nous ne faisons aucun compromis sur les performances, quel que soit le type. Chaque requête vectorielle dans Elasticsearch – HNSW, IVF, de reclassement ou hybride – s'exécute sur ce moteur, conçu autour des opérations et des types que nous utilisons réellement.</p><p>Simdvec possède des bibliothèques natives distinctes pour x86 et ARM, chacune comportant plusieurs niveaux d'architecture du jeu d'instructions (ISA) sélectionnés au démarrage. La surcharge des appels depuis Java via FFI est très faible, de l'ordre de quelques <a href="https://github.com/ldematte/simsimd-benchmarks/blob/main/COMPARISON.md#ffm-downcall-overhead-measurements">nanosecondes</a>.</p><h3>Le panorama</h3><p>Nous ne sommes pas les seuls à développer des noyaux de distance vectorielle optimisés pour SIMD. L'écosystème est riche et nous souhaitions comprendre les performances de simdvec. Non pas pour classer les projets, mais pour contextualiser et situer le moteur d'Elasticsearch. Nous avons sélectionné trois projets comme points de référence, chacun représentant une approche différente :</p><ul><li><p><strong>jvector</strong> : une bibliothèque Java de recherche de plus proches voisins approximatifs (ANN) qui utilise l'API Panama Vector pour le calcul de distance vectorisé, avec une accélération C native optionnelle sur x86.</p></li><li><p><strong>FAISS</strong> : un framework de recherche vectorielle open source largement déployé, avec des noyaux AVX2/AVX-512 ajustés manuellement.</p></li><li><p><strong>NumKong</strong> (anciennement SimSIMD) : une suite complète de plus de 2 000 noyaux SIMD ajustés manuellement, couvrant les fonctions de distance, les opérations matricielles et le calcul géospatial.</p></li></ul><p>Chaque projet répond à un objectif différent et fait l'objet de compromis différents. Nous incluons des numéros de référence provenant d'eux pour donner du contexte à la performance de simdvec sur les opérations spécifiques dont Elasticsearch a besoin.</p><h3>Comment nous mesurons</h3><p>Les <a href="https://github.com/ChrisHegarty/jvector-kernel-benchmarks">benchmarks simdvec et jvector</a> sont écrits en Java avec JMH, le harnais de microbenchmark JVM standard, avec la surcharge FFI incluse. Pour les <a href="https://github.com/ldematte/simsimd-benchmarks">benchmarks NumKong</a> et <a href="https://github.com/ChrisHegarty/faiss-kernel-benchmarks">FAISS</a>, nous avons écrit de petits programmes C/C++ utilisant Google Benchmark, qui est le framework standard de microbenchmark C++. Ces deux frameworks mesurent les temps d'exécution en nanosecondes, après une phase de warmup et un étalonnage des itérations. Nous avons vérifié, grâce à des compteurs de performance matériels, que toutes les bibliothèques utilisent SIMD sur les deux plateformes. L'ensemble du code des benchmarks est disponible publiquement dans les référentiels GitHub associés (et, pour simdvec, dans le référentiel <a href="https://github.com/elastic/elasticsearch">elasticsearch</a>).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt90a7d66553be3c9d/6a1701d166c4f942caf8bea5/aee116772df161cf86b7668f575ac34c733a23c5-1580x238.png" alt="Tableau listant deux plateformes : x86 avec AMD EPYC Turin (Zen 5), AVX2 et AVX‑512, AWS c8a.4xlarge, et ARM avec Graviton 4 (Neoverse V2), NEON et SVE2, AWS c8g.4xlarge." /><p><strong>Logiciel :</strong> JDK 25.0.2, JMH 1.37, GCC 14, Google Benchmark (dernière version).</p><h2>Un vecteur à la fois</h2><p>L'opération fondamentale de la recherche vectorielle consiste à calculer la distance entre deux vecteurs. Chaque évaluation de voisinage HNSW, chaque score de candidat IVF, chaque comparaison de reclassement ramène à cette boucle interne.</p><p>Nous avons mesuré le débit d'une seule paire à 1 024 dimensions sur les deux plateformes, en commençant par le type float32, le type de référence et celui où l'écosystème est le plus compétitif. Nous avons comparé simdvec à FAISS et jvector ; nous avons exclu NumKong car il utilise des accumulateurs float64 pour float32, ce qui le rend 3,2 à 5,3 fois plus lent (selon la plateforme), privilégiant la précision numérique au débit. Pour une comparaison équitable, nous avons testé NumKong sur int8, où il utilise la même stratégie d'accumulateurs que simdvec.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte3bc2ecaf3ad2b61/6a1701d2ab7f08039ddb9d0f/352cfa0fc18f123140f746d843404f80127fb1b7-1500x675.png" alt="Graphique à barres horizontales intitulé &quot;float32 Dot Product – AMD Turin&quot; qui compare cinq implémentations : FAISS AVX‑512 à 23,2 ns/op, ES simdvec AVX‑512 à 28,3 ns/op, FAISS AVX2 à 36,4 ns/op, ES simdvec AVX2 à 38,9 ns/op et jvector à 43,9 ns/op." /><p>Sur x86, FAISS AVX-512 est le noyau à paire unique le plus rapide à 23 ns. Simdvec AVX-512 suit à 28 ns, un écart qui reflète la surcharge d'appel FFI. Les deux utilisent le FMA 512 bits avec déroulement par accumulateurs multiples. Au niveau AVX2, les deux sont beaucoup plus proches, 36 ns et 39 ns respectivement, tous deux limités par le registre de 256 bits et les largeurs de chargement en mémoire. jvector arrive à 44 ns grâce à l'API Java Panama Vector. Panama génère un bon code SIMD, mais les intrinsèques C++ optimisées manuellement conservent un avantage.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcbbbe442631a575d/6a1701d42b835f81bcf4b083/95e44d9767f21ec4bccaed835e3c99aa180431ee-1500x495.png" alt="Graphique à barres horizontales intitulé &quot;float32 Dot Product – Graviton 4 (ARM)&quot; montrant ES simdvec à 70,2 ns/op, jvector à 110,0 ns/op et FAISS à 155,6 ns/op." /><p>Sur ARM, simdvec affiche le meilleur temps d'exécution (70 ns), devançant largement jvector (110 ns) et FAISS (156 ns). Simdvec utilise des noyaux NEON optimisés manuellement pour aarch64. Jvector, quant à lui, ne possède aucun code ARM natif et repose sur Panama. FAISS s'appuie sur la vectorisation automatique du compilateur plutôt que sur des fonctions intrinsèques NEON explicites, ce qui explique l'écart plus important. Ceci illustre l'avantage pratique de posséder la bibliothèque de noyaux : lors du passage d'Elasticsearch à Graviton, nous avons intégré des noyaux NEON dédiés. Ni jvector ni FAISS n'ont accordé la même priorité au code natif ARM.</p><p>Mais Elasticsearch ne se limite pas aux nombres à virgule flottante 32 bits. La quantification d'<strong>Int8</strong> réduit la mémoire d'un facteur 4, la quantification bfloat16 d'un facteur 2 et la quantification BBQ d'un facteur 32. Chaque type nécessite sa propre stratégie SIMD, et simdvec fournit des noyaux natifs optimisés manuellement pour chacun d'entre eux.</p><p>Parmi les bibliothèques que nous avons comparées, seule NumKong possède des noyaux comparables pour int8. Nous avons mesuré le produit scalaire int8, la distance euclidienne au carré et le cosinus pour le format int8 sur 1 024 dimensions.</p><p><strong>Score Int8 pour une seule paire (1 024 dimensions, ns/vec op – plus bas est mieux)</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3ac255d158e93504/6a1701d5a292997e48d00eb1/a0b852fd5f51d57bd2488886600472ee65ab64da-1594x378.png" alt="Tableau comparant les performances x86 et ARM pour le produit scalaire, la distance euclidienne au carré et les opérations cosinus, en listant les valeurs ES, NumKong et diff pour chaque opération sur les deux architectures." /><p>Sur les deux architectures, NumKong est aussi performant, voire plus rapide, pour les petites et moyennes dimensions, la différence étant principalement due à une surcharge d'appels réduite (appel direct en C contre FFI Java). Pour les grandes dimensions, simdvec rattrape son retard, grâce à une implémentation noyau plus efficace (qui utilise le déroulement en cascade) qui amortit le coût des appels : à mesure que la dimension augmente, <a href="https://github.com/ldematte/simsimd-benchmarks/blob/main/COMPARISON.md#single-pair-i8-nsop-2">cet écart se réduit et finit par s'inverser</a>. Le point de bascule se situe entre 768 et 1 536 dimensions, selon la fonction et l'architecture.</p><p>Malgré la surcharge légèrement supérieure de l'interface FFI Java, simdvec rivalise avec les bibliothèques C/C++ fortement optimisées. Non seulement c'est la seule bibliothèque dotée de noyaux optimisés pour float32 <em>et</em> int8, mais elle est également en tête sur ARM et juste derrière FAISS sur x86 (pour float32), et très proche de NumKong sur les deux architectures (pour int8). Enfin, pour bfloat16, int4, binary et BBQ, bien qu'il existe des alternatives, simdvec se distingue par un SIMD ajusté manuellement et adapté à la structure des données de chaque type.</p><p>Cependant, un moteur de recherche en production n'évalue pas un vecteur à la fois ; il en évalue des milliers par requête. La question suivante est de savoir ce qui se passe à cette échelle.</p><h3>Des milliers à la fois</h3><p>Les performances sur une seule paire ne représentent qu'une partie du problème. En pratique, c'est le comportement des systèmes sous charge qui est important. Une simple requête HNSW peut évaluer des centaines de voisins dans le graphe. Une analyse IVF peut évaluer des milliers d'entrées de listes de publication. Une passe de reclassement peut évaluer des dizaines de milliers de candidats. Le débit sur une seule paire est important, mais ce qui compte davantage, c'est la rapidité avec laquelle il est possible d'évaluer de nombreux vecteurs et la façon dont les performances se dégradent lorsque l'ensemble de travail déborde des caches du processeur.</p><p>Simdvec propose un scoring par lots pour tous les types de données. Il ne s'agit pas simplement de boucles sur des noyaux de distance à une seule paire, mais de boucles internes dotées de plusieurs accumulateurs qui chargent le vecteur de requête une fois par pas de dimension et le partagent entre plusieurs vecteurs de documents, avec un prefetching explicite des lignes de cache pour le lot suivant. Ni jvector ni FAISS n'offrent d'équivalent (à l'heure actuelle). Jvector ne dispose pas d'API Bulk ; les appelants calculent donc le score d'une paire à la fois dans une boucle. FAISS expose <code>fvec_inner_products_ny</code>, qui, à l'heure actuelle, est implémenté comme une boucle sur sa fonction de distance à une seule paire, sans amortissement ni prefetching des requêtes.</p><p><strong>Float32.</strong> Pour mesurer l'impact au niveau du noyau, nous avons évalué une requête unique sur un nombre croissant de vecteurs de documents float32 de 1 024 dimensions, en utilisant des modèles d'accès aléatoire simulant des recherches de voisins dans un graphe dispersé de type HNSW. Les trois tailles d'ensemble de données (32, 625 et 32 500 vecteurs) ont été choisies de manière à ce que l'ensemble de travail dépasse respectivement les caches L1, L2 et L3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2df64ec77a1921ae/6a1701d714b270393ae3c4de/1d90267be1c63ac82b8ba588617ebedb0be0d1b6-1334x558.png" alt="Deux graphiques à barres comparant les temps de scoring du produit scalaire Float32 en lots pour Elasticsearch simdvec, FAISS et jvector sur AMD Turin (x86, AVX-512) et Graviton 4 (ARM, NEON) sur trois tailles : 32 vecteurs, 625 vecteurs et 32 500 vecteurs." /><p>Lorsque les données tiennent dans le cache, simdvec est le plus rapide sur les deux plateformes, mais l'écart reste modeste, car l'arithmétique du noyau est prépondérante. La différence est flagrante lorsque la taille de l'ensemble de travail dépasse le cache L3. Sur x86, simdvec atteint 95 ns par vecteur, contre 165 ns pour FAISS et 412 ns pour jvector. Sur ARM, le constat est identique : simdvec se maintient à 162 ns, tandis que FAISS grimpe à 347 ns et jvector à 476 ns. Le prefetching et l'amortissement des requêtes dans simdvec masquent la latence mémoire, contrairement à une simple boucle sur des noyaux à paire unique. Cet avantage est encore plus manifeste précisément là où les véritables charges de travail de recherche s'exécutent, au cœur de la mémoire principale.</p><p><strong>Int8.</strong> Le même schéma s'applique aux types quantifiés. Nous avons mesuré le scoring par lots du produit scalaire int8 à 1 024 dimensions avec des tailles d'ensemble de données choisies pour dépasser les mêmes limites de cache L1, L2 et L3, en comparant le scoring par lots de simdvec au scoring de paires individuelles de NumKong dans une boucle.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcda85e10007188d0/6a1701d9cf4f25d722b2cff7/9ee97d98b40d13b19370b76b33e67ea66bfb3250-1580x338.png" alt=" Tableau intitulé &quot;x86 – Bulk scoring, int8 dot product (ns/op, lower is better)&quot; comparant ES simdvec et NumKong sur trois tailles de vecteurs – 128, 2 500 et 130 000 – avec les valeurs ns/op correspondantes et les ratios d'accélération." /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt972c311b7d08ba73/6a1701dadc55dec02ee00c87/601f50a03fa3e6263cbac9700281dfe3e511de60-1580x338.png" alt="Tableau intitulé &quot;ARM – Bulk scoring, int8 dot product (ns/op, lower is better)&quot; comparant ES simdvec et NumKong sur trois tailles de vecteurs – 128, 2 500 et 130 000 – avec les valeurs ns/op correspondantes et les ratios d'accélération" /><p>Sur x86, simdvec est de 1,2 à 1,9 fois plus rapide, grâce à la combinaison du prefetching explicite et du traitement par lots. Sur ARM, simdvec l'emporte également (de 1,7 à 1,9 fois plus rapide) quelle que soit la taille des ensembles de données. Cet avantage provient du traitement par lots de quatre vecteurs simultanément, offrant un parallélisme au niveau mémoire via un modèle d'accès entrelacé. Dans les deux cas, le résultat le plus frappant se situe au niveau des ensembles de données les plus volumineux, là où il est le plus significatif.</p><p>Les résultats concernant la distance au carré et le cosinus montrent un schéma similaire, avec des accélérations de 1,4 à 1,8 fois pour ARM, et de 1,3 à 3,0 fois pour x86 (détails <a href="https://github.com/ldematte/simsimd-benchmarks/blob/main/COMPARISON.md">ici</a>).</p><h3>Quand la mémoire est essentielle</h3><p>Les index vectoriels de production ne tiennent généralement pas dans le cache du processeur. Un index vectoriel de 10 millions d'éléments (int8) à 1 024 dimensions pèse 10 Go. Le scoring des candidats implique le traitement en continu des données depuis la DRAM, et c'est là que l'architecture de scoring par lots fait toute la différence.</p><p>Nous avons utilisé des compteurs de performances matérielles pour mesurer ce qui se passe à l'intérieur du processeur pendant le scoring par lots et avons constaté que masquer la latence de la mémoire nécessite deux stratégies fondamentalement différentes, une par architecture.</p><p><strong>Sur x86, le prefetching explicite élimine les défauts de cache. </strong>Le noyau principal traite les vecteurs séquentiellement, chaque vecteur étant entièrement calculé avant le suivant, tout en émettant des instructions de prefetching pour le lot suivant. Les données futures sont chargées dans le cache L1 avant que le processeur n'en ait besoin.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt368f29b5143d0f5a/6a1701dcc1e8a51780f8817b/a39548f8060c2a4a5154521a4047dd92d8cd77be-1580x309.png" alt="Tableau intitulé « x86 (AMD Turin) — Compteurs matériels par opération int8 » comparant les modes simple et groupé pour les pertes de cache L1, l'IPC et les pertes de dTLB, avec les facteurs d'amélioration correspondants." /><p>Sur ARM, la même approche séquentielle s'est avérée peu performante, même avec prefetching. En revanche, le <strong>noyau de traitement par lots entrelace les charges</strong> de quatre vecteurs à chaque position d'itération, offrant ainsi au moteur hors séquence quatre flux mémoire indépendants. Le processeur ne récupère pas les données plus rapidement, mais le temps d'attente est réduit en ayant toujours une autre opération à traiter pendant que les requêtes mémoire sont en cours de traitement. Une analyse détaillée est disponible dans <a href="https://github.com/elastic/elasticsearch/issues/145412">ce ticket GitHub</a>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8751ac5b20b75508/6a1701deab7f08db83db9d13/832de3bc0d556a493b7bf3f250196018acfc1585-1580x238.png" alt="Tableau intitulé &quot;ARM (Graviton 4) – Hardware counters per int8 operation&quot; comparant les modes unique et groupé pour les défauts de cache L1 et les blocages du backend, avec les notes d'amélioration correspondantes" /><p>Les chiffres racontent deux histoires différentes :</p><ol><li><p>Sur x86, le prefetching réduit les défauts de cache de 139 000 à 19 000 et double le nombre d'instructions par cycle (IPC). L'avantage en termes de traitement par lots s'accroît avec la taille des données, passant de 1,2 fois pour le cache L2 à 2,8 fois pour les caches au-delà du cache L3, car le prefetching masque les allers-retours DRAM de plus en plus coûteux.</p></li><li><p>Sur ARM, le nombre d'échecs de cache reste pratiquement inchangé. Ce qui change, c'est le taux d'utilisation : les blocages du backend diminuent de 40 % car le modèle d'accès entrelacé assure l'alimentation continue du pipeline. Cet avantage reste constant, à 1,8 fois, quelle que soit la taille de l'ensemble de données, car le parallélisme au niveau de la mémoire s'applique que les données proviennent du cache ou de la DRAM.</p></li></ol><p>Deux architectures, deux stratégies, un résultat : à l'échelle de la production, simdvec maintient le pipeline du processeur occupé même lorsque les vecteurs sont dispersés dans la mémoire principale.</p><h2>Ce que cela signifie pour les utilisateurs d'Elasticsearch</h2><p>Ces capacités au niveau du noyau s'additionnent. Une simple requête de recherche vectorielle peut calculer des millions d'opérations de distance : parcours de graphe HNSW, scoring des candidats, reclassement. Sur des milliers de requêtes simultanées, chaque opération, même en nanosecondes, se traduit directement par une latence de requête et un débit de cluster optimaux. Que vous utilisiez float32, int8, bfloat16 ou BBQ, que votre index soit en mémoire ou sur disque, simdvec est le moteur sous-jacent, et chacune de ces opérations s'exécute sur ce même moteur, optimisé à la nanoseconde près.</p><p>L'essentiel à retenir est qu'à l'échelle de la production, les performances de la recherche vectorielle ne sont pas principalement déterminées par le débit SIMD brut. Elles dépendent surtout de la capacité du système à masquer efficacement la latence mémoire tout en maintenant la capacité de calcul sur des millions de petites opérations.</p><p>Les noyaux simdvec s'améliorent à quasiment chaque nouvelle version d'Elasticsearch. Dès l'apparition de nouveaux types de quantification et de plateformes matérielles, des noyaux optimisés sont intégrés. De plus, les types existants continuent de gagner en vitesse grâce à l'amélioration des implémentations déjà disponibles.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-vector-search-simdvec-engine</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-vector-search-simdvec-engine</guid>
    <category><![CDATA[Base vectorielle]]></category>
    <category><![CDATA[À l'intérieur d'Elastic]]></category>
    <dc:creator><![CDATA[Chris Hegarty,Lorenzo Dematte,Simon Cooper]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta18088409621369b/6a1701dfdc55de7297e00c8b/df9646091bafbbf0a6dfd212ff8a6bd1e8589708-1280x720.png" length="0" type="image/png"/>
    <pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Indexation vectorielle jusqu'à 12 fois plus rapide dans Elasticsearch avec NVIDIA cuVS : accélération GPU : chapitre 2]]></title>
    <description><![CDATA[Découvrez comment Elasticsearch atteint un débit d'indexation près de 12 fois supérieur grâce à l'indexation vectorielle accélérée par GPU et NVIDIA cuVS.]]></description>
    <content:encoded><![CDATA[<p>Plus tôt cette année, Elastic a annoncé la <a href="https://ir.elastic.co/news/news-details/2025/Elastic-Brings-Enterprise-Data-to-NVIDIA-AI-Factories/default.aspx">collaboration</a> avec NVIDIA pour apporter l'accélération GPU à Elasticsearch, en intégrant <a href="https://developer.nvidia.com/cuvs">NVIDIA cuVS</a>—comme détaillé lors d'une <a href="https://www.nvidia.com/en-us/on-demand/session/gtc25-S71286/">session à NVIDIA GTC</a> et dans divers <a href="https://www.elastic.co/search-labs/blog/gpu-accelerated-vector-search-elasticsearch-nvidia">blogs</a>. Cet article fait le point sur les efforts de co-ingénierie menés avec l'équipe de recherche vectorielle de NVIDIA.</p><h2>Récapitulatif</h2><p>Tout d'abord, faisons le point sur la situation. Elasticsearch s'est imposé comme une base de données vectorielle puissante, offrant un ensemble complet de fonctionnalités et des performances élevées pour la recherche de similitudes à grande échelle. Avec des capacités telles que la quantification scalaire, la quantification binaire améliorée (<a href="https://www.elastic.co/search-labs/blog/better-binary-quantization-lucene-elasticsearch">BBQ</a>), les opérations vectorielles <a href="https://www.elastic.co/blog/accelerating-vector-search-simd-instructions">SIMD</a> et des algorithmes plus efficaces en termes d'espace disque comme <a href="https://www.elastic.co/search-labs/blog/diskbbq-elasticsearch-introduction">DiskBBQ</a>, il offre déjà des options efficaces et flexibles pour gérer les charges de travail vectorielles.</p><p>En intégrant NVIDIA cuVS en tant que module accessible pour les tâches de recherche vectorielle, nous visons à améliorer considérablement les performances et l'efficacité de l'indexation vectorielle afin de mieux prendre en charge les charges de travail vectorielles à grande échelle.</p><h2>Le défi</h2><p>L'un des défis les plus complexes dans la création d'une base de données vectorielle haute performance est la construction de l'index vectoriel, le graphe <a href="https://arxiv.org/abs/1603.09320">HNSW</a>. La construction de l'index est rapidement dominée par des millions, voire des milliards d'opérations arithmétiques, car chaque vecteur est comparé à de nombreux autres. De plus, les opérations liées au cycle de vie des index, telles que la compression et les fusions, peuvent augmenter davantage la charge de calcul globale liée à l'indexation. À mesure que les volumes de données et les intégrations vectorielles associées augmentent de manière exponentielle, les GPU de calcul accéléré, conçus pour le parallélisme massif et les calculs mathématiques à haut débit, sont idéalement positionnés pour gérer ces charges de travail.</p><h2>Installez le plugin Elasticsearch-GPU</h2><p><a href="https://developer.nvidia.com/cuvs">NVIDIA cuVS</a> est une bibliothèque open source CUDA-X pour la recherche vectorielle accélérée par GPU et le clustering de données, permettant une création rapide d'index et une récupération d'embeddings pour les charges de travail liées à l'IA et aux recommandations.</p><p>Elasticsearch utilise cuVS via <a href="https://mvnrepository.com/artifact/com.nvidia.cuvs/cuvs-java">cuvs-java</a>, une bibliothèque open-source développée par la communauté et gérée par NVIDIA. La bibliothèque cuvs-java est légère et repose sur l'<a href="https://docs.rapids.ai/api/cuvs/nightly/c_api/">API cuVS C</a> en utilisant <a href="https://openjdk.org/projects/panama/">Panama</a> Foreign Function pour exposer les fonctionnalités cuVS d'une manière idiomatique Java, tout en restant moderne et performante.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7fd7361099da05a/6a17e920be608670af00477f/5f6daa1eb07f704a6707d9e6b7ccb81d0abaa8c9-566x419.png" alt="Fonctionnement d'Elasticsearch avec NVIDIA cuVS, l'indexation CPU et GPU" /><p>La bibliothèque cuvs-java est intégrée dans un <a href="https://github.com/elastic/elasticsearch/pull/135545">nouveau plug-in Elasticsearch</a> ; par conséquent, l'indexation vectorielle sur le GPU peut être effectuée sur le même node et processus Elasticsearch, sans qu'il soit nécessaire de provisionner du code ou du matériel externe. Lors de la création d'index, si la bibliothèque cuVS est installée et qu'un GPU est présent et configuré, Elasticsearch utilisera le GPU pour accélérer le processus d'indexation vectorielle. Les vecteurs sont transmis au GPU, qui crée un un graphe <a href="https://arxiv.org/abs/2308.15136">CAGRA</a>. Ce graphe est ensuite converti au format HNSW, ce qui le rend immédiatement disponible pour la rechercher vectorielle sur le processeur. Le format final du graphe construit est identique à celui qui serait construit sur le CPU ; cela permet à Elasticsearch d'exploiter les GPU pour une indexation vectorielle à haut débit lorsque le matériel sous-jacent le prend en charge, tout en libérant la puissance du CPU pour d'autres tâches (recherche simultanée, traitement des données, etc.).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt485f55f29d6df5c4/6a17e922be6086dcf3004785/3ea255bd9bfd7983f78143c5eba999d2149d72be-671x356.png" alt="" /><h2>Accélération de la création d'index</h2><p>Dans le cadre de l'intégration de l'accélération GPU dans Elasticsearch, plusieurs améliorations ont été apportées à cuvs-java, en mettant l'accent sur l'efficacité de l'entrée/sortie de données et l'invocation de fonctions. L'une des principales améliorations est l'utilisation de <a href="https://github.com/rapidsai/cuvs/blob/2cf5fa7666d703dccbe655f8214656b0952bb69b/java/cuvs-java/src/main/java/com/nvidia/cuvs/CuVSMatrix.java">cuVSMatrix</a> pour modéliser de manière transparente les vecteurs, qu'ils se trouvent sur le tas Java, hors tas ou dans la mémoire du GPU. Cela permet aux données de se déplacer efficacement entre la mémoire et le GPU, en évitant les copies inutiles de milliards de vecteurs potentiels.</p><p>Grâce à cette abstraction sous-jacente sans copie, le transfert vers la mémoire GPU et la récupération du graphe peuvent être effectués directement. Pendant l'indexation, les vecteurs sont d'abord mis en mémoire tampon sur le tas Java, puis envoyés au GPU pour construire le graphe CAGRA. Le graphe est ensuite récupéré à partir du GPU, converti au format HNSW et persisté sur le disque.</p><p>Au moment de la fusion, les vecteurs sont déjà stockés sur le disque, contournant ainsi entièrement le tas Java. Les fichiers d'index sont mappés en mémoire et les données sont transférées directement dans la mémoire du GPU. La conception s'adapte également facilement à différentes largeurs de bits, telles que float32 ou int8, et s'étend naturellement à d'autres schémas de quantification.</p><h2>Roulement de tambour... alors, comment ça fonctionne ?</h2><p>Avant d'examiner les chiffres, un peu de contexte s'impose. La fusion des segments dans Elasticsearch s'exécute généralement automatiquement en arrière-plan pendant l'indexation, ce qui rend difficile l'évaluation comparative de manière isolée. Pour obtenir des résultats reproductibles, nous avons utilisé la fusion forcée pour déclencher explicitement la fusion des segments dans une expérience contrôlée. Comme la fusion forcée effectue les mêmes opérations de fusion sous-jacentes que la fusion en arrière-plan, ses performances servent d'indicateur utile des améliorations attendues, même si les gains exacts peuvent différer selon les charges de travail d'indexation réelles.</p><p>Passons maintenant aux chiffres.</p><p>Nos premiers résultats de référence sont très prometteurs. Nous avons exécuté une évaluation comparative sur une instance AWS <code>g6.4xlarge</code> avec un stockage NVMe connecté localement. Un seul node d'Elasticsearch a été configuré pour utiliser le nombre optimal par défaut de threads d'indexation (8, soit un pour chaque noyau physique) et pour désactiver la<a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/merge"> limitation de fusion</a> (qui est moins applicable avec les disques NVMe rapides).</p><p>Pour l'ensemble de données, nous avons utilisé 2,6 millions de vecteurs avec 1 536 dimensions provenant de l' <a href="https://github.com/elastic/rally-tracks/blob/master/openai_vector/README.md">OpenAI Rally vector track</a>, encodés sous forme <a href="https://github.com/elastic/elasticsearch/pull/137072">de chaînes base64</a> et indexés sous forme de float32 <em>hnsw</em>. Dans tous les scénarios, les graphes créés atteignent des niveaux de rappel allant jusqu'à 95 %. Voici nos conclusions :</p><ul><li><p><strong>Débit d'indexation :</strong> en transférant la construction des graphiques vers le GPU pendant les vidages de mémoire tampon, nous multiplions le débit par environ 12.</p></li><li><p><strong>Fusion forcée :</strong> une fois l'indexation terminée, le GPU continue d'accélérer la fusion des segments, multipliant par environ 7 la vitesse de la phase de fusion forcée.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfea4ee13b5a3b10d/6a17e923e9ea879c6aa9c616/f60ea9ee5996e456f393ffd195ee7eada6e5a7c2-948x387.png" alt="" /><ul><li><p><strong>Utilisation du processeur :</strong> le transfert de la construction du graphe vers le GPU réduit considérablement l'utilisation moyenne et maximale du processeur. Les graphiques ci-dessous illustrent l'utilisation du CPU pendant l'indexation et la fusion, et mettent en évidence à quel point elle est plus faible lorsque ces opérations sont exécutées sur le GPU. La réduction de l'utilisation du CPU pendant l'indexation GPU permet de libérer des cycles CPU qui peuvent être réaffectés à l'amélioration des performances de recherche.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80ff9c53f9b6884a/6a17e925445de9ee4b4d0187/5e680a5fc41700a877f3d8b2e5ce18ebd3f37a0b-1600x562.png" alt="" /><ul><li><p><strong>Rappel :</strong> la précision reste pratiquement identique entre les exécutions CPU et GPU, le graphique généré par le GPU affichant un rappel légèrement supérieur.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5cbe084eca27b8e4/6a17e926faa913317093c8b7/48a2b7758606bd321712b7d8378cd2640e652a4e-1384x544.png" alt="" /><h2>Comparaison selon un autre critère : le prix</h2><p>La comparaison précédente utilisait intentionnellement un matériel identique, la seule différence étant l'utilisation ou non du GPU lors de l'indexation. Cette configuration est utile pour isoler les effets du calcul brut, mais nous pouvons également examiner la comparaison du point de vue des coûts.</p><p>Pour un prix horaire à peu près équivalent à celui de la configuration accélérée par GPU, il est possible de provisionner une configuration uniquement sur processeur avec environ deux fois plus de ressources CPU et mémoire comparables : 32 vCPU (AMD EPYC) et 64 Go de RAM, permettant de doubler le nombre de threads d’indexation à 16.</p><p>Afin de garantir l'équité et la cohérence de la comparaison, nous avons réalisé cette expérience uniquement sur processeur sur une instance AWS g6.8xlarge, avec le GPU explicitement désactivé. Cela nous a permis de maintenir toutes les autres caractéristiques matérielles constantes tout en évaluant le compromis coût-performance entre l'accélération GPU et l'indexation uniquement sur processeur.</p><p>L'instance de processeur plus puissante montre effectivement une performance améliorée par rapport aux benchmarks de la section ci-dessus, comme on pouvait s'y attendre. Cependant, lorsque nous comparons cette instance de processeur plus puissante aux résultats originaux accélérés par GPU, le GPU offre toujours des gains de performance substantiels : <strong>~5x</strong> d'amélioration dans le débit d'indexation, et <strong>~6x </strong>dans la fusion forcée, tout en construisant des graphes qui atteignent des niveaux de rappel allant jusqu'à <strong>95%.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt94b5eb6f95ba307d/6a17e928abe0f255d4dfea35/8ffa58cae3ad175ef2932a351aeef4c34a1407b9-948x394.png" alt="" /><h2>Conclusion</h2><p>Dans les scénarios de bout en bout, l'accélération GPU avec NVIDIA cuVS permet d'améliorer de près de 12 fois le débit d'indexation et de réduire de 7 fois la latence de fusion forcée, tout en diminuant considérablement l'utilisation du processeur. Cela démontre que l'indexation vectorielle et les charges de travail de fusion bénéficient considérablement de l'accélération GPU. Sur une comparaison ajustée en fonction des coûts, l'accélération GPU continue d'offrir des gains de performances substantiels, avec un débit d'indexation environ 5 fois supérieur et des opérations de fusion forcée 6 fois plus rapides.</p><p>L'indexation vectorielle accélérée par GPU est actuellement prévue pour la préversion technique dans Elasticsearch 9.3, dont la sortie est prévue début 2026.</p><p>Plus d'informations à venir.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-gpu-accelerated-vector-indexing-nvidia</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-gpu-accelerated-vector-indexing-nvidia</guid>
    <category><![CDATA[Base vectorielle]]></category>
    <dc:creator><![CDATA[Chris Hegarty,Hemant Malik,Corey Nolet,Manas Singh,Mithun Radhakrishnan,Mayya Sharipova,Lorenzo Dematte,Ben Frederickson]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1248d51633bd75d9/6a17e92ae9ea8714b3a9c61a/08f7469a4daaf67b7c5999585aae179b6680c78d-896x746.png" length="0" type="image/png"/>
    <pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>