L'AI dove vivono i dati aziendali (parte 3): Ricerca semantica con T-SQL

Punto di partenza

Nel secondo articolo di questa serie abbiamo creato un external model verso Azure OpenAI e abbiamo usato la funzione AI_GENERATE_EMBEDDINGS per generare gli embeddings dei testi presenti nella tabella ai_demo.PostSearchDocuments.

La tabella ai_demo.PostSearchDocuments nel database StackOverflowMini contiene ora due elementi essenziali:

  1. I dati grezzi, come titolo, tag, testi delle domande e delle risposte
  2. La colonna Embedding, che contiene la rappresentazione vettoriale del testo costruito nella colonna DocumentText

In questo terzo articolo useremo finalmente gli embeddings per eseguire ricerche semantiche direttamente da T-SQL. L’obiettivo è trovare testi simili per significato rispetto a una richiesta espressa in linguaggio naturale, anche quando il testo cercato non coincide esattamente con le parole presenti nei documenti.

Il meccanismo sarà il seguente: trasformeremo il testo della ricerca in un vettore usando lo stesso modello di embedding già configurato, poi confronteremo quel vettore con quelli salvati nella tabella usando la funzione VECTOR_DISTANCE.

Dal testo alla distanza vettoriale

La ricerca semantica parte da una richiesta espressa in linguaggio naturale. Invece di cercare una corrispondenza esatta tra parole, trasformiamo quella richiesta in un embedding usando lo stesso modello utilizzato per generare gli embeddings dei testi salvati nella tabella ai_demo.PostSearchDocuments; avremo quindi due elementi confrontabili:

  1. Il vettore generato a partire dal testo che si desidera cercare
  2. I vettori già presenti nella colonna Embedding

La funzione VECTOR_DISTANCE permette di calcolare la distanza tra questi vettori. Nel nostro esempio useremo la metrica cosine, molto comune negli scenari di ricerca semantica.

Il valore restituito rappresenta una distanza: più il valore è basso, cioè più vicino a zero, più il testo salvato nella tabella ai_demo.PostSearchDocuments è vicino semanticamente al testo cercato. Ordinando i risultati per distanza crescente possiamo quindi ottenere i documenti più simili per significato.

Ricerca semantica con VECTOR_DISTANCE

Il sistema è pronto per ricevere richieste espresse in linguaggio naturale. In questo esempio non cerchiamo direttamente le parole “parameter sniffing”, ma descriviamo un problema tipico: una stored procedure diventa lenta solo per alcuni valori dei parametri e sembra riutilizzare un piano di esecuzione non ottimale.

-- Semantic search with VECTOR_DISTANCE
DECLARE
  @SearchText NVARCHAR(MAX) = N'After a deployment, the same stored procedure ' + 
    'became slow only for some parameter values. ' +
    'It looks like SQL Server is reusing a bad execution plan.';
DECLARE
  @qv VECTOR(1536) = AI_GENERATE_EMBEDDINGS
                     (
                       @SearchText 
                       USE MODEL [AzureOpenAI_text_embedding_ada_002]
                     );

SELECT
  TOP (10)
  VECTOR_DISTANCE('cosine', @qv, Embedding) AS Distance
  ,QuestionId
  ,AcceptedAnswerId
  ,QuestionScore
  ,AcceptedAnswerScore
  ,ViewCount
  ,Tags
  ,Title
FROM
  [ai_demo].[PostSearchDocuments]
WHERE
  Embedding IS NOT NULL
ORDER BY
  Distance;
GO

La variabile @SearchText contiene il testo della ricerca. Questo testo viene trasformato in un vettore tramite la funzione AI_GENERATE_EMBEDDINGS, usando lo stesso external model utilizzato nella fase di generazione degli embeddings.

La query confronta poi il vettore appena generato con la colonna Embedding della tabella ai_demo.PostSearchDocuments, calcolando la distanza tramite VECTOR_DISTANCE. I risultati vengono ordinati per distanza crescente, in modo da mostrare per primi i documenti semanticamente più vicini alla richiesta.

Si osserva che la ricerca non dipende dalla presenza esatta delle parole usate nel testo della richiesta. Il motore può recuperare contenuti collegati al problema descritto, anche se nei testi salvati vengono usati termini differenti o formulazioni diverse.

Ricerca semantica e filtri relazionali

La ricerca semantica può essere combinata con i normali predicati T-SQL. Questo è uno degli aspetti più interessanti dell’approccio: il confronto vettoriale permette di trovare testi simili per significato, mentre il modello relazionale continua a essere usato per applicare filtri, ordinamenti e criteri di qualità sui dati.

Nel seguente esempio cerchiamo contenuti relativi all’aggiornamento di righe in una tabella SQL Server usando valori provenienti da un’altra tabella. Oltre alla distanza vettoriale, applichiamo anche un filtro sul punteggio della domanda, considerando solo documenti con QuestionScore >= 10.

-- Semantic search with VECTOR_DISTANCE and relational filtering
DECLARE
  @SearchText NVARCHAR(MAX) = N'I need to update rows in one SQL Server table ' +
    'using values from another table joined by a key.';
DECLARE
  @qv VECTOR(1536) = AI_GENERATE_EMBEDDINGS
                     (
                       @SearchText 
                       USE MODEL [AzureOpenAI_text_embedding_ada_002]
                     );

SELECT
  TOP (10)
  VECTOR_DISTANCE('cosine', @qv, Embedding) AS Distance
  ,QuestionId
  ,AcceptedAnswerId
  ,QuestionScore
  ,AcceptedAnswerScore
  ,ViewCount
  ,Tags
  ,Title
  ,LEFT(AcceptedAnswerBody, 1000) AS AcceptedAnswerPreview
FROM
  [ai_demo].[PostSearchDocuments]
WHERE
  Embedding IS NOT NULL
  AND QuestionScore >= 10
ORDER BY
  Distance;
GO

La condizione QuestionScore >= 10 non partecipa al calcolo della distanza semantica, ma restringe l’insieme delle righe restituite ai soli contenuti che hanno già ricevuto un certo riconoscimento dalla community.

In uno scenario aziendale lo stesso principio può essere applicato usando metadati diversi, ad esempio area applicativa, prodotto, lingua, data di aggiornamento, stato del documento o livello di confidenzialità. La ricerca semantica individua i contenuti più vicini per significato, mentre i filtri relazionali permettono di mantenere il controllo sui dati da includere nei risultati.

Uno sguardo al piano di esecuzione

Osservando il piano di esecuzione della query precedente si nota un comportamento importante. La ricerca con VECTOR_DISTANCE viene eseguita calcolando la distanza tra il vettore della richiesta e gli embeddings presenti nelle righe candidate.

SQL Server esegue una scansione della tabella ai_demo.PostSearchDocuments, applica i predicati Embedding IS NOT NULL e QuestionScore >= 10, calcola la distanza vettoriale con l’operatore Compute Scalar e ordina il risultato con un Top N Sort per restituire le prime 10 righe.

La scansione legge tutte le righe della tabella: non c’è un indice sulla colonna QuestionScore; i predicati riducono l’insieme a 1.487 righe e su queste viene calcolata la distanza con VECTOR_DISTANCE. Il risultato viene poi ordinato per distanza crescente.

Il funzionamento della ricerca semantica con la funzione VECTOR_DISTANCE è chiaro: ogni riga candidata viene confrontata con il vettore della richiesta e i testi semanticamente più vicini vengono restituiti per primi. Su un insieme di dati contenuto questo approccio performa bene. Quando il numero di righe cresce, però, diventa importante valutare meccanismi più adatti alla ricerca vettoriale su volumi maggiori. È qui che entrano in gioco gli indici vettoriali e la funzione VECTOR_SEARCH, che approfondiremo nel prossimo articolo.

Conclusioni

In questo articolo abbiamo usato gli embeddings generati precedentemente per eseguire ricerche semantiche direttamente da T-SQL. Abbiamo trasformato una richiesta espressa in linguaggio naturale in un vettore e l’abbiamo confrontata con gli embeddings salvati nella tabella ai_demo.PostSearchDocuments usando la funzione VECTOR_DISTANCE.

La ricerca semantica non sostituisce il modello relazionale, ma lo affianca. I predicati T-SQL permettono di applicare filtri sui dati, mentre la distanza vettoriale consente di ordinare i risultati in base alla vicinanza semantica rispetto alla richiesta dell’utente.

Nel prossimo articolo vedremo come creare un indice vettoriale e come usare VECTOR_SEARCH per eseguire ricerche semantiche con SQL Server 2025 e Azure SQL.