Pourquoi nous avons construit un moteur de recherche souverain
Crawler Node, bus NATS JetStream, indexeur Rust, index ClickHouse, BM25 et signaux explicables : récit technique de comet Search, un moteur dont nous possédons chaque étage.
2 juin 2026 · 6 min de lecture
Construire un moteur de recherche est, sur le papier, une idée déraisonnable. Les moteurs dominants ont vingt ans d'avance, des index de plusieurs centaines de milliards de pages et des budgets sans commune mesure. Et pourtant : une suite qui se dit souveraine mais envoie chaque requête de ses utilisateurs à un moteur tiers a un trou au milieu. La requête de recherche est l'une des données les plus intimes qui soient — elle dit ce que vous cherchez, donc ce qui vous préoccupe. C'est pourquoi comet Search existe. Voici comment il est construit, étage par étage.
Vue d'ensemble
L'architecture est un pipeline dont chaque étage est remplaçable et observable :
crawler (Node/TypeScript)
│ pages, liens, médias
▼
NATS JetStream (bus persistant, rejouable)
│
▼
indexeur (Rust) ──▶ ClickHouse (index colonnes + agrégats)
▲
│
searchd (Rust/axum) ──▶ SERP (Web / Images / Vidéos)
Rien d'exotique dans les briques : du TypeScript là où l'écosystème est riche, du Rust là où la performance compte, une base analytique éprouvée pour l'index. L'intérêt est dans l'assemblage.
Un crawler qui respecte les règles
La collecte est assurée par un crawler écrit en Node/TypeScript. Sa première règle est la politesse : il lit et respecte robots.txt avant de visiter un site, et il espace ses requêtes pour ne pas peser sur les serveurs qu'il visite. Ce n'est pas de la vertu gratuite — un crawler est un invité du web, et un invité mal élevé finit banni. Respecter les règles d'exclusion, c'est aussi la condition pour que l'index reste défendable : il ne contient que ce que les éditeurs ont accepté de rendre accessible aux robots.
Le crawler ne se contente pas de télécharger des pages : il en extrait le texte, les liens sortants avec leurs ancres, les images et les vidéos référencées, puis publie le tout sous forme de messages structurés.
Un bus persistant entre la collecte et l'indexation
Entre le crawler et l'indexeur, il n'y a pas d'appel direct : il y a NATS JetStream, un bus de messages persistant. Ce découplage a trois vertus.
- L'amortissement. Le crawl est irrégulier par nature ; l'indexation préfère un débit stable. Le bus absorbe les rafales.
- L'indépendance des pannes. L'indexeur peut redémarrer, être mis à jour ou prendre du retard sans que la collecte s'arrête, et réciproquement.
- La rejouabilité. C'est la vertu décisive : les messages sont conservés. Quand nous améliorons l'extraction — un meilleur parseur, un nouveau type de média —, nous rejouons le flux et réindexons l'existant sans re-crawler un seul site. Le web n'est sollicité qu'une fois ; nos erreurs d'analyse, elles, sont réparables à volonté.
Un indexeur Rust, un index ClickHouse
L'indexeur, écrit en Rust, consomme le bus et alimente ClickHouse. Le choix d'une base orientée colonnes pour un index de recherche peut surprendre, mais il est cohérent : un index inversé est, au fond, une grande table de faits (terme, document, positions, poids) sur laquelle on fait des agrégations massives. C'est exactement le terrain de jeu de ClickHouse.
Les statistiques globales du corpus — fréquences documentaires, longueurs moyennes, agrégats par domaine — sont des requêtes d'agrégation naturelles :
-- fréquence documentaire d'un terme, ingrédient de l'IDF
SELECT term, uniqExact(doc_id) AS df
FROM postings
GROUP BY term
L'indexeur maintient aussi les signaux calculés hors requête : l'autorité de domaine, les statistiques de fraîcheur, la déduplication des médias. Tout ce qui peut être précalculé l'est, pour que le service de requêtes n'ait plus qu'à composer.
Servir la requête : BM25 et des signaux assumés
Le service de requêtes, searchd, est écrit en Rust avec le framework axum. Le socle de la pertinence est BM25 — un modèle probabiliste classique, documenté depuis des décennies, qui pondère les termes par leur rareté (IDF) et sature leur fréquence dans le document. Sur ce socle viennent des signaux, chacun justifiable :
- la fraîcheur : à pertinence textuelle égale, un contenu récent est favorisé, avec une décroissance douce plutôt qu'un seuil ;
- l'autorité de domaine, calculée au niveau eTLD+1 — c'est le domaine enregistrable (
exemple.org, pasblog.exemple.org) qui porte la réputation, ce qui évite qu'une myriade de sous-domaines fabrique de l'autorité artificielle ; - un plafond sur les ancres : le texte des liens entrants est un signal précieux, mais c'est aussi le vecteur historique du « google-bombing » — des milliers de liens portant la même ancre pour pousser une page sur une requête qu'elle ne mérite pas. Chez nous, la contribution des ancres est plafonnée : au-delà d'un seuil, répéter le même texte de lien n'apporte plus rien.
Aucun de ces signaux n'est un secret. C'est un choix : un classement dont on peut expliquer chaque composante est un classement qu'on peut auditer, contester et corriger.
Web, Images, Vidéos — et des panneaux de connaissance
La page de résultats propose trois onglets — Web, Images, Vidéos — alimentés par le même pipeline : les médias extraits au crawl sont dédupliqués, indexés avec leur contexte textuel, et servis par searchd comme les documents.
À droite des résultats, des panneaux de connaissance présentent les entités reconnues dans la requête — personnes, organisations, lieux. Ils sont construits à partir de Wikidata, la base de connaissances libre : les entités et leurs alias sont ingérés par le même bus, stockés dans ClickHouse, et résolus au moment de la requête. Pas de boîte noire ici non plus : chaque fiche a une source publique et vérifiable.
Pourquoi posséder son index change tout
On pourrait objecter qu'il existe des API de recherche très correctes, et qu'un métamoteur aurait coûté cent fois moins cher. C'est vrai. Mais posséder l'index change trois choses qui, pour une suite souveraine, ne sont pas négociables.
- Pas de profilage. Vos requêtes ne quittent pas l'infrastructure. Le journal de requêtes est anonyme par conception : il sert à mesurer la qualité du moteur — quels résultats sont cliqués, lesquels sont ignorés — sans identifier qui cherche. On améliore le classement, pas des profils.
- Un classement explicable. Quand un résultat remonte, nous pouvons dire pourquoi : son score textuel, sa fraîcheur, l'autorité de son domaine. Aucune position n'est vendue, aucune n'est inexplicable.
- L'indépendance. Pas d'API tierce qui change de prix, de quotas ou de conditions. Le moteur vit et évolue au rythme de la suite.
Soyons clairs sur ce que comet Search n'est pas : un concurrent de Google sur l'exhaustivité. Son index est sans commune mesure avec ceux des géants, et il le restera. Mais ce n'est pas l'objectif. L'objectif est un moteur que l'on comprend de bout en bout — de la lecture de robots.txt jusqu'au score de chaque résultat — et dont les requêtes de vos équipes ne nourrissent le modèle économique de personne. C'est une définition modeste de la recherche. C'est aussi, nous semble-t-il, la bonne.
Poursuivre la lecture
Ingénierie
Mesurer le stockage sans lire vos fichiers
Deltas d'octets idempotents, réconciliation périodique, quota en trois temps et refus structuré : comment comet mesure votre stockage sans jamais lire vos fichiers.
Produit
Orgs, équipes, sièges : le modèle Workspace de comet
Org personnelle pour chacun, organisations gratuites, sièges réellement appliqués, équipes qui pilotent l'accès aux apps et provisioning automatique : le modèle Workspace de comet.