01 · Vespa comme moteur dédié
Objectif. Utiliser un moteur qui prend en charge l’indexation, les requêtes YQL et le classement, avec une trajectoire possible vers la recherche vectorielle et hybride. Le service Python reste responsable du contrat d’accès ; il ne réimplémente pas un index inversé.
Compromis. Pour dix fiches, SQLite FTS ou un index embarqué suffiraient avec une empreinte plus faible. Vespa est choisi pour explorer l’exploitation d’un moteur de recherche et ses paramètres, en cohérence avec le poste visé. Ce POC ne prouve aucune supériorité sur Elasticsearch ou OpenSearch.
À l’échelle. Mesurer d’abord le débit d’indexation, la taille des index et les latences sous charge mixte. Déterminer ensuite le partitionnement et la réplication à partir du volume, des objectifs de disponibilité et du temps de reconstruction acceptable.
02 · BM25 avant la recherche hybride
Objectif. Disposer d’une référence lexicale simple. BM25 utilise notamment la fréquence des termes, leur rareté dans le corpus et la longueur des documents. La référence est 2 × BM25(title) + BM25(body). Les variantes font varier le poids du titre, saturent les contributions, ou ajoutent des signaux de couverture et de proximité. Les deux derniers profils reclassent les 50 meilleurs candidats BM25 par nœud en seconde phase.
Traitement du français. La langue est fixée à fr à l’indexation et dans les requêtes pour appliquer le même traitement linguistique aux titres, aux textes et aux recherches courtes.
Compromis. Le facteur 2 est une heuristique du prototype, pas le résultat d’une optimisation. La recherche lexicale peut manquer un synonyme ou une reformulation. Le score sert à classer une liste ; il n’est ni une probabilité ni une mesure comparable entre toutes les requêtes.
À l’échelle. Constituer des requêtes annotées, mesurer nDCG@10 et le rappel, puis comparer lexical, vectoriel et hybride avec le même corpus. Publier aussi leur coût mémoire, CPU et latence : un meilleur classement peut coûter plus cher à servir.
03 · Un adaptateur commun pour HTTP et MCP
Objectif. Centraliser la validation utile à la recherche, les limites, les appels à Vespa et la forme des résultats. FastAPI sert le navigateur ; le SDK MCP officiel expose les mêmes capacités aux agents. Modifier la recherche ne nécessite pas deux implémentations parallèles.
Compromis. Le client HTTP vers Vespa est synchrone et les recherches sont bornées par processus. Ce choix garde le code court pour le faible trafic attendu ; il impose de maîtriser le nombre de workers et de threads. Le SDK MCP transforme les erreurs d’outil dans son propre protocole, tandis que l’API utilise des statuts HTTP.
À l’échelle. Séparer le contrat métier des transports, conserver des tests de parité et dimensionner les connexions sortantes. Une évolution asynchrone peut aider pour de nombreuses attentes réseau ; elle ne supprime pas le besoin de contrôler le travail admis.
04 · Concurrence, délais et surcharge explicites
Objectif. Éviter qu’un afflux de requêtes transforme la saturation de Vespa en une file d’attente sans fin. Le sémaphore autorise huit recherches simultanées ; les suivantes échouent rapidement. Les requêtes sont limitées à 256 caractères et dix résultats.
Compromis. Cette limite est locale à un processus. Deux workers autoriseraient jusqu’à seize recherches, ce qui changerait le budget global. Le délai Vespa de 2 s et les délais du client HTTP réduisent l’attente, mais ne constituent pas une garantie absolue de latence de bout en bout. La lecture d’une fiche utilise le pool de connexions sans sémaphore distinct.
À l’échelle. Définir un objectif de latence et de disponibilité, puis introduire quotas par usage, files bornées, délais de bout en bout et reprises avec temporisation. Éviter les reprises immédiates et illimitées qui aggravent la surcharge.
05 · Ingestion continue et reprise après interruption
Objectif. Le flux SSE Wikimedia signale les modifications. Le collecteur filtre les articles français, enregistre leur titre dans une file SQLite persistante, puis récupère l’introduction actuelle auprès de MediaWiki. Un seul worker écrit dans Vespa, au maximum une requête source toutes les deux secondes.
Reprise. L’identifiant de reprise du flux et l’ajout à la file sont validés dans la même transaction. Une tâche est retirée après l’écriture réussie dans Vespa. Une panne entre ces deux opérations rejoue la même écriture sous le même identifiant de page : la livraison est au moins une fois, avec des remplacements idempotents. Un événement arrivé pendant l’écriture reste en attente.
Mises à jour et suppressions. Le collecteur relit l’état actuel plutôt que d’appliquer aveuglément un ancien événement. Il refuse une révision inférieure à celle connue. Une page disparue ou sortie de l’espace des articles est retirée de l’index. Une vérification périodique corrige aussi les événements manqués : une page toutes les 30 secondes, soit environ 17 heures pour 2 000 pages sans retards.
Compromis. La file est plafonnée à 1 000 titres et le registre à 2 000 identifiants de pages, y compris les pages supprimées. Le filtrage du flux public est local. Le serveur conserve les événements pendant une durée limitée ; une reprise expirée repart du flux courant et s’appuie sur la réconciliation. Le corpus n’est pas un instantané immuable. Les délais affichés mesurent l’attente depuis la mise en file, pas un engagement de fraîcheur de la source.
Provenance. Les introductions sont limitées à 12 000 caractères, sans HTML. Chaque document contient sa révision, un lien vers la source et son historique. Les noms des contributeurs reçus dans le flux ne sont pas stockés. Licence CC BY-SA 4.0 ↗
06 · Une VM et des volumes persistants
Objectif. Rendre la démo facile à reproduire sur une VM de 4 Go. Compose décrit les services et leurs dépendances. Les conteneurs peuvent être recréés ; les volumes conservent l’index Vespa et les compteurs analytics.
Compromis. Un seul hôte reste un point de défaillance unique. Le profil plafonne Vespa à 2 560 Mio, l’API à 384 Mio, l’initialisation à 256 Mio, le proxy, les analytics et le collecteur à 128 Mio chacun. Le mode mémoire réduite et les tas JVM bornés conviennent à ce minuscule corpus ; ils ne représentent pas une recommandation de production.
À l’échelle. Définir les domaines de panne, les sauvegardes et leurs tests de restauration avant de multiplier les nœuds. Ne pas confondre persistance, sauvegarde et réplication. Kubernetes devient utile si les besoins d’exploitation justifient son coût ; il ne remplace pas ces décisions.
07 · Déploiement vérifié, sans retour arrière automatique
Objectif. Déployer le commit qui vient de passer les tests. Le workflow contrôle les contrats API/MCP, démarre Vespa avec le profil mémoire, puis utilise une clé SSH dédiée et une identité serveur connue pour transférer le code sur la VM.
Compromis. Les contrôles locaux ne suffisent pas : le workflow teste aussi l’URL depuis GitHub pour détecter les problèmes de proxy ou de réseau. La reconstruction et le remplacement des services peuvent provoquer une interruption. Une modification de schéma ou de données ne s’annule pas simplement en réinstallant l’ancien code.
À l’échelle. Épingler les images par digest, verrouiller les dépendances transitives, versionner les migrations et définir une stratégie de retour arrière. Tester la restauration et les déploiements progressifs avant de promettre une disponibilité élevée.
08 · SQLite pour des analytics privées et agrégées
Objectif. Suivre l’usage du POC avec peu de ressources et sans prestataire externe. La base ne contient que la date UTC, la section, la campagne, le type d’événement et son compteur. Les incréments sont transactionnels ; le mode WAL facilite la coexistence de lectures et d’écritures.
Compromis. Les événements viennent du navigateur et peuvent être dupliqués ou artificiels. Un tag de campagne décrit le lien partagé, pas l’identité du visiteur. Les jours hors de la fenêtre de 30 jours sont purgés lors des accès. Le tableau de bord écoute sur un service séparé, publié uniquement sur la boucle locale de la VM, accessible par tunnel SSH.
À l’échelle. Définir les métriques nécessaires avant d’ajouter des données. Séparer télémétrie produit et mesures de fiabilité ; instrumenter les histogrammes de latence, la saturation et les erreurs sans enregistrer les requêtes ou les identités des visiteurs.
09 · Plusieurs sources, un contrat de document et des lots reprenables
Objectif. Dix connecteurs produisent des fiches et observations bornées : entités Wikidata, protéines UniProt, matériaux Materials Project, notices OpenAlex et OpenAIRE, séries Eurostat, Banque mondiale, FMI et OCDE, catalogue data.gouv.fr. La recherche commune reste lexicale ; une observation statistique conserve ses dimensions, sa période, son unité et sa valeur dans un JSON consultable.
Reprise. Un lot normalisé est enregistré dans SQLite avant toute écriture. Les identifiants natifs déterminent des IDs stables propres à chaque source. Après interruption, le même lot est rejoué avant toute nouvelle collecte. Les anciennes fiches de l’échantillon sont retirées seulement après l’écriture complète du nouveau lot. Il n’y a pas de transaction atomique couvrant SQLite et Vespa : une génération partielle peut être visible pendant sa reprise.
Ressources et erreurs. Réponses limitées à 4 Mo, maximum de 50 documents par source et collectes séquentielles. Les collectes réussies sont espacées de 24 h ; les erreurs ont une temporisation exponentielle plafonnée à une heure. Materials Project reste signalé « clé requise » tant que la clé n’est pas configurée. Un échec ne supprime pas la dernière copie réussie et ne bloque pas les autres sources.
Limites. Les graphes complets ne sont pas hébergés, les fichiers des portails et les textes intégraux ne sont pas collectés, un petit graphe RDF versionné complète ces fiches dans le laboratoire SPARQL. Les champs textuels restent analysés en français : les titres et noms scientifiques en anglais peuvent nécessiter des requêtes dans leur langue d’origine. Les séries statistiques décrivent le millésime récupéré, qui peut comporter estimations et révisions.
10 · YQL et SPARQL : admission explicite et exécution observable
Objectif. Le laboratoire de requêtes propose sept scénarios réels : recherche et agrégation sur Vespa, jointures et parcours sur un petit instantané RDF Wikidata. Les outils MCP query_index et query_graph utilisent les mêmes contrats que HTTP.
Admission. Le serveur reconstruit chaque requête depuis des paramètres validés. Le texte soumis doit correspondre exactement au modèle. Les écritures, la fédération externe et les parcours non bornés sont absents des modèles acceptés. Ce mécanisme ne valide pas toutes les requêtes YQL ou SPARQL possibles.
Exécution. Deux exécutions simultanées au maximum ; Vespa reçoit un délai de 2 secondes. Chaque requête SPARQL utilise un processus jetable arrêté après 3 secondes, sur un graphe de moins de 2 000 triplets. Les réponses affichent le texte, la durée et la provenance. Le SHA-256 et les révisions Wikidata identifient le graphe ; celui-ci est distinct du corpus vivant et renouvelé explicitement par un commit.
Limites. Les temps SPARQL incluent le démarrage du processus et le chargement du graphe. Les modèles fixes et le petit corpus rendent la démonstration reproductible ; ils ne prouvent pas le fonctionnement à grande échelle ni une isolation de requêtes arbitraires.