« On nous a dit qu'il fallait une base vectorielle. » Pour quelques milliers de documents, MySQL et un peu de PHP font le travail sans nouvelle infra à opérer. La base vectorielle se justifie à grande échelle, pas avant.
Le stockage
CREATE TABLE doc_embedding (
id INT PRIMARY KEY AUTO_INCREMENT,
doc_id INT NOT NULL,
vector JSON NOT NULL, -- [0.012, -0.08, ...]
INDEX (doc_id)
);
La similarité cosinus en PHP
function cosine(array $a, array $b): float {
$dot = $na = $nb = 0.0;
foreach ($a as $i => $v) {
$dot += $v * $b[$i];
$na += $v * $v;
$nb += $b[$i] * $b[$i];
}
return $dot / (sqrt($na) * sqrt($nb) + 1e-9);
}
$q = embed($query); // vecteur requête
$rows = $pdo->query('SELECT doc_id, vector FROM doc_embedding')->fetchAll();
usort($rows, fn($x, $y) =>
cosine($q, json_decode($y['vector'], true))
<=> cosine($q, json_decode($x['vector'], true)));
$top = array_slice($rows, 0, 5);
Jusqu'où ça tient
| Volume | Approche | Latence recherche |
|---|---|---|
| < 10k vecteurs | MySQL + cosine PHP en RAM | quelques dizaines de ms |
| 10k – 100k | MySQL + pré-filtre SQL + cosine | 100–500 ms |
| > 100k | Base vectorielle dédiée | là c'est justifié |
L'optimisation gratuite
Charger 10k vecteurs à chaque requête est inutile : les garder en cache mémoire (APCu, ou un singleton de process worker) et ne recalculer qu'à l'ajout de documents. La recherche devient un simple parcours en RAM. Simple, debuggable, zéro nouvelle dépendance à opérer.