Aller au contenu
English

Catégories de stockage

  • Leçon 3
  • 50 min
  • Module 1 : Choisir le stockage selon la charge de travail

Ce que vous saurez faire

Donnez à chaque type de données de soutien le stockage qui convient à son utilisation. Les choix sont une base de données relationnelle, le stockage objet, un cache et un index vectoriel.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 50 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • Le projet ~/projects/ticket-api, avec le petit jeu de données chargé et PostgreSQL en marche. python -m pytest affiche 34 passed (34 tests réussis). En cas de doute, exécutez python -m scripts.load --reset.

Cette leçon n’ajoute aucun fichier au projet. Vous examinez les données dans psql et dans le dossier data/ du projet.

Une bibliothèque a quatre façons de conserver les choses

Section intitulée « Une bibliothèque a quatre façons de conserver les choses »

Pensez à une bibliothèque publique. Elle conserve les choses de quatre façons différentes, parce que les gens les utilisent de quatre façons différentes.

  • Le catalogue. Une fiche pour chaque livre : titre, auteur, année, numéro de rayon. Vous pouvez lui poser plusieurs questions : « livres de cet auteur », « livres de 2024 sur les jardins ». Les fiches sont petites, et les bibliothécaires les modifient souvent.
  • Les rayons. Des rangées d’étagères avec les livres eux-mêmes. Chaque livre a un numéro de rayon. Vous ne cherchez pas directement dans les rayons. Vous trouvez le numéro dans le catalogue, puis vous prenez le livre entier.
  • Le chariot du comptoir. Les livres demandés aujourd’hui attendent près du comptoir, pour que le prochain lecteur les obtienne vite. Chaque soir, on vide le chariot. Rien n’est perdu : chaque livre a aussi sa place dans les rayons.
  • L’étagère « vous aimerez peut-être aussi ». Des livres placés ensemble parce qu’ils traitent de sujets semblables. Vous la trouvez en vous plaçant près d’un livre que vous aimez, et non grâce à un titre.

Personne ne rangerait les livres dans les tiroirs à fiches. Personne ne chercherait « tous les livres de 2024 » dans les rayons. Chaque façon convient à une tâche.

Tomás aime les réponses simples. « PostgreSQL peut tout stocker, dit-il. Une photo, c’est juste des octets, et un vecteur, c’est juste des nombres. Un seul stockage, et c’est réglé. »

Il a raison : PostgreSQL peut le faire. Mais regardez les besoins de chaque type de données. La leçon précédente a montré que les fichiers décrits par le service de soutien occuperaient 11 Go. Comparez cela avec le reste :

fichiers : les fichiers décrits par la table attachments du grand jeu de données (11 478 Mo). base de données : toute la base de données PostgreSQL (316 Mo). détails : la table attachments elle-même (17 Mo).
Description textuelle du graphique

Un diagramme à colonnes en mégaoctets. Les fichiers décrits par la table attachments : 11 478. Toute la base de données : 316. La table attachments, qui contient les détails des fichiers : 17.

Dans le petit jeu de données, une ligne de billet de soutien occupe en moyenne 219 octets (SELECT round(avg(pg_column_size(t.*))) FROM tickets t;). Un fichier moyen du grand jeu de données occupe 190 ko : autant qu’environ 900 lignes de billets. Avec les fichiers, la base de données passerait de 316 Mo à environ 12 Go. Chaque sauvegarde, chaque copie et chaque restauration transporterait ces gigaoctets, même si personne ne modifie jamais les fichiers.

L’erreur inverse pose aussi problème. Une table répond bien aux questions exactes, mais « billets semblables à celui-ci » n’est pas une question exacte. Dans psql, essayez les deux approches pour T-30002, « Double facturation pour la commande LK-182074 » :

SELECT count(*) FROM tickets WHERE subject ILIKE '%charged twice%';
count
-------
6
(1 row)

Les mots trouvent six billets avec la même expression, et rien d’autre. Exécutez maintenant la requête vectorielle de la leçon de configuration avec LIMIT 12 plutôt que LIMIT 4. Elle retourne d’abord les six mêmes billets. Viennent ensuite T-30192 « Accès à mon compte bloqué », quatre billets « Mauvais prix facturé », puis T-30021 « Code de réduction non appliqué ». La plupart décrivent des problèmes d’argent avec d’autres mots, et aucun filtre sur les mots ne les trouverait. « Proche » ne veut pas toujours dire « correct » : le client bloqué est proche seulement parce que son texte mentionne aussi une commande. Une recherche par similarité donne des candidats, pas des faits.

Un seul stockage pour tout est donc possible, mais il convient mal à au moins deux types de données.

Un stockage est tout endroit où une application conserve des données. Quatre types couvrent les besoins du service de soutien. Chacun convient à une façon de trouver les données.

Une base de données relationnelle conserve des lignes dans des tables avec des colonnes typées. Les lignes se réfèrent entre elles par des clés. « Relationnelle » vient du mot mathématique qui désigne une table, une relation. Avec SQL, vous trouvez des lignes selon n’importe quelle colonne et vous joignez des tables. Vous modifiez plusieurs lignes dans une seule transaction : tous les changements, ou aucun. PostgreSQL en est une. C’est le catalogue de la bibliothèque.

Le stockage objet conserve des fichiers, appelés objets, chacun sous un nom, appelé sa clé : par exemple tickets/T-30004/34ef…/photo-1.png. Vous déposez un objet entier et récupérez un objet entier. Il ne peut pas répondre à une question comme « fichiers des billets de facturation ouverts ». Mais il conserve plusieurs téraoctets à faible coût. Amazon S3, Azure Blob Storage et Google Cloud Storage sont des services de stockage objet. À partir du module 5, ce cours utilise Azurite, un émulateur d’Azure Blob Storage qui fonctionne sur votre ordinateur. Ce sont les rayons de la bibliothèque.

Un cache est un stockage rapide de copies de réponses, trouvées par une clé et conservées brièvement. Chaque entrée a une expiration : après celle-ci, l’entrée disparaît et la prochaine requête interroge de nouveau le stockage réel. Redis est un cache courant. Un cache peut perdre n’importe quoi à tout moment, par conception. C’est le chariot du comptoir.

Un index vectoriel conserve des vecteurs et trouve rapidement ceux qui sont les plus proches d’un vecteur donné. « Index » désigne une structure construite pour trouver les choses rapidement. Il existe des bases de données vectorielles spécialisées, comme Qdrant ou Milvus. Ce cours utilise pgvector, une extension qui ajoute des vecteurs et des index vectoriels à PostgreSQL. Les vecteurs restent ainsi près des billets qu’ils décrivent. C’est l’étagère « vous aimerez peut-être aussi ».

Un petit exemple détaillé : un billet, quatre stockages

Section intitulée « Un petit exemple détaillé : un billet, quatre stockages »

Prenez un billet et suivez ses éléments. T-30004 est un billet d’expédition résolu : « aspirateur robot non livré ». Dans psql, examinez ses fichiers joints :

SELECT file_name, content_type, size_bytes, object_key FROM attachments WHERE ticket_id = 'T-30004';
file_name | content_type | size_bytes | object_key
-----------------------+-----------------+------------+----------------------------------------------------------------------------
photo-1.png | image/png | 3508 | tickets/T-30004/34ef8e4b-458e-4c68-91a0-79728852e080/photo-1.png
receipt-LK-630122.pdf | application/pdf | 757 | tickets/T-30004/50ba0cc3-e31b-4b3b-9fe1-11a4e205d6a0/receipt-LK-630122.pdf
(2 rows)

La table contient deux petites lignes de détails. Les fichiers eux-mêmes ne sont pas dans la base de données. Dans le petit jeu de données, ils attendent dans le dossier data/small/files/ du projet, sous les mêmes clés. Dans un deuxième terminal, dans le dossier du projet :

Fenêtre de terminal
ls -l data/small/files/tickets/T-30004/*/

Sous Windows, utilisez Get-ChildItem -Recurse data\small\files\tickets\T-30004. Vous voyez photo-1.png avec 3 508 octets et receipt-LK-630122.pdf avec 757 octets : les tailles annoncées dans les détails. Les fichiers fictifs sont petits. Les vraies photos occupent des centaines de kilooctets. Le module 5 place ces fichiers dans le stockage objet.

Le reste de T-30004 se trouve dans PostgreSQL : sa ligne dans tickets, 2 messages et 2 exécutions d’IA. Ces exécutions sont une classification et un brouillon de réponse qui s’est terminé par error (erreur). Son vecteur est une ligne dans ticket_embeddings :

SELECT ticket_id, vector_dims(embedding), left(embedding::text, 60) FROM ticket_embeddings WHERE ticket_id = 'T-30004';
ticket_id | vector_dims | left
-----------+-------------+--------------------------------------------------------------
T-30004 | 384 | [0.02035228,0.01017145,-0.04077965,-0.03433716,0.07428094,-0
(1 row)

384 nombres, dont les cinq premiers sont visibles. Personne ne peut les lire, mais deux billets sur le même problème obtiennent des nombres semblables. C’est pourquoi les vecteurs les plus proches de T-30002 étaient les autres billets « Double facturation ».

Un billet utilise déjà trois stockages. Le catalogue contient sa ligne, ses messages, ses exécutions et les détails de ses fichiers. Les rayons contiennent ses deux fichiers, et l’étagère « vous aimerez peut-être aussi » contient son vecteur. Si la page du billet devenait lente, un cache pourrait conserver une copie de sa réponse pendant quelques minutes. Ce serait le quatrième stockage.

Mei dessine le tout sur une page. Chaque flèche indique comment l’API de billets accède à un stockage. Les lignes pointillées montrent quelles données se réfèrent à quelles autres.

L'API de billets, à gauche, accède à quatre stockages. La base de données relationnelle, PostgreSQL, par SQL selon n'importe quelle colonne, avec des jointures et des transactions : elle conserve les clients, les billets, les messages, les documents et ai_runs, ainsi que la table attachments avec le nom, la taille, la somme de contrôle et la clé d'objet de chaque fichier. Le stockage objet, en récupérant ou en déposant un fichier par sa clé : photos et reçus, un objet par fichier. La ligne attachments pointe vers son fichier par la clé d'objet. L'index vectoriel, pgvector dans PostgreSQL, par les vecteurs les plus proches : ticket_embeddings avec 384 nombres par billet, produits à partir du texte du billet, et un index HNSW construit à partir de ces vecteurs au module 5. Un cache, facultatif, par clé : des réponses mises en cache avec une heure d'expiration.
La carte du stockage du service de soutien : quatre types de stockage, les accès de l'API et les liens entre les données.
Description textuelle du diagramme

L’API utilise SQL pour la base de données relationnelle : n’importe quelle colonne, des jointures et des transactions. Elle récupère ou dépose un fichier entier par sa clé dans le stockage objet. Elle demande à l’index vectoriel les vecteurs les plus proches. Elle récupère une réponse en cache par sa clé. Deux liens pointillés comptent. Une ligne attachments contient la clé de son fichier dans le stockage objet. Chaque vecteur dans ticket_embeddings provient du texte d’un billet. L’index HNSW, ajouté au module 5, est construit à partir des vecteurs. Le cache est facultatif : le projet n’en a pas.

Essayez maintenant pour chaque élément de données. L’explorateur lit la carte du stockage du projet, le fichier que vous ajoutez dans la prochaine leçon.

Explorer

Où va chaque élément de données du service de soutien?

Stockage
Stockage objet
Original ou copie
Original (source de vérité)

Une photo jointe par un client va dans le stockage objet. C’est un original : aucun autre stockage ne peut le refaire.

Une photo jointe par un client
Exemplephoto-1.png sur T-30004 (créée par un programme)
StockageStockage objet : un objet par fichier; son nom, sa taille et sa somme de contrôle forment une ligne de la table attachments
Type de stockageStockage objet
Pourquoi làUn fichier est gros, et personne ne le modifie après le téléversement. La base de données garde seulement ses détails.
Comment on la litLire ou écrire un fichier entier par sa clé, par exemple tickets/T-30004/<id>/photo-1.png.
Ce stockage est mauvais pourLes questions. Il ne peut pas répondre à « quels fichiers appartiennent aux billets de facturation ouverts ? » sans base de données.
Original ou copieOriginal (source de vérité)
Combien43 fichiers (petites données); 61 853 décrits (grandes données)

Tables PostgreSQL

  • Un billet
  • Un message
  • Un document de politique
  • Une exécution d’IA

Stockage objet

  • Une photo jointe par un client (votre choix)

Cache

  • Une réponse en cache

Index vectoriel (pgvector, dans PostgreSQL)

  • Un vecteur de billet
  • L’index des billets semblables (HNSW)
Huit éléments des données de Larkfield et le stockage qui convient à chacun, tirés du fichier docs/storage-map.md du projet. Nombres : petit et grand jeux de données. L'index HNSW arrive au module 5; le projet n'a pas de cache.
Description textuelle de l’explorateur

L’explorateur a une seule commande : un bouton pour chaque élément de données. Pour chacun, il montre un exemple de Larkfield, le stockage, l’emplacement dans celui-ci et le type de stockage. Il montre aussi pourquoi les données y vont, comment lire ce stockage et ses limites. Enfin, il indique si les données sont originales ou copiées, et combien il y en a. En dessous, chaque élément de données figure sous son stockage.

Un billet, un message, un document de politique et une exécution d’IA vont dans des tables PostgreSQL (une base de données relationnelle). Chacun est un original. Une photo va dans le stockage objet. Son nom, sa taille, sa somme de contrôle et sa clé d’objet vont dans une ligne de la table attachments. Un vecteur de billet et l’index de billets semblables (HNSW) vont dans l’index vectoriel, pgvector dans PostgreSQL. Les deux sont des copies, produites à partir du texte du billet et des vecteurs. Une réponse mise en cache va dans un cache, et c’est une copie jetable.

La réponse à votre prédiction : la photo va dans le stockage objet, et ses détails dans une ligne de attachments dans PostgreSQL. La ligne permet de trouver le fichier : « les fichiers de T-30004 » est une requête SQL, et la réponse contient les clés.

Associez maintenant les groupes de l’inventaire aux stockages :

Groupe de l’inventaire Stockage Pourquoi Limites de ce stockage
Petits enregistrements avec beaucoup de requêtes : clients, billets, messages, documents, exécutions d’IA Base de données relationnelle (PostgreSQL) Réponses exactes selon n’importe quelle colonne, jointures, transactions, règles qui rejettent les données incorrectes Gros fichiers; recherche par le sens
Gros fichiers : photos et reçus Stockage objet (Azurite dans ce cours) Faible coût par gigaoctet; un fichier est écrit une fois et lu en entier Toute question sur les fichiers; elle exige les détails dans la base de données
Vecteurs : recherche par proximité Index vectoriel (pgvector, dans PostgreSQL) Trouve rapidement les vecteurs les plus proches; près des enregistrements qu’il décrit Faits exacts; chaque vecteur dépend d’un modèle et de sa version
Réponses répétées Cache (absent du projet) Répond à une question répétée sans la base de données Conserver quoi que ce soit : les entrées expirent ou disparaissent

Sam pose la question du débutant : « Donc les vecteurs sont aussi dans PostgreSQL. C’est un index vectoriel ou une base de données relationnelle? »

« Les deux, dit Mei. La catégorie dépend de la façon de trouver les données, pas du produit. pgvector donne à PostgreSQL une deuxième façon de trouver les lignes : par proximité. Un produit qui ne fait que cela est une base de données vectorielle. »

Chaque stockage ajouté entraîne un coût quotidien :

  • Un autre élément à faire fonctionner et à sécuriser : un serveur ou un service, ses utilisateurs, ses clés, ses mises à jour.
  • Un autre élément à sauvegarder et à restaurer. Une sauvegarde de PostgreSQL ne contient pas les fichiers du stockage objet. Le module 5 restaure les deux et trouve les manques.
  • Des données qui doivent concorder entre les stockages. Une ligne attachments indique qu’un fichier existe. Si le fichier manque, ou qu’un fichier n’a pas de ligne, les stockages ne concordent pas. Le module 5 recherche les deux cas.

Larkfield ajoute donc un stockage seulement quand l’inventaire le demande. Les fichiers ont clairement besoin du stockage objet : 11 Go qui ne changent jamais. Les vecteurs restent dans PostgreSQL, car 10 000 vecteurs y tiennent facilement. Les billets qu’ils décrivent sont dans la même base de données. Le module 5 compare ce choix à une base de données vectorielle spécialisée. Le cache attend qu’une mesure révèle une réponse lente demandée encore et encore. Au module 4, un index et une meilleure requête rendent la liste des billets 134 fois plus rapide, sans cache.

Le service de soutien veut trois nouvelles fonctionnalités. Pour chaque élément de données, choisissez un stockage et donnez une raison tirée de son mode d’accès :

  1. Les enregistrements vocaux des appels téléphoniques, d’environ 2 Mo chacun, conservés pendant 90 jours.
  2. Une case du tableau de bord « les dix problèmes les plus fréquents aujourd’hui », recalculée à partir des billets toutes les cinq minutes.
  3. La langue préférée de chaque client, utilisée par les agents pour filtrer.
Afficher un exemple de réponse
  1. Le stockage objet, avec une ligne de détails dans PostgreSQL : le billet de l’appel, la clé, la taille, la date. Les enregistrements sont gros, ne changent jamais et sont lus en entier. Les 90 jours sont une règle de cycle de vie (module 5).
  2. Un cache, ou une petite table qu’une tâche actualise. La réponse coûte cher à calculer et reste la même pour chaque agent. Une réponse vieille de cinq minutes convient, et une entrée perdue est recalculée.
  3. Une colonne dans la table customers (relationnelle). C’est un petit fait qui change rarement. Les agents filtrent selon ce fait : une question exacte sur une colonne.

Erreur courante

Choisir le stockage selon le produit, plutôt que selon le mode d'accès

Symptôme : une conception indique « PostgreSQL » ou « la base de données vectorielle » pour tout. Personne ne peut dire comment lire une photo, à quelle fréquence un vecteur change ou ce qui arrive quand une entrée disparaît. La base de données grossit de gigaoctets de fichiers. Ou des questions exactes vont à un stockage qui répond seulement à « qu’est-ce qui est proche ».

Cause : l’équipe a choisi le stockage d’abord, puis y a adapté les données. Personne n’a fait l’inventaire.

Diagnostic : pour chaque élément de données, posez les questions de l’inventaire. Comment est-il lu? À quelle fréquence change-t-il? Quelle quantité y a-t-il? À quel point la réponse doit-elle être récente et exacte? Demandez ensuite quelles sont les limites du stockage choisi. Si la réponse correspond au principal mode d’accès des données, le stockage ne convient pas.

Correction : partez de l’inventaire et choisissez la catégorie avant le produit. Un produit peut jouer deux rôles, comme PostgreSQL avec pgvector ici. Mais chaque rôle doit convenir à un mode d’accès.

Vérifiez votre compréhension

Nommez les quatre types de stockage et dites comment trouver les données dans chacun.

Afficher la réponse

Une base de données relationnelle : par n’importe quelle colonne avec SQL, avec des jointures et des modifications dans des transactions. Le stockage objet : un objet entier à la fois, par sa clé. Un cache : une copie d’une réponse par sa clé, jusqu’à ce que l’entrée expire ou disparaisse. Un index vectoriel : les vecteurs les plus proches d’un vecteur donné.

Vérifiez votre compréhension

Tomás dit : « PostgreSQL peut stocker des octets, alors gardons les photos dans une colonne. Un seul stockage, c'est plus simple. » Donnez deux coûts de ce choix, avec les chiffres du service de soutien.

Afficher la réponse

D’abord, la taille : les fichiers du grand jeu de données ajouteraient environ 11 Go à une base de données de 316 Mo. Elle atteindrait environ 36 fois sa taille actuelle. Chaque sauvegarde, copie et restauration transporterait ces gigaoctets, même si aucun fichier ne change jamais. Ensuite, l’incompatibilité : un fichier moyen (190 ko) occupe autant d’espace qu’environ 900 lignes de billets de soutien. Un fichier se lit en entier, par sa clé. C’est le rôle du stockage objet. La base de données n’a besoin que des détails : nom, taille, somme de contrôle et clé, soit 17 Mo au total.

Vérifiez votre compréhension

Vérification pratique : pour le billet T-30004, indiquez où chaque élément est stocké, avec la requête ou la commande qui l'affiche.

Afficher la réponse

Sa ligne : tickets (SELECT * FROM tickets WHERE ticket_id = 'T-30004';). Ses 2 messages : messages. Ses 2 exécutions d’IA : ai_runs. Les détails de ses 2 fichiers : attachments, avec les clés des objets. Ses 2 fichiers : data/small/files/tickets/T-30004/… actuellement, puis le stockage objet à partir du module 5 (ls -l data/small/files/tickets/T-30004/*/). Son vecteur : ticket_embeddings, 384 nombres (vector_dims(embedding)).

Récapitulatif

  • Une base de données relationnelle trouve des lignes par n’importe quelle colonne, avec des jointures et des transactions. Le stockage objet conserve des fichiers entiers par clé. Un cache conserve des copies de réponses jusqu’à ce qu’elles expirent. Un index vectoriel trouve les vecteurs les plus proches.
  • Un seul stockage pour tout pose deux problèmes. Les fichiers décrits (11 Go) rendraient la base de données environ 36 fois plus volumineuse. Et un filtre sur des mots ne peut pas trouver des « billets comme celui-ci ».
  • T-30004 se trouve dans trois stockages. Ses enregistrements et les détails de ses fichiers sont dans PostgreSQL. Ses fichiers vont dans le stockage objet (à partir du module 5), et son vecteur est dans pgvector.
  • Choisissez la catégorie selon le mode d’accès, puis le produit. Chaque stockage supplémentaire entraîne des coûts d’exploitation, de sécurisation, de sauvegarde et de maintien de la cohérence entre les stockages.

Ensuite : certains de ces stockages conservent les données d’origine, et d’autres conservent des copies. Vous décidez lesquels jouent chaque rôle, puis vous recréez une copie à partir de son original.

Leçon suivante : Propriété et source de vérité