Vai al contenuto principale

Come cercare immagini e testo con MongoDB Vector Search e FastAPI

Crea un'app end-to-end di vector search con FastAPI e MongoDB Atlas. Impara a generare, archiviare e interrogare embedding di testo e immagini in questo tutorial pratico.
Aggiornato 29 set 2026  · 10 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

La ricerca basata su keyword funziona bene per le ricerche semplici, ma va rapidamente in crisi quando conta il significato più che le parole esatte. Se un documento parla di “aumentare i tempi di risposta” e un altro di “migliorare le prestazioni”, un motore di ricerca tradizionale li considera non correlati, anche se descrivono la stessa idea. Perdiamo le relazioni semantiche solo perché la formulazione è diversa.

La vector search risolve questo limite rappresentando testi e immagini come embedding: vettori numerici generati da modelli di machine learning che catturano contesto, intento e similarità semantica. Una volta archiviati questi embedding in MongoDB, possiamo interrogarli per trovare elementi davvero correlati, indipendentemente dai termini esatti utilizzati.

In questo tutorial costruiremo un esempio pratico end-to-end di questo flusso usando FastAPI e MongoDB Atlas Vector Search. Genereremo embedding di testo con SentenceTransformers e embedding di immagini con un modello basato su CLIP, li archivieremo in MongoDB ed eseguiremo ricerche per similarità su entrambi. Alla fine avrai una base funzionante che può supportare ricerca semantica di articoli, raccomandazioni di prodotti, strumenti per similarità visiva e molte altre applicazioni reali.

Detto questo, iniziamo.

Prerequisiti

Prima di costruire, ci servono alcune cose. Questo tutorial presume una familiarità di base con Python, FastAPI e MongoDB, ma non useremo nulla di avanzato: tutto ciò che serve verrà introdotto lungo il percorso.

Ecco cosa ci serve:

  • Python 3.10+
  • Un cluster MongoDB Atlas con Vector Search abilitata
  • Ambiente FastAPI
  • Postman o cURL
  • Accesso a Internet per scaricare modelli ed embedding

Librerie Python che useremo

Le installeremo durante il setup:

  • FastAPI: il nostro web framework
  • uvicorn: server di sviluppo
  • pymongo: driver MongoDB
  • sentence-transformers: modello di embedding testuale
  • open_clip: modello di embedding di immagini basato su CLIP
  • torch: richiesto da CLIP e SentenceTransformers
  • Pillow: supporto per l'elaborazione di immagini (PIL)

Questi strumenti ci danno tutto il necessario per generare embedding, archiviarli in MongoDB e interrogarli in modo efficiente con la vector search.

Capire la Vector Search

Prima di scrivere codice, è utile capire cosa succede davvero sotto il cofano. La vector search non è complicata una volta scomposta; conoscere le basi rende il resto del tutorial molto più facile da seguire.

Cos'è un embedding?

Un embedding è semplicemente un elenco di numeri (un vettore) che rappresenta il significato di un dato.

Per il testo, l'embedding cattura elementi come contesto e intento. Per le immagini, cattura pattern e caratteristiche visive.

Un esempio molto semplificato di embedding è questo:

[0.21, -0.17, 0.89, ...]

Due elementi semanticamente simili—per esempio, due frasi che descrivono la stessa idea o due immagini con oggetti simili—avranno vettori matematicamente vicini. La vector search misura proprio questa vicinanza.

Come MongoDB usa gli embedding

MongoDB in sé non genera embedding. Invece, si concentra su ciò che fa meglio:

  • Archiviare vettori di embedding
  • Indicizzarli usando un vector index
  • Recuperare in modo efficiente i vicini più prossimi

In altre parole, i nostri modelli generano gli embedding e MongoDB gestisce la ricerca.

Questa separazione netta rende il sistema sia flessibile sia scalabile.

Tipi di modelli di embedding

Possiamo scegliere qualsiasi modello di embedding, purché produca un vettore numerico. Modelli diversi sono specializzati per diversi tipi di dati:

Tipo di dato

Modello di esempio

Note

Testo

all-MiniLM-L6-v2

Leggero e molto usato per NLP

Immagine

CLIP/OpenCLIP

Converte le immagini in vettori semantici

Multimodale

Multimodale

Gestisce testo e immagini insieme

Questo è il workflow che implementeremo con FastAPI e MongoDB Atlas.

Una volta configurato, potremo cercare testi e immagini per significato—qualcosa che la ricerca per keyword tradizionale non può fare.

Configurare MongoDB Atlas

Prima di costruire l'applicazione FastAPI, ci serve un posto dove archiviare e interrogare i nostri embedding. MongoDB Atlas lo rende semplice, e creare indici vettoriali richiede solo pochi minuti.

1. Crea un cluster

Se non ne hai già uno, crea un nuovo cluster in MongoDB Atlas. Un cluster free-tier (M0) va benissimo per questo tutorial. Consulta la documentazione MongoDB per maggiori dettagli su come creare un cluster.

2. Crea un database e le collection

All'interno del cluster:

  1. Crea un database. Lo chiameremo vector_db. Per maggiori dettagli, vedi la documentazione.
  2. Crea due collection al suo interno:
    • texts: dove archiviare i documenti di testo e i loro embedding
    • images: dove archiviare i nomi file e gli embedding delle immagini

Consulta la documentazione per maggiori dettagli su come creare una collection.

Abbiamo separato la collection delle immagini da quella dei testi perché usano modelli di embedding e dimensioni dei vettori differenti.

3. Crea gli indici vettoriali

MongoDB ha bisogno di un vector index per eseguire ricerche per similarità veloci. Creeremo un indice per gli embedding di testo e uno per gli embedding di immagini.

Puoi crearli in Atlas → Collections → Search Indexes. Iniziamo configurando la collection dei testi.

L'immagine seguente spiega meglio il processo.

Dashboard di MongoDB Atlas che spiega il processo per creare un search index

Nella schermata successiva, fai clic su Vector Search ->JSON Editor -> Next. L'immagine seguente ti aiuterà a capire meglio il processo

Dashboard di MongoDB Atlas che spiega il processo per creare un search index. Fase uno del processo.

Dashboard di MongoDB Atlas che spiega il processo per creare un search index. Fase due del processo.

Indice vettoriale per il testo

Nel vector search index, modifica il testo JSON per allinearlo al nostro codice.

Usiamo il modello all-MiniLM-L6-v2 per il testo, che produce embedding a 384 dimensioni.

Ecco la definizione JSON:

{
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 384,
      "similarity": "cosine"
    }
  ]
}

Dai a questo indice un nome: vector_texts_search e salva.

Questo consente a MongoDB di eseguire ricerche con similarità coseno sugli embedding testuali. L'immagine sotto illustra il processo più nel dettaglio.Dashboard di MongoDB Atlas che spiega il processo per creare un search index. Fase tre del processo.

Image contains a JSON text editor for the JSON definition of the text search.

Indice vettoriale per le immagini

Per le immagini, usiamo un modello basato su CLIP che produce vettori a 512 dimensioni, quindi l'indice per le immagini deve rispecchiare quella dimensione. La definizione JSON deve corrispondere al codice qui sotto. A parte questo, il resto del flusso è identico.

{
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 512,
      "similarity": "cosine"
    }
  ]
}

Dai a questo indice il nome: vector_images_search.

Una volta che entrambi gli indici sono attivi, MongoDB Atlas è pronto per le query di vector search.

Configurare il progetto FastAPI

Ora che il cluster MongoDB Atlas e gli indici vettoriali sono pronti, possiamo configurare l'app FastAPI che genererà gli embedding e li archivierà in MongoDB. Terremo la struttura del progetto piccola e focalizzata, dato che l'obiettivo è capire il flusso più che costruire un servizio production-ready completo.

1. Installa le dipendenze necessarie

Installeremo FastAPI, Uvicorn, il driver Python per MongoDB e le librerie necessarie per generare embedding di testo e immagini. Esegui:

pip install fastapi uvicorn pymongo python-dotenv sentence-transformers torch pillow open_clip_torch python-multipart

Breve panoramica del perché ci servono:

  • fastapi—il nostro framework API
  • uvicorn—server ASGI per eseguire FastAPI
  • pymongo—driver MongoDB
  • python-dotenv—carica le variabili d'ambiente da .env
  • sentence-transformers—modello per embedding testuali
  • torch—richiesto dai modelli di embedding
  • pillow—gestione base delle immagini
  • open_clip_torch—modello di embedding di immagini basato su CLIP
  • python-multipart—necessario per caricare file tramite FastAPI

Una volta installato tutto, possiamo impostare il progetto.

2. Struttura del progetto

Terremo tutto in un unico file Python, con la configurazione gestita tramite variabili d'ambiente:

fastapi-mongodb-vector-search/
│── main.py
│── .env
│── venv/

main.py conterrà l'intera applicazione: gli endpoint per il testo, quelli per le immagini e la connessione a MongoDB.

MONGODB_URI="your connection string"
DB_NAME="vector_db"
TEXT_COLLECTION="texts"
IMAGE_COLLECTION="images"
  • MONGODB_URI—l'URI Atlas del tuo cluster
  • DB_NAME—il database che abbiamo creato
  • TEXT_COLLECTION—dove verranno archiviati testo + embedding
  • IMAGE_COLLECTION—dove verranno salvati gli embedding delle immagini

FastAPI caricherà questi valori all'avvio dell'app, mantenendo la configurazione separata dal codice.

Implementare la ricerca testuale

Con il progetto FastAPI configurato, possiamo partire costruendo il flusso per la ricerca testuale. Questa parte introduce l'idea alla base della vector search: generiamo gli embedding del testo, li salviamo in MongoDB e li interroghiamo usando il vector index creato in precedenza.

Lo faremo in due piccoli passaggi, così sarà facile testare ed effettuare il debug man mano.

 a. Aggiungi testo e genera embedding

Il primo endpoint accetta un titolo e del contenuto testuale. Uniremo entrambi i campi in una stringa, genereremo un embedding con SentenceTransformers e salveremo il documento insieme al vettore di embedding.

Ecco come appare in codice:

# main.py (excerpt)

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from pymongo import MongoClient
from sentence_transformers import SentenceTransformer
from dotenv import load_dotenv
import os

load_dotenv()

app = FastAPI()

# --- DB setup ---
client = MongoClient(os.getenv("MONGODB_URI"))
db = client[os.getenv("DB_NAME")]
texts_coll = db[os.getenv("TEXT_COLLECTION")]
Images_coll = db[os.getenv("IMAGE_COLLECTION")]


# --- text embedding model ---
MODEL_NAME = "all-MiniLM-L6-v2"
text_model = SentenceTransformer(MODEL_NAME)

# --- request schema ---
class AddTextRequest(BaseModel):
    title: str
    content: str

@app.post("/add-text")
def add_text(payload: AddTextRequest):
    try:
        # Combine fields for richer embeddings
        text = f"{payload.title}\n\n{payload.content}"

        # Generate text embedding
        embedding = text_model.encode(text).tolist()

        # Store document in MongoDB
        doc = {
            "title": payload.title,
            "content": payload.content,
            "embedding": embedding,
            "model": MODEL_NAME,
        }

        result = texts_coll.insert_one(doc)

        return {
            "inserted_id": str(result.inserted_id),
            "title": payload.title
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Come testare questo endpoint

cURL, Postman e strumenti simili possono essere usati per il test. In questo tutorial useremo Postman.

Dovremo anche esporre il nostro endpoint FastAPI su Internet per testarlo con Postman sul web. Useremo Ngrok per questo. Se sei nuovo a Ngrok, visita la documentazione. Per testare, esegui prima il codice FastAPI con il comando seguente:

uvicorn main:app --reload

Poi, crea un tunnel dal tuo localhost a Internet con il comando Ngrok qui sotto:

Ngrok http 8000

Questo genererà un URL da usare per i test, come nell'immagine seguente:

Immagine di un terminale con il server Ngrok in esecuzione. 
Contiene l'URL localhost e l'URL web tunnellizzato

Invia una richiesta POST con Postman all'endpoint add-text. L'immagine sotto illustra ulteriormente l'invio della richiesta e la risposta attesa.

Immagine di una chiamata API con Postman, URL Ngrok e risposta della chiamata API.

Risposta attesa:

{
  "inserted_id": "65f...",
  "title": "Why FastAPI is great."
}

Questo conferma che il modello di embedding è stato caricato correttamente e che MongoDB ha salvato il vettore. Se funziona, la pipeline testuale è operativa.

b. Cerca testo con la vector search

Ora che possiamo aggiungere testo, il passo successivo è cercarlo usando lo stage $vectorSearch di MongoDB. Qui:

  1. Convertiamo la query dell'utente in un embedding.
  2. Chiediamo a MongoDB di recuperare i vettori più vicini.
  3. Restituiamo i documenti più simili.

Aggiungi il seguente endpoint a main.py:

class SearchTextRequest(BaseModel):
    query: str
    limit: int = 5

@app.post("/search-text")
def search_text(payload: SearchTextRequest):
    try:
        # Convert search query to embedding
        query_vector = text_model.encode(payload.query).tolist()

        # Vector search pipeline
        pipeline = [
            {
                "$vectorSearch": {
                    "queryVector": query_vector,
                    "path": "embedding",
                    "numCandidates": 100,
                    "limit": payload.limit,
                    "index": "vector_texts_search" # field MUST match the index name in Atlas exactly


                }
            },
            {
                "$project": {
                    "title": 1,
                    "content": 1,
                    "score": {"$meta": "vectorSearchScore"},
                    "_id": 0
                }
            }
        ]

        results = list(texts_coll.aggregate(pipeline))
        return {"results": results}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

> Il parametro numCandidates determina quanti possibili match vengono valutati prima di restituire i risultati migliori. 

> Valori più alti migliorano l'accuratezza ma aumentano i tempi di query. Una buona regola pratica è 10–20× il tuo limit.

Come testare la ricerca testuale

Dopo aver aggiunto uno o più documenti, invia una richiesta POST all'endpoint /search-text tramite Postman usando il link generato da Ngrok, come nell'immagine seguente:

Immagine di una chiamata API con Postman, URL Ngrok e risposta della chiamata API.

Output atteso:

{
  "results": [
    {
      "title": "Why FastAPI is great",
      "content": "FastAPI makes building APIs simple and fast.",
      "score": 0.85
    }
  ]
}

Se vedi un risultato con uno score di similarità, la pipeline di vector search per il testo funziona end-to-end. Una volta che questa parte è stabile, possiamo passare al flusso per le immagini.

Implementare la ricerca per immagini

Ora che il flusso per il testo funziona, possiamo estendere la stessa idea alle immagini. Il flusso generale è simile: l'unica grande differenza è come generiamo gli embedding. Invece di SentenceTransformers, useremo un modello basato su CLIP, progettato per convertire le immagini in vettori a 512 dimensioni.

Come prima, implementeremo tutto passo dopo passo, così è facile testare e fare debug.

a. Aggiungi immagine e genera embedding

Questo endpoint accetta un file immagine caricato, lo converte in un tensore comprensibile da CLIP, genera un embedding a 512 dimensioni e lo salva in MongoDB.

Ecco come appare:

# --- CLIP model setup ---
import torch
import open_clip
from PIL import Image
import io
from fastapi import UploadFile, File

# Load CLIP model once when the app starts
clip_model, _, preprocess = open_clip.create_model_and_transforms(
    "ViT-B-32",
    pretrained="openai"
)
device = "cuda" if torch.cuda.is_available() else "cpu"
clip_model.to(device)

@app.post("/add-image")
async def add_image(file: UploadFile = File(...)):
    """
    Upload an image, generate its CLIP embedding, and store in MongoDB.
    """
    try:
        # Read file contents
        image_bytes = await file.read()
        image = Image.open(io.BytesIO(image_bytes)).convert("RGB")

        # Preprocess for CLIP and encode
        image_tensor = preprocess(image).unsqueeze(0).to(device)
        with torch.no_grad():
            image_embedding = clip_model.encode_image(image_tensor)

        # Normalize the embedding (important for cosine similarity)
        image_embedding /= image_embedding.norm(dim=-1, keepdim=True)
        vector = image_embedding.cpu().numpy().flatten().tolist()

        # Store in MongoDB
        doc = {
            "filename": file.filename,
            "embedding": vector
        }
        result = images_coll.insert_one(doc)

        return {
            "inserted_id": str(result.inserted_id),
            "filename": file.filename
        }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Perché la normalizzazione è importante

Gli embedding di CLIP funzionano al meglio con la similarità coseno. Per rendere i confronti accurati e stabili, normalizziamo i vettori:

image_embedding /= image_embedding.norm(dim=-1, keepdim=True)

Questo assicura che la distanza coseno rifletta la similarità reale.

Testa l'endpoint di upload immagini

Per testare la funzionalità in Postman, invia una richiesta POST all'endpoint /add-image. Invia una form-data come body della richiesta con un'immagine .jpg o .png. L'immagine sotto mostra il processo.

Immagine di una chiamata API con Postman, URL Ngrok e risposta della chiamata API.

Se tutto funziona, dovresti ottenere qualcosa del tipo:

{
  "inserted_id": "692454f6156fbb762ed865a0",
  "filename": "file-name.png"
}

A questo punto, i tuoi embedding delle immagini sono stati salvati correttamente in MongoDB.

b. Cerca immagini con la vector search

Ora possiamo creare l'endpoint che prende un'immagine di query caricata, la converte in un embedding e trova le immagini salvate più vicine usando il nostro indice vettoriale per le immagini.

Aggiungi questo a main.py:

@app.post("/search-image")
async def search_image(file: UploadFile = File(...)):
    """
    Upload an image and find the most visually similar images in MongoDB.
    """
    try:
        # Read the uploaded file
        image_bytes = await file.read()
        image = Image.open(io.BytesIO(image_bytes)).convert("RGB")

        # Generate embedding for the query image
        image_tensor = preprocess(image).unsqueeze(0).to(device)
        with torch.no_grad():
            query_embedding = clip_model.encode_image(image_tensor)

        query_embedding /= query_embedding.norm(dim=-1, keepdim=True)
        query_vector = query_embedding.cpu().numpy().flatten().tolist()

        # Vector search pipeline
        pipeline = [
            {
                "$vectorSearch": {
                    "queryVector": query_vector,
                    "path": "embedding",
                    "numCandidates": 100,
                    "limit": 5,
                    "index": "vector_images_search"
                }
            },
            {
                "$project": {
                    "filename": 1,
                    "score": {"$meta": "vectorSearchScore"},
                    "_id": 0
                }
            }
        ]

        results = list(images_coll.aggregate(pipeline))
        return {"results": results}

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Testa l'endpoint di ricerca immagini

Per testare in Postman, invia una richiesta POST all'endpoint /search-image. Invia la form data come body della richiesta con un'immagine simile a quelle caricate in precedenza. L'immagine sotto mostra il processo.

Immagine di una chiamata API con Postman, URL Ngrok verso la route /search-image e risposta della chiamata API.

L'output atteso dovrebbe essere simile a:

{
  "results": [
    {
      "filename": "image1.png",
      "score": 1.0
    },
    {
      "filename": "image2.png",
      "score": 0.81
    }
  ]
}

Uno score di 1.0 significa che ha trovato la stessa immagine. Valori vicini (0,7–0,9) indicano una forte similarità visiva.

Se vedi un array con dei risultati, la tua vector search per immagini è operativa.

A questo punto, se tutto funziona, abbiamo un sistema di ricerca semantica completo sia per testo che per immagini.

Conclusione

In questo tutorial abbiamo costruito un intero workflow di ricerca semantica con FastAPI e MongoDB Atlas. Abbiamo generato embedding testuali con SentenceTransformers, creato embedding di immagini con un modello CLIP, archiviato tutto in MongoDB e interrogato i dati usando la Vector Search di MongoDB e Postman. Questo pattern è la base per applicazioni come ricerca semantica di documenti, strumenti di similarità di immagini, sistemi di raccomandazione e funzionalità AI multimodali.

La forza di questa architettura sta nella sua flessibilità: MongoDB non ti vincola a modelli specifici. Finché gli embedding sono vettori numerici e le dimensioni corrispondono alla configurazione dell'indice, puoi collegare qualsiasi modello testuale, di immagini o multimodale adatto al tuo caso d'uso.

Con queste basi, puoi estendere ulteriormente il progetto: archivia metadati, costruisci una logica di ranking o integra il tutto in app per l'utente finale. Lo stesso workflow scala senza sforzo grazie ai servizi completamente gestiti di MongoDB Atlas.

Puoi trovare il progetto completo e funzionante su GitHub.


Moses Anumadu's photo
Author
Moses Anumadu

Ingegnere software

Argomenti
MongoDB

I migliori corsi DataCamp

Corso

Introduzione a MongoDB in Python

3 ore
24.3K
Impara a gestire e analizzare dati strutturati in modo flessibile con MongoDB.
Vedi i dettagliRight Arrow
Inizia Il Corso
Mostra altroRight Arrow
Correlato

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

Mostra AltroMostra Altro