Accéder au contenu principal

Comment créer une application de recherche vectorielle avec MongoDB Atlas et Python

Apprenez à exécuter votre première recherche vectorielle MongoDB. Ce tutoriel vous guide pas à pas pour trouver des éléments similaires avec des embeddings et des exemples détaillés.
· 6 min lire

Explorez l'IA

Il n’y a pas si longtemps, les ordinateurs fonctionnaient comme des bibliothécaires efficaces mais très littéraux. Si vous cherchiez « combats de robots géants », ils ne retrouvaient que des titres contenant exactement ces mots. Un match parfait comme « Kaiju Mech Warfare » passait à la trappe. Les ordinateurs reconnaissaient les mots, mais manquaient la musique : pas de compréhension, pas de nuance, pas de contexte. C’était l’ère de la recherche par mots-clés, longtemps notre meilleure option.

Puis est arrivée une révolution. Inspirée du cerveau humain, l’intelligence artificielle a inventé une nouvelle façon d’apprendre. Plutôt que de mémoriser des mots, l’IA a commencé à comprendre les relations entre eux. Elle sait que « roi » est à « homme » ce que « reine » est à « femme ». Elle reconnaît que « heureux », « joyeux » et « exalté » partagent le même territoire émotionnel, tandis que « sombre » appartient à un univers tout autre.

Comment l’IA a-t-elle accompli cela ? En créant une carte du sens.

Qu’est-ce que la recherche vectorielle ? La carte du sens

Imaginez une vaste galaxie multidimensionnelle où chaque concept — un mot, une phrase, une image, une chanson — est une étoile. Dans cette galaxie, les étoiles aux significations proches forment des amas, tandis que les autres sont à des années-lumière.

Un vector embedding n’est rien d’autre que la coordonnée d’une étoile dans cette galaxie. C’est une liste de nombres (par ex. [0.12, -0.45, 0.89, ...]) qui localise précisément un concept sur cette carte du sens.

Vector search est la capacité révolutionnaire à naviguer sur cette carte. Lorsque vous demandez « un film sur un garçon orphelin qui découvre qu’il est sorcier », nous ne cherchons pas ces mots exacts. À la place, nous :

  1. Trouvons la coordonnée (le vecteur) de votre requête sur la carte.
  2. Repérons les étoiles voisines les plus proches (nos intrigues de films).

Les étoiles les plus proches représentent les résultats les plus similaires sur le plan sémantique. C’est ainsi que l’IA est passée d’un bibliothécaire littéral à un conseiller avisé qui comprend ce que vous voulez vraiment dire.

Pourquoi est-ce si important ?

La recherche par le sens plutôt que par mots-clés alimente des applications d’IA modernes dans tous les secteurs. Cette capacité permet :

  • Netflix de recommander des films inconnus qui partagent la même « ambiance » que votre historique de visionnage.
  • Spotify de composer des playlists avec des morceaux qui sonnent comme vos favoris, quel que soit le genre ou l’époque.
  • Des chatbots et des LLM de saisir l’intention derrière vos questions et de fournir des réponses pertinentes et contextualisées.
  • Les sites e-commerce d’afficher des produits visuellement similaires aux images que vous téléchargez.

La recherche vectorielle fait le lien entre l’intention humaine et les données numériques, transformant en profondeur notre façon d’interagir avec l’information. Cette technologie rend les systèmes numériques moins mécaniques et plus proches de collaborateurs intuitifs.

Apprenons : créer votre première application de recherche vectorielle avec MongoDB

Bienvenue dans la nouvelle frontière de la recherche ! MongoDB a introduit la Vector Search dans Atlas. Vous pouvez ainsi stocker et interroger des embeddings vectoriels (issus de texte, d’images ou d’audio) directement dans MongoDB — inutile d’utiliser une base vectorielle séparée comme Pinecone ou Weaviate.

Dans ce tutoriel, nous allons créer un moteur de recommandation de chaussures simple mais puissant avec Python et MongoDB Atlas. Vous apprendrez à transformer du texte en représentations numériques porteuses de sens (vecteurs), puis à utiliser la Vector Search d’Atlas pour trouver des films aux intrigues similaires.

Ce que vous allez apprendre

  • Comment vous connecter en toute sécurité à un cluster MongoDB Atlas avec la bibliothèque pymongo de Python.
  • Comment créer et insérer des documents contenant des embeddings vectoriels.
  • Comment générer des embeddings à partir de texte avec la bibliothèque sentence-transformers.
  • Comment créer un index de Vector Search dans l’interface MongoDB Atlas.
  • Comment effectuer une requête de recherche sémantique avec l’étape d’agrégation $vectorSearch.

Prérequis

pip install pymongo sentence-transformers numpy

Étape 1 : créer un cluster MongoDB Atlas

  • Connectez-vous à Atlas.

  • Créez un cluster gratuit. Créez un utilisateur et copiez son nom d’utilisateur et son mot de passe.

  • Après avoir créé l’utilisateur, cliquez sur Choose a connection method. Vous verrez le premier écran ci-dessous. Cliquez sur Drivers pour accéder au second écran. Sélectionnez Python comme driver et la version appropriée. Copiez la chaîne de connexion.

Choose Cluster Connection Method

Select Driver and version

  • Allez dans Database Deployments → Cliquez sur Browse Collections → Créez une nouvelle base de données :
    • Nom de la base : vectorDemo
    • Nom de la collection : items

MongoDB: Create new database and collection image

  • Activez la Vector Search :
    • Dans l’interface MongoDB Atlas, allez à Vector Search Indexes → Créez un nouvel index pour items.
    • Nom de l’index : « vector_index »
    • Utilisez cette définition :
{
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 768,
      "similarity": "cosine"
    }
  ]
}

Remarque : 768 est la taille des embeddings que nous utiliserons avec le modèle sentence-transformers.

MongoDB: Create Vector Search Index

Comprendre la définition de l’index :

  • "type": "vector" : indique à MongoDB Atlas qu’il s’agit d’un index vectoriel.
  • "path": "embedding" : c’est le champ de nos documents qui contient les vecteurs — un point crucial.
  • "numDimensions" : 768 : ce paramètre doit correspondre à la dimension des vecteurs produits par notre modèle.
  • "similarity" : "cosine" : l’algorithme qui mesure la « proximité » des vecteurs. Idéal pour la similarité basée sur du texte.

Étape 2 : connecter Python à MongoDB Atlas

Récupérez votre chaîne de connexion MongoDB Atlas :

  • Dans MongoDB Atlas, cliquez sur Connect → Drivers → Python.
  • Remplacez <username>, <password> et <cluster-url> dans l’extrait ci-dessous.
from pymongo import MongoClient

# Replace with your Atlas connection string
uri = "mongodb+srv://<username>:<password>@<cluster-url>/vectorDemo?retryWrites=true&w=majority"

client = MongoClient(uri)
db = client["vectorDemo"]
collection = db["items"]
print("Connected to MongoDB Atlas")

# Clear existing
collection.delete_many({})
print("Cleared collection.")

Étape 3 : générer des embeddings avec Python

Nous allons utiliser SentenceTransformers pour convertir le texte en embeddings.

from sentence_transformers import SentenceTransformer
# Choose model: higher-quality for search -> "sentence-transformers/all-mpnet-base-v2" (768-d)
# If you need faster/smaller: "all-MiniLM-L6-v2" (384-d)
MODEL_NAME = "sentence-transformers/all-mpnet-base-v2"
# MODEL_NAME = "all-MiniLM-L6-v2"

# Note: if you use all-mpnet-base-v2, your Atlas vector index must use numDimensions: 768
# If you use all-MiniLM-L6-v2, index numDimensions: 384
model = SentenceTransformer(MODEL_NAME)

def embed_text(text: str):
    return model.encode(text).tolist()

Étape 4 : insérer des documents d’exemple avec embeddings

Stockons des descriptions de produits dans MongoDB avec leurs embeddings.

# Each product includes name, description, list of features, use_cases and tags.
products = [
    # Marathon / long-distance running (explicit!)
    {
        "name": "MarathonPro 3000",
        "description": "Designed specifically for marathon and ultra distance running: maximum cushioning, breathable knit upper, responsive midsole and engineered heel support for long-run comfort.",
        "features": ["marathon", "long-distance", "max cushioning", "breathable", "support"],
        "category": "shoes",
        "use_cases": ["marathon", "long-distance running", "road running"],
        "tags": ["running", "endurance", "comfort"]
    },
    {
        "name": "Enduro LongRun",
        "description": "Lightweight long-run trainer optimized for marathon pacing with added cushioning, stable platform, and enhanced forefoot energy return for hours of comfortable running.",
        "features": ["long-run", "lightweight", "energy return", "cushioning"],
        "category": "shoes",
        "use_cases": ["marathon", "road running"],
        "tags": ["running","marathon","comfort"]
    },

    # Road running / neutral
    {
        "name": "Red Road Runner",
        "description": "Neutral road running shoe for daily training: breathable mesh, moderate cushioning and responsive ride; suitable for tempo runs and long easy runs.",
        "features": ["road running", "breathable", "moderate cushioning"],
        "category": "shoes",
        "use_cases": ["training", "road running", "tempo runs"],
        "tags": ["running","training"]
    },

    # Trail running (explicit trail)
    {
        "name": "TrailMaster RidgeGrip",
        "description": "Trail-running shoe with aggressive outsole, rock plate for protection, waterproof upper, designed for technical trails and rugged terrain.",
        "features": ["trail", "high grip", "rock plate", "waterproof"],
        "category": "shoes",
        "use_cases": ["trail running", "hiking", "off-road"],
        "tags": ["trail","outdoors"]
    },

    # Tennis & court
    {
        "name": "CourtPro Tennis",
        "description": "Court shoe with lateral support, non-marking sole and reinforced toe; built for tennis footwork and short intense bursts, not for long-distance running.",
        "features": ["court", "lateral support", "non-marking sole"],
        "category": "shoes",
        "use_cases": ["tennis","court sports"],
        "tags": ["tennis","sport"]
    },

    # Formal
    {
        "name": "Oxford Leather Formal",
        "description": "Classic leather formal shoe for office and events: polished leather, sturdy sole, refined silhouette.",
        "features": ["formal", "leather", "office"],
        "category": "shoes",
        "use_cases": ["formal wear","office"],
        "tags": ["formal","leather"]
    },

    # Hiking
    {
        "name": "Alpine Trek Boots",
        "description": "High-ankle hiking boots with waterproof membrane, ankle support and durable lugged outsole for mountain treks.",
        "features": ["hiking", "waterproof", "ankle support", "lugged outsole"],
        "category": "shoes",
        "use_cases": ["hiking","trekking","outdoor"],
        "tags": ["outdoors","hiking"]
    },

    # Casual sneakers
    {
        "name": "Classic Canvas Sneaker",
        "description": "Casual everyday canvas sneaker with rubber sole, comfortable fit for daily wear and walking.",
        "features": ["casual","canvas", "everyday"],
        "category": "shoes",
        "use_cases": ["casual","walking"],
        "tags": ["casual"]
    },

    # Cross-trainer
    {
        "name": "CrossFit Trainer",
        "description": "Stable cross-trainer shoe engineered for gym workouts, short sprints, and lateral movements; flexible yet supportive.",
        "features": ["cross-train","stable","gym"],
        "category": "shoes",
        "use_cases": ["gym","cross-training"],
        "tags": ["training","gym"]
    },

    # Cleats
    {
        "name": "Pro Soccer Cleats",
        "description": "Low-profile football/soccer cleats with studded outsole; optimized for grip on grass and agility.",
        "features": ["cleats","studs","agility"],
        "category": "shoes",
        "use_cases": ["soccer","football"],
        "tags": ["sports","cleats"]
    }
]

# ---------- Create 'canonical_text' to improve embedding quality for better scoring ----------
for p in products:
    # join features and others into one rich text blob
    features = ", ".join(p["features"])
    uses = ", ".join(p["use_cases"])
    tags = ", ".join(p["tags"])
    canonical = f"{p['name']}. {p['description']}. Features: {features}. Use cases: {uses}. Tags: {tags}."
    p["canonical_text"] = canonical

# ---------- Embed canonical_text----------
print("Embedding items...")
for p in products:
    p["embedding"] = embed_text(p["canonical_text"])

# ---------- Insert into MongoDB ----------
collection.insert_many(products)

Avec insert_many, nous effectuons une écriture groupée unique et efficace dans la base.

Étape 5 : exécuter votre première recherche vectorielle

Place à l’étape finale — et la plus enthousiasmante ! Nous allons utiliser le framework d’agrégation de MongoDB et $vectorSearch — un opérateur pour trouver les meilleures chaussures correspondant à la requête.

query_text = "25k long running best shoes"
query_embedding = embed_text(query_text)

pipeline = [
    {
        "$vectorSearch": {
            "index": "vector_index",  # Use the vector search index you created
            "path": "embedding",
            "queryVector": query_embedding,
            "numCandidates": 100,
            "limit": 3
        }
    },
    {
        "$project": {
            "name": 1,
            "description":1,
            "score": {"$meta": "vectorSearchScore"}
        }
    }
]

results = collection.aggregate(pipeline)

print(f"\nSearch results for: '{query_text}'\n")
for r in results:
    print(f"- {r['name']} (score: {r['score']:.4f})")

Disséquer le pipeline $vectorSearch :

  • $vectorSearch : c’est l’opérateur central. Il compare efficacement notre queryVector au champ indexé plot_embedding de tous les documents.
  • $project : cette étape remodèle la sortie. Nous incluons le name et la description, excluons l’_id et d’autres champs « bruités », et surtout, nous ajoutons un champ score via $meta: "vectorSearchScore". Ce score, de 0 à 1, indique la similarité du résultat avec notre requête.

Sortie attendue

Si tout est correctement configuré, vous verrez quelque chose comme ceci :

Search results for: '25k long running best shoes'

- MarathonPro 3000 (score: 0.7980)
- Red Road Runner (score: 0.7479)
- Enduro LongRun (score: 0.7389)

Remarquez que « MarathonPro 3000 » arrive en tête — exactement ce à quoi nous nous attendions.

Félicitations ! Vous avez construit de bout en bout une application de recherche vectorielle. Vous avez appris à vous connecter à une base de données, créer et valider des données, générer des embeddings et tirer parti de MongoDB Atlas pour retrouver l’information de manière réellement intelligente. Bienvenue dans le futur de l’interaction avec les données.

Conclusion

Dans ce tutoriel, vous avez appris à :

  • Vous connecter à MongoDB Atlas avec Python et pymongo — la base de toute application pilotée par une base de données.
  • Créer des embeddings (texte uniquement) à partir d’un catalogue produit réaliste avec des modèles de haute qualité comme all-mpnet-base-v2, puis à les stocker dans MongoDB avec une bonne normalisation.
  • Constituer un jeu de données riche et structuré à l’aide de canonical_text (nom, description, fonctionnalités, cas d’usage, tags), ce qui améliore la pertinence des embeddings.
  • Effectuer des recherches de similarité vectorielle avec l’étape d’agrégation $vectorSearch de MongoDB pour trouver des produits sémantiquement proches à partir de requêtes en langage naturel.

Prochaines étapes (à vous de jouer)

  • Stockez des avis utilisateurs et construisez un moteur de recherche sémantique.

Expérimentez avec différentes métriques de similarité (dotProduct, euclidean).

FAQs

Pourquoi canonical_text est-il plus riche qu’une simple description produit ?

canonical_text inclut les fonctionnalités, cas d’usage et tags afin d’apporter plus de contexte aux embeddings — ce qui aide le modèle à mieux capter l’intention de l’utilisateur en recherche vectorielle.

Pourquoi avoir choisi all-mpnet-base-v2 plutôt que MiniLM ou CLIP ?

all-mpnet-base-v2 (768 dim) offre de meilleures représentations sémantiques pour des similarités texte seules comparé aux modèles légers (384 dim). CLIP excelle en multimodal, mais est moins précis pour des requêtes texte nuancées.

Cette approche passe-t-elle à l’échelle sur de grands jeux de données ?

Oui ! MongoDB Atlas prend en charge des index vectoriels avec des millions de documents. À grande échelle, affiner les paramètres d’index (par ex. numCandidates) et réappliquer un re-ranking uniquement sur le top‑N maintient d’excellentes performances.

Et si je veux ensuite une recherche multimodale (texte + image) ?

Vous pouvez passer à un modèle d’embedding multimodal (comme CLIP ou des alternatives open source), normaliser les embeddings, les stocker de la même façon, puis utiliser la même stratégie recherche vectorielle + re-ranking pour une recherche sur médias mixtes.

Comment choisir la dimension du modèle à utiliser ?

Des dimensions plus élevées (par ex. 512, 768, 1024, 2056) capturent généralement mieux la sémantique, au prix d’un stockage et d’un calcul accrus. Utilisez des modèles plus petits (384) pour la vitesse ou l’expérimentation, et passez à 768 quand la précision prime.

Puis-je combiner recherche vectorielle et recherche full‑text ?

Absolument. MongoDB Atlas vous permet de combiner une étape $search avec des requêtes compound — en mélangeant des filtres full‑text BM25 avec knnBeta ou $vectorSearch — pour des expériences de recherche hybrides riches.

Nilesh Soni

Auteur

Nilesh Soni

Ingénieur logiciel senior chez Uber

Sujets

Contenus associés

Tutoriel

Tableaux Python

Tutoriel

Données JSON Python : Un guide illustré d'exemples