Tutoriel Oracle AI Vector Search : stocker et interroger des embeddings avec Python
Ce tutoriel présente Oracle AI Vector Search, ses fonctionnalités clés, et guide un projet local pas à pas. Il couvre la mise en place, la recherche sémantique, l’indexation vectorielle et les points de dépannage courants.
Dans ce tutoriel, nous allons construire une démo locale de recherche sémantique avec Oracle AI Vector Search, Python et Oracle Database Free 26ai.
Nous commencerons avec des vecteurs tridimensionnels saisis à la main pour visualiser le calcul de distance, puis nous générerons des embeddings de texte et les interrogerons depuis Oracle Database avec SQL.
Ce tutoriel s’adresse aux développeurs Python et SQL qui découvrent la recherche vectorielle et qui sont à l’aise avec Docker, les variables d’environnement, les packages Python et l’installation d’une base locale.
Les applications dopées à l’IA ont besoin d’une recherche qui comprend le sens, pas seulement les mots exacts. Une application de support, un portail de documentation ou un outil interne de connaissance doit pouvoir retrouver « stockage de base de données pour la recherche IA » même si le meilleur document correspondant dit « store vector embeddings in native columns ».
Vector embeddings rendent cela possible en représentant le texte sous forme de vecteurs numériques. Oracle AI Vector Search permet de stocker ces vecteurs directement dans Oracle Database, de les interroger en SQL et de conserver les embeddings à côté des données relationnelles de l’application.
Dans ce flux de travail local, nous n’avons pas besoin d’une base de données vectorielle séparée.
Nous exécuterons Oracle Database Free 26ai en local, nous connecterons Python en mode oracledb Thin, stockerons d’abord des vecteurs manuels, puis des embeddings OpenAI, lancerons une recherche sémantique, comparerons la récupération sémantique à un prédicat d’exacte correspondance de phrase, et créerons un index vectoriel validé via USER_INDEXES.
À la fin, nous aurons un flux de travail de recherche sémantique piloté par Python qui stocke les embeddings dans Oracle Database et récupère localement les documents les plus similaires.
Qu’est-ce qu’Oracle AI Vector Search ?
Oracle AI Vector Search regroupe des fonctionnalités d’Oracle Database pour stocker, indexer et interroger des embeddings vectoriels. Un embedding est une liste de taille fixe de nombres qui représente le sens d’un texte, d’images ou d’autres données dans une forme que la base peut comparer mathématiquement.
Un modèle d’embedding génère ces vecteurs numériques. Il prend en entrée une phrase, un paragraphe, la description d’une image ou un extrait de code, et renvoie un vecteur avec un nombre fixe de dimensions.
Des entrées similaires doivent produire des vecteurs proches, tandis que des entrées sans rapport doivent être plus éloignées. Il faut donc utiliser le même modèle d’embedding pour les documents stockés et les requêtes entrantes, car les distances n’ont de sens que si les vecteurs partagent le même repère.
Dans ce tutoriel, les vecteurs manuels sont volontairement petits pour que nous puissions inspecter les calculs. Les véritables embeddings de texte sont bien plus grands, car le modèle a besoin de suffisamment de dimensions pour encoder des relations plus fines entre les mots, les expressions et les sujets.
La recherche vectorielle classe les lignes selon la distance entre vecteurs. Pour les requêtes de distance euclidienne et cosinus, plus la distance est petite, plus la correspondance est proche. Dans ce tutoriel, nous commencerons avec une petite colonne VECTOR(3, FLOAT32) afin d’observer directement le comportement des distances, puis nous passerons à des embeddings VECTOR(1536, FLOAT32) générés à partir de texte.
Figure 1. Flux Oracle AI Vector Search
Oracle AI Vector Search stocke les embeddings dans une colonne VECTOR native et classe les résultats par distance vectorielle.
Oracle Database est utile lorsque les embeddings doivent vivre à côté des données relationnelles de l’application comme les identifiants de documents, titres, contenus, utilisateurs, produits, tickets ou métadonnées.
Certaines applications utilisent une base vectorielle ou un moteur de recherche séparé pour des charges de travail spécialisées, mais pour ce flux local de recherche sémantique, Oracle Database fournit le stockage vectoriel et les fonctions de recherche nécessaires.
Fonctionnalités clés d’Oracle AI Vector Search
Nous utiliserons quatre fonctionnalités dans la démo : stockage vectoriel natif, fonctions de distance, index vectoriels et intégration relationnelle.
Type de données vectorielles natif
Oracle Database prend en charge des colonnes VECTOR natives avec dimensions explicites et formats d’éléments. Dans la démo, nous utiliserons VECTOR(3, FLOAT32) pour les vecteurs manuels et VECTOR(1536, FLOAT32) pour le modèle d’embedding par défaut text-embedding-3-small.
Fonctions et opérateurs de distance
Les exemples exécutables utilisent VECTOR_DISTANCE() car la métrique de distance reste explicite en SQL.
Nous utiliserons la distance euclidienne pour l’exemple manuel, puis la distance cosinus pour les embeddings de texte.
Oracle Database inclut également des opérateurs abrégés de distance vectorielle et des comportements liés au produit scalaire, mais ce tutoriel conserve du SQL exécutable avec la fonction explicite VECTOR_DISTANCE().
Différentes métriques répondent à des nuances différentes de « proximité ».
Pour un petit tutoriel, la distance cosinus est un bon défaut pour des embeddings de texte car elle se concentre sur la direction, souvent bien corrélée à la similarité sémantique.
La distance euclidienne est plus facile à visualiser avec des vecteurs écrits à la main, et les comparaisons de type produit scalaire sont utiles dans certains systèmes lorsque la magnitude ou la normalisation des vecteurs fait partie du design du modèle.
Métrique
Ce qu’elle compare
Bon usage
Points d’attention
Cosinus
Direction du vecteur
Embeddings de texte et similarité sémantique
Résultats dépendants du même modèle d’embedding et d’un prétraitement cohérent
Euclidienne
Distance en ligne droite
Petits exemples, intuition géométrique, certains vecteurs de caractéristiques numériques
La magnitude influe sur la distance, donc l’échelle peut compter
Produit scalaire
Direction et magnitude ensemble
Flux pensés autour de vecteurs normalisés ou d’un scoring par produit interne
Le sens du score et les règles de normalisation doivent être comprises avant toute comparaison
Index vectoriels
La recherche vectorielle exacte est utile pour la justesse et les petits jeux de données. Quand les données grossissent, les index vectoriels permettent des recherches approchées de plus proches voisins.
Oracle AI Vector Search inclut des index en mémoire sous forme de graphes de voisins, souvent associés aux recherches de type HNSW, et des index par partitions de voisins, souvent associés au partitionnement de type IVF.
Dans cette démo locale, nous utilisons ORGANIZATION NEIGHBOR PARTITIONS et validons l’index avec USER_INDEXES.
Les index approximatifs échangent un peu de certitude d’une recherche exhaustive contre une récupération plus rapide à l’échelle.
Le bon type d’index dépend de la charge, du volume, du rythme de mise à jour et de l’objectif de rappel.
Ce tutoriel utilise un index de type IVF par partitions de voisins pour garder l’installation locale simple et illustrer concrètement la création d’index sans transformer le tutoriel en guide d’optimisation.
Famille d’index
Principe
Forces
Compromis
Quand l’utiliser
IVF / partitions de voisins
Partitionner l’espace vectoriel, puis chercher dans les partitions probables
Modèle mental simple, pratique pour beaucoup de jeux chargés par lots
Le rappel et la vitesse dépendent du partitionnement et des réglages de recherche
Nous voulons une voie simple de recherche approchée pour un jeu de données en croissance
HNSW / graphe de voisins
Construire un graphe reliant les vecteurs proches pour une traversée rapide
Bon profil rappel/latence pour de nombreuses charges de plus proches voisins
Plus orienté mémoire, et la configuration peut compter davantage
Nous avons besoin d’une faible latence et pouvons allouer mémoire et efforts de tuning
Intégration aux requêtes relationnelles
Une colonne vectorielle peut cohabiter avec des colonnes relationnelles classiques. Notre table documents stockera le titre, le contenu et l’embedding ensemble, afin que SQL renvoie à la fois le score de similarité et le texte d’origine.
Comment démarrer avec Oracle AI Vector Search
Nous utiliserons un chemin d’installation local : Oracle Database Free 26ai dans Docker, le service FREEPDB1 et un utilisateur applicatif dédié vector_demo.
Les concepts de recherche vectorielle sont accessibles, mais la mise en place est intermédiaire : nous utilisons Docker, un schéma de base, des packages Python, des variables d’environnement et une clé d’API d’embedding.
Prérequis
Il vous faudra :
Docker Desktop ou Docker Engine.
Accès à Oracle Container Registry.
Les ports locaux 1521 et 5500 disponibles.
Python 3.10 ou supérieur.
Des bases en Python et SQL.
Une familiarité avec Docker et les variables d’environnement.
Une clé API OpenAI pour les étapes d’embedding.
Cette démo nécessite une version/environnement Oracle Database incluant les fonctionnalités vectorielles utilisées ici, notamment les colonnes VECTOR, VECTOR_DISTANCE() et CREATE VECTOR INDEX.
Le chemin local utilise Oracle Database Free 26ai avec le tag d’image ci-dessous, et le DSN utilise le service de base enfichable FREEPDB1.
Les étapes avec vecteurs manuels ne nécessitent pas de clé OpenAI. Les étapes sémantiques envoient le texte d’exemple des documents et des requêtes au fournisseur d’embedding configuré, donc nous n’utiliserons que du texte d’exemple/non sensible.
Ce tutoriel utilise oracledb, le pilote Python actuel pour Oracle Database. python-oracledb s’exécute en mode Thin par défaut, donc cette démo locale ne nécessite pas les bibliothèques Oracle Client. Le mode Thick est utile dans d’autres déploiements Oracle Database, mais nous n’appellerons pas oracledb.init_oracle_client() ici.
Démarrer Oracle Database Free 26ai en local
Créez un répertoire de projet pour les scripts que nous allons écrire.
mkdir oracle-ai-vector-search-python
cd oracle-ai-vector-search-pythonPropulsé par
Démarrez Oracle Database Free 26ai avec l’image locale du conteneur.
docker run --name oracle-free-26ai-vector \--detach\--publish1521:1521 \--publish5500:5500 \
--shm-size=1g \--envORACLE_PWD="replace-with-a-strong-password"\
container-registry.oracle.com/database/free:23.26.1.0-lite-amd64Propulsé par
Consultez les journaux du conteneur et attendez que la base indique que le démarrage est terminé.
FREEPDB1 est le service de base enfichable utilisé par ce chemin local avec Oracle Database Free. Notre DSN Python sera localhost:1521/FREEPDB1.
Créer le schéma vector_demo dans FREEPDB1
Utilisez SYS uniquement pour l’étape de configuration du schéma. Le mot de passe dans la commande sqlplus correspond à la valeur ORACLE_PWD de la commande docker run ; le mot de passe dans CREATE USER est le mot de passe applicatif que nous exporterons en DB_PASSWORD.
Exécutez la configuration dans le conteneur de base de données.
# Create the application user and grant the privileges needed for the demo.dockerexec-i oracle-free-26ai-vector \
sqlplus -s'sys/"replace-with-oracle-pwd"@FREEPDB1 as sysdba'<<'SQL'
WHENEVER SQLERROR EXIT SQL.SQLCODE
CREATE USER vector_demo IDENTIFIED BY "replace-with-vector-demo-password";
GRANT CREATE SESSION, CREATE TABLE, CREATE SEQUENCE, UNLIMITED TABLESPACE TO vector_demo;
EXIT
SQLPropulsé par
Il s’agit d’un raccourci de développement local pour la démo. CREATE SEQUENCE est nécessaire car les tables utilisent des colonnes identité.
En production, nous reverrions les privilèges avec un administrateur de base et appliquerions le principe du moindre privilège adapté à la charge applicative.
Stockez les identifiants de base et les réglages d’embedding dans des variables d’environnement plutôt que de les coder en dur dans les fichiers Python.
exportDB_USER="vector_demo"exportDB_PASSWORD="replace-with-vector-demo-password"exportDB_DSN="localhost:1521/FREEPDB1"exportOPENAI_API_KEY="replace-with-your-api-key"exportEMBEDDING_MODEL="text-embedding-3-small"exportEMBEDDING_DIM="1536"Propulsé par
OPENAI_API_KEY n’est requis que pour les étapes d’embedding et de recherche sémantique. EMBEDDING_DIM doit correspondre au nombre de dimensions renvoyées par le modèle choisi.
Projet démo Oracle AI Vector Search
Nous construirons la démo en huit jalons. Chaque script ajoute un concept et produit une sortie à vérifier avant d’avancer.
La partie « base uniquement » est complète après les étapes 1 à 3. À ce stade, nous nous serons connectés à Oracle Database, aurons stocké des vecteurs manuels, les aurons interrogés par distance et créé la table sémantique. La clé API OpenAI devient nécessaire à l’étape 4.
Étape 1 : se connecter à la base locale
Nous allons d’abord vérifier que Python peut se connecter à Oracle Database en tant qu’utilisateur applicatif vector_demo. Ce script lit DB_USER, DB_PASSWORD et DB_DSN à partir de l’environnement, puis affiche le mode du pilote et la version de la base.
Créer le script
Enregistrez le code suivant sous 01_check_connection.py.
import os
import oracledb
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defmain():# Load required database settings from environment variables.
user = required_env("DB_USER")
password = required_env("DB_PASSWORD")
dsn = required_env("DB_DSN")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")# Open a Thin-mode connection with the application user.with oracledb.connect(user=user, password=password, dsn=dsn)as connection:
mode ="thin"if oracledb.is_thin_mode()else"thick"print("Connected to Oracle Database.")print(f"Driver mode: {mode}")print(f"Database version: {connection.version}")if __name__ =="__main__":
main()Propulsé par
La sortie doit confirmer que la connexion fonctionne et que le pilote est en mode Thin.
Connected to Oracle Database.
Driver mode: thin
Database version: 23.26.1.0.0Propulsé par
Nous savons maintenant que la base locale, le nom de service, les identifiants et le pilote Python fonctionnent avant de créer des tables vectorielles.
Étape 2 : se forger une intuition avec des vecteurs manuels
Avant d’introduire les modèles d’embedding, stockons trois petits vecteurs faciles à raisonner. L’appel array.array("f", values) crée un tableau de flottants 32 bits que python-oracledb peut lier à une colonne VECTOR(..., FLOAT32).
Figure 2. Vecteurs manuels et distance euclidienne.
L’exemple manuel utilise la distance euclidienne. Le vecteur « apple » a une distance de 0,0000 car il correspond au vecteur de requête. Le vecteur « banana » est classé second car sqrt((1.0 - 0.9)^2 + (0.0 - 0.1)^2 + (0.0 - 0.0)^2) = 0,1414.
Créer le script
Enregistrez le code suivant sous 02_manual_vectors.py.
import array
import os
import oracledb
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defmain():
user = required_env("DB_USER")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")# Define three small vectors so the distance calculation is easy to inspect.
rows =[("apple", array.array("f",[1.0,0.0,0.0])),("banana", array.array("f",[0.9,0.1,0.0])),("car", array.array("f",[0.0,1.0,0.0])),]with oracledb.connect(
user=user,
password=required_env("DB_PASSWORD"),
dsn=required_env("DB_DSN"),)as connection:with connection.cursor()as cursor:# Recreate the table so the script can be run repeatedly.
cursor.execute("""
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE manual_vectors PURGE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE <> -942 THEN
RAISE;
END IF;
END;
""")
cursor.execute("""
CREATE TABLE manual_vectors (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
label VARCHAR2(100),
embedding VECTOR(3, FLOAT32)
)
""")# Bind each vector as a 32-bit floating-point array.
cursor.executemany("""
INSERT INTO manual_vectors (label, embedding)
VALUES (:1, :2)
""",
rows,)
connection.commit()# Rank rows by Euclidean distance from the query vector.
cursor.execute("""
SELECT label,
VECTOR_DISTANCE(
embedding,
:query_vector,
EUCLIDEAN
) AS distance
FROM manual_vectors
ORDER BY distance
FETCH EXACT FIRST 2 ROWS ONLY
""",
query_vector=array.array("f",[1.0,0.0,0.0]),)print("Created manual_vectors.")print("Inserted 3 manual vectors.")print("\nNearest manual vectors:")for rank,(label, distance)inenumerate(cursor, start=1):print(f"{rank}. {label:<6} distance={float(distance):.4f}")if __name__ =="__main__":
main()Propulsé par
Le vecteur identique apparaît en premier avec une distance de 0,0000, et « banana » en second.
Created manual_vectors.
Inserted 3 manual vectors.
Nearest manual vectors:
1. apple distance=0.0000
2. banana distance=0.1414Propulsé par
C’est l’idée centrale de la recherche vectorielle : les lignes sont classées par proximité mathématique avec un vecteur de requête. Les modèles d’embedding génèrent des vecteurs plus grands, mais le comportement côté base reste le même.
Étape 3 : créer la table de documents sémantiques
Maintenant que les vecteurs fonctionnent, créons une table de type applicatif. Le point clé est que la dimension de la colonne vectorielle doit correspondre à la dimension de sortie du modèle d’embedding.
La dimension fait partie du contrat de la table. Si un modèle renvoie 1 536 nombres, la colonne doit être déclarée en VECTOR(1536, FLOAT32).
Si nous passons ensuite à un modèle avec une longueur différente, il faudra recréer ou migrer la colonne vectorielle pour conserver la compatibilité des insertions et requêtes.
Comme le DDL ne permet pas de lier la dimension vectorielle via une variable SQL classique, le script convertit EMBEDDING_DIM en entier avant de l’utiliser dans CREATE TABLE.
Créer le script
Enregistrez le code suivant sous 03_create_documents_table.py.
import os
import oracledb
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defconfigured_dimension():try:
dimension =int(required_env("EMBEDDING_DIM"))except ValueError as exc:raise SystemExit("EMBEDDING_DIM must be an integer.")from exc
if dimension <=0:raise SystemExit("EMBEDDING_DIM must be a positive integer.")return dimension
defmain():
user = required_env("DB_USER")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")# Validate the configured model name and vector dimension.
model_name = required_env("EMBEDDING_MODEL")
dimension = configured_dimension()with oracledb.connect(
user=user,
password=required_env("DB_PASSWORD"),
dsn=required_env("DB_DSN"),)as connection:with connection.cursor()as cursor:# Recreate the documents table so the script is repeatable.
cursor.execute("""
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE documents PURGE';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE <> -942 THEN
RAISE;
END IF;
END;
""")
cursor.execute(f"""
CREATE TABLE documents (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
title VARCHAR2(200) NOT NULL,
content VARCHAR2(1000) NOT NULL,
embedding VECTOR({dimension}, FLOAT32)
)
""")print(f"Embedding model: {model_name}")print(f"Embedding dimension: {dimension}")print("Recreated documents table.")if __name__ =="__main__":
main()Propulsé par
La sortie doit afficher le modèle d’embedding configuré et la dimension vectorielle.
Embedding model: text-embedding-3-small
Embedding dimension: 1536
Recreated documents table.Propulsé par
Nous avons terminé la partie base de données. Oracle Database peut stocker et comparer des vecteurs en local ; passons maintenant des vecteurs écrits à la main aux embeddings générés à partir de texte.
Étape 4 : vérifier la dimension du modèle d’embedding
Avant d’insérer des embeddings, demandons au modèle un vecteur et vérifions sa longueur. Cela évite l’erreur la plus courante des tables vectorielles : insérer un vecteur dont la longueur ne correspond pas à la dimension de la colonne VECTOR.
Un modèle d’embedding n’est pas qu’un convertisseur texte→nombres ; il définit l’espace de sens de l’application. Tous les embeddings de documents et de requêtes de cette démo doivent venir du même modèle.
Utiliser un seul modèle garantit qu’une petite distance signifie un sens similaire, plutôt que deux vecteurs sans lien qui auraient par hasard une forme proche. Le modèle détermine aussi la longueur du vecteur, d’où la vérification préalable.
Créer le script
Enregistrez le code suivant sous 04_check_embedding_dimension.py.
import os
from openai import OpenAI
defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defconfigured_dimension():try:returnint(required_env("EMBEDDING_DIM"))except ValueError as exc:raise SystemExit("EMBEDDING_DIM must be an integer.")from exc
defmain():
required_env("OPENAI_API_KEY")
model_name = required_env("EMBEDDING_MODEL")
expected_dimension = configured_dimension()# Request one embedding to confirm the model output dimension.
client = OpenAI()
response = client.embeddings.create(
model=model_name,input="Oracle AI Vector Search dimension check",)
returned_dimension =len(response.data[0].embedding)print(f"Embedding model: {model_name}")print(f"Returned embedding length: {returned_dimension}")print(f"Configured EMBEDDING_DIM: {expected_dimension}")# Stop before loading data if the table dimension is incompatible.if returned_dimension != expected_dimension:raise SystemExit("Dimension check failed. Update EMBEDDING_DIM, rerun ""03_create_documents_table.py, and try again.")print("Dimension check passed.")if __name__ =="__main__":
main()Propulsé par
Exécuter le script
Exécutez la vérification de dimension.
python 04_check_embedding_dimension.pyPropulsé par
Sortie attendue
Pour le modèle et la dimension par défaut, la sortie doit ressembler à ceci.
Embedding model: text-embedding-3-small
Returned embedding length: 1536
Configured EMBEDDING_DIM: 1536
Dimension check passed.Propulsé par
Si nous choisissons plus tard un autre modèle d’embedding, mettez à jour EMBEDDING_MODEL, réglez EMBEDDING_DIM à la longueur renvoyée et recréez la table documents.
Étape 5 : générer et insérer les embeddings des documents
Nous allons maintenant générer des embeddings pour un petit jeu de données autonome et les insérer dans Oracle Database.
Chaque embedding est converti en array.array("f", embedding) avant liaison pour correspondre à la colonne vectorielle en FLOAT32.
Créer le script
Enregistrez le code suivant sous 05_insert_embeddings.py.
import array
import os
import oracledb
from openai import OpenAI
DOCUMENTS =[("Oracle AI Vector Search","Oracle Database can store vector embeddings in native VECTOR ""columns and query them with SQL similarity search.",),("Semantic Search for Applications","Semantic search ranks results by meaning, helping applications ""find related content even when exact words differ.",),("Vector Index Workflow","Vector indexes help approximate nearest-neighbor search scale ""when datasets grow beyond small examples.",),("Local Docker Development","Docker containers make it practical to run a local database for ""development and repeatable tutorials.",),("Python Database Code","Python applications can connect to Oracle Database with the ""oracledb driver and use environment variables for credentials.",),("Acoustic Guitar Practice","Daily guitar practice improves timing, chord transitions, and ""confidence when learning new songs.",),("Weeknight Vegetable Soup","A simple soup can combine onions, carrots, beans, herbs, and ""broth for an easy weeknight meal.",),]
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defconfigured_dimension():try:returnint(required_env("EMBEDDING_DIM"))except ValueError as exc:raise SystemExit("EMBEDDING_DIM must be an integer.")from exc
defmain():
user = required_env("DB_USER")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")
required_env("OPENAI_API_KEY")
model_name = required_env("EMBEDDING_MODEL")
expected_dimension = configured_dimension()# Generate embeddings for all sample documents in one API request.
client = OpenAI()
response = client.embeddings.create(
model=model_name,input=[content for _, content in DOCUMENTS],)# Restore the response order using each item's index.
embeddings =[
item.embedding
for item insorted(
response.data,
key=lambda item: item.index,)]ifany(len(embedding)!= expected_dimension for embedding in embeddings):raise SystemExit("An embedding length did not match EMBEDDING_DIM. ""Rerun 04_check_embedding_dimension.py.")# Bind each embedding as a 32-bit floating-point array.
rows =[(title, content, array.array("f", embedding))for(title, content), embedding inzip(DOCUMENTS, embeddings)]# Replace the sample rows and commit the transaction.with oracledb.connect(
user=user,
password=required_env("DB_PASSWORD"),
dsn=required_env("DB_DSN"),)as connection:with connection.cursor()as cursor:
cursor.execute("DELETE FROM documents")
cursor.executemany("""
INSERT INTO documents (title, content, embedding)
VALUES (:1, :2, :3)
""",
rows,)
cursor.execute("SELECT COUNT(*) FROM documents")
row_count = cursor.fetchone()[0]
connection.commit()print(f"Embedding model: {model_name}")print(f"Generated embeddings for {len(DOCUMENTS)} documents.")print(f"Inserted {len(DOCUMENTS)} documents.")print(f"documents row count: {row_count}")if __name__ =="__main__":
main()Propulsé par
Le nombre de lignes doit correspondre aux sept documents intégrés.
Embedding model: text-embedding-3-small
Generated embeddings for 7 documents.
Inserted 7 documents.
documents row count: 7Propulsé par
Nous avons maintenant le texte et les embeddings stockés ensemble dans Oracle Database. Les documents sans rapport sur la guitare et la soupe sont inclus, afin que les résultats présentent des correspondances proches et éloignées évidentes.
Étape 6 : exécuter une requête de recherche sémantique
Ensuite, nous allons embedder une requête en langage naturel et la comparer aux embeddings stockés. Ce script utilise la distance cosinus, couramment utilisée pour les embeddings de texte car elle privilégie la direction du vecteur plutôt que sa magnitude brute.
Pour la recherche sémantique, la requête passe par le même modèle d’embedding que les documents. Nous ne demandons pas à SQL de « comprendre » la phrase anglaise directement.
Nous demandons au modèle de convertir la phrase en vecteur, puis à Oracle Database de classer les vecteurs stockés par leur distance à ce vecteur de requête.
Créer le script
Enregistrez le code suivant sous 06_semantic_search.py.
import array
import os
import oracledb
from openai import OpenAI
QUERY_TEXT ="Where should an AI app keep meaning-based search data?"
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defmain():
user = required_env("DB_USER")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")
required_env("OPENAI_API_KEY")# Generate an embedding for the natural-language query.
client = OpenAI()
response = client.embeddings.create(
model=required_env("EMBEDDING_MODEL"),input=QUERY_TEXT,)
query_vector = array.array("f", response.data[0].embedding)with oracledb.connect(
user=user,
password=required_env("DB_PASSWORD"),
dsn=required_env("DB_DSN"),)as connection:with connection.cursor()as cursor:# Rank stored documents by cosine distance from the query vector.
cursor.execute("""
SELECT title,
content,
VECTOR_DISTANCE(
embedding,
:query_vector,
COSINE
) AS distance
FROM documents
ORDER BY distance
FETCH EXACT FIRST 5 ROWS ONLY
""",
query_vector=query_vector,)
rows = cursor.fetchall()ifnot rows:raise SystemExit("No documents found. Run 05_insert_embeddings.py first.")print(f"Query: {QUERY_TEXT}")print("\nTop 5 results:")for rank,(title, content, distance)inenumerate(rows, start=1):print(f"{rank}. {title}")print(f" distance: {float(distance):.6f}")print(f" {content[:90]}...")if __name__ =="__main__":
main()Propulsé par
Les classements et distances exacts peuvent varier si le modèle d’embedding change. Cependant, les documents sur Oracle AI Vector Search, la recherche sémantique, le code Python et l’indexation vectorielle devraient figurer en tête.
Query: Where should an AI app keep meaning-based search data?
Top 5 results:
1. Oracle AI Vector Search
distance: <cosine distance from your run>
Oracle Database can store vector embeddings in native VECTOR columns and query them with SQL...
2. Semantic Search for Applications
distance: <cosine distance from your run>
Semantic search ranks results by meaning, helping applications find related content even when...
3. Python Database Code
distance: <cosine distance from your run>
Python applications can connect to Oracle Database with the oracledb driver and use environment...
4. Vector Index Workflow
distance: <cosine distance from your run>
Vector indexes help approximate nearest-neighbor search scale when datasets grow beyond small...
5. Local Docker Development
distance: <cosine distance from your run>
Docker containers make it practical to run a local database for development and repeatable...Propulsé par
Pour les requêtes de distance euclidienne et cosinus de ce tutoriel, des valeurs plus faibles indiquent des correspondances plus proches.
Le produit scalaire est une autre approche utile dans de nombreux flux de recherche vectorielle, notamment quand la magnitude ou la normalisation importent, mais le sens du score et la normalisation doivent être traités avec soin.
Nous garderons du code exécutable avec euclidienne et cosinus pour faciliter l’interprétation.
Si nous normalisons nous‑mêmes les embeddings dans une future application, il faudra normaliser de la même façon les embeddings stockés et ceux des requêtes ; sinon, distances et classements peuvent changer.
Étape 7 : comparer la recherche sémantique à une correspondance de phrase
La recherche sémantique est utile car elle ne requiert pas la présence exacte de la même expression dans le document.
Comparons la requête sémantique à un simple prédicat d’expression exacte.
Ce n’est pas une démo de moteur de recherche plein texte ; c’est une petite comparaison SQL qui met en évidence la différence entre appariement littéral et classement fondé sur le sens.
Créer le script
Enregistrez le code suivant sous 07_semantic_vs_keyword.py.
import array
import os
import oracledb
from openai import OpenAI
SEMANTIC_QUERY ="Where should an AI app keep meaning-based search data?"
KEYWORD_PHRASE ="meaning-based search data"
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defmain():
user = required_env("DB_USER")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")
required_env("OPENAI_API_KEY")# Generate an embedding for the semantic query.
client = OpenAI()
response = client.embeddings.create(
model=required_env("EMBEDDING_MODEL"),input=SEMANTIC_QUERY,)
query_vector = array.array("f", response.data[0].embedding)with oracledb.connect(
user=user,
password=required_env("DB_PASSWORD"),
dsn=required_env("DB_DSN"),)as connection:with connection.cursor()as cursor:# Rank documents by semantic similarity.
cursor.execute("""
SELECT title,
VECTOR_DISTANCE(embedding, :query_vector, COSINE)
FROM documents
ORDER BY VECTOR_DISTANCE(embedding, :query_vector, COSINE)
FETCH EXACT FIRST 3 ROWS ONLY
""",
query_vector=query_vector,)
semantic_rows = cursor.fetchall()# Compare semantic results with an exact phrase predicate.
cursor.execute("""
SELECT title
FROM documents
WHERE LOWER(title || ' ' || content)
LIKE '%' || :phrase || '%'
ORDER BY title
FETCH FIRST 3 ROWS ONLY
""",
phrase=KEYWORD_PHRASE.lower(),)
keyword_rows = cursor.fetchall()print(f"Semantic query: {SEMANTIC_QUERY}")print(f"Keyword phrase: {KEYWORD_PHRASE}")print("\nSemantic results:")for rank,(title, distance)inenumerate(semantic_rows, start=1):print(f"{rank}. {title}")print(f" distance: {float(distance):.6f}")print("\nKeyword results:")if keyword_rows:for rank,(title,)inenumerate(keyword_rows, start=1):print(f"{rank}. {title}")else:print("0 exact phrase matches")if __name__ =="__main__":
main()Propulsé par
La recherche sémantique doit retourner des documents pertinents même si l’expression exacte n’est pas présente.
Semantic query: Where should an AI app keep meaning-based search data?
Keyword phrase: meaning-based search data
Semantic results:
1. Oracle AI Vector Search
distance: <cosine distance from your run>
2. Semantic Search for Applications
distance: <cosine distance from your run>
3. Python Database Code
distance: <cosine distance from your run>
Keyword results:
0 exact phrase matchesPropulsé par
Les prédicats SQL traditionnels restent essentiels pour les filtres, jointures, droits et correspondances exactes. La recherche vectorielle ajoute un signal de classement fondé sur le sens, que l’on peut combiner aux données relationnelles quand l’application a besoin de récupération sémantique.
Étape 8 : ajouter et valider un index vectoriel
Enfin, nous allons créer un index vectoriel et valider qu’Oracle Database le signale comme un index valide détenu par le schéma de démo.
Cette étape illustre la création d’index ; notre jeu de données minuscule n’est pas suffisant pour tirer des conclusions de performance.
Sans index, Oracle Database peut comparer exactement le vecteur de requête à chaque vecteur stocké. Cette approche convient aux très petits jeux et pour l’apprentissage.
Avec de grands jeux, les index vectoriels approchés réduisent l’espace de recherche pour des réponses rapides tout en trouvant des voisins proches.
Choisissez la famille d’index après avoir considéré taille de données, objectifs de latence, exigences de rappel, budget mémoire et fréquence de mise à jour des vecteurs.
La requête finale confirme que la recherche sémantique renvoie toujours des résultats après la création de l’index.
Nous n’utiliserons pas EXPLAIN PLAN ni DBMS_XPLAN ici : le tutoriel valide la création via les métadonnées de schéma, pas via le plan d’exécution.
Créer le script
Enregistrez le code suivant sous 08_create_vector_index.py.
import array
import os
import oracledb
from openai import OpenAI
INDEX_NAME ="DOCUMENT_EMBEDDING_IDX"
QUERY_TEXT ="Where should an AI app keep meaning-based search data?"
ADMIN_USERS ={"SYS","SYSTEM","PDBADMIN"}defrequired_env(name):
value = os.getenv(name)ifnot value:raise SystemExit(f"Set {name} before running this script.")return value
defmain():
user = required_env("DB_USER")if user.upper()in ADMIN_USERS:raise SystemExit("Use the vector_demo application user, not an admin user.")
required_env("OPENAI_API_KEY")# Generate the query vector used for the validation search.
client = OpenAI()
response = client.embeddings.create(
model=required_env("EMBEDDING_MODEL"),input=QUERY_TEXT,)
query_vector = array.array("f", response.data[0].embedding)with oracledb.connect(
user=user,
password=required_env("DB_PASSWORD"),
dsn=required_env("DB_DSN"),)as connection:with connection.cursor()as cursor:# Remove a prior index so the script can be rerun safely.try:
cursor.execute(f"DROP INDEX {INDEX_NAME}")except oracledb.DatabaseError as exc:
error = exc.args[0]if error.code !=1418:raise# Create an approximate neighbor-partitions vector index.
cursor.execute("""
CREATE VECTOR INDEX document_embedding_idx
ON documents (embedding)
ORGANIZATION NEIGHBOR PARTITIONS
DISTANCE COSINE
WITH TARGET ACCURACY 95
""")# Confirm that Oracle reports the vector index as valid.
cursor.execute("""
SELECT index_name, index_type, status
FROM user_indexes
WHERE index_name = :index_name
""",
index_name=INDEX_NAME,)
index_row = cursor.fetchone()# Confirm that semantic search still returns rows after index creation.
cursor.execute("""
SELECT title
FROM documents
ORDER BY VECTOR_DISTANCE(embedding, :query_vector, COSINE)
FETCH EXACT FIRST 3 ROWS ONLY
""",
query_vector=query_vector,)
rows = cursor.fetchall()ifnot index_row:raise SystemExit("Vector index was not found in USER_INDEXES.")print("Created vector index DOCUMENT_EMBEDDING_IDX.")print("\nIndex validation:")print(f"Index name: {index_row[0]")}print(f"Index type: {index_row[1]")}print(f"Status: {index_row[2]")}
result_count =len(rows)print("\nSemantic search still returns "f"{result_count} results after index creation.")if __name__ =="__main__":
main()Propulsé par
La sortie doit inclure une ligne pour DOCUMENT_EMBEDDING_IDX, avec INDEX_TYPE à VECTOR et STATUS à VALID.
Created vector index DOCUMENT_EMBEDDING_IDX.
Index validation:
Index name: DOCUMENT_EMBEDDING_IDX
Index type: VECTOR
Status: VALID
Semantic search still returns 3 results after index creation.Propulsé par
USER_INDEXES confirme que l’index existe et est valide. Cela ne prouve pas qu’une requête particulière l’a utilisé, et ce tutoriel n’emploie pas la sortie de plan d’exécution comme méthode de validation.
En production, nous testerions avec un volume réaliste, des patrons de requêtes réels et des objectifs de performance.
Astuces et dépannage pour Oracle AI Vector Search
Le conteneur de base est encore en démarrage
Attendez la fin du démarrage, puis relancez docker logs oracle-free-26ai-vector. La base doit être prête avant que Python puisse se connecter à localhost:1521/FREEPDB1.
Le port 1521 est déjà utilisé
Arrêtez le service local en conflit ou modifiez le mapping de ports Docker. Mettez à jour DB_DSN si le port hôte change.
La connexion à la base échoue
Vérifiez DB_USER, DB_PASSWORD et DB_DSN. Utilisez FREEPDB1 dans le DSN, et connectez les scripts applicatifs en tant que vector_demo, pas SYS, SYSTEM ou PDBADMIN.
La clé API d’embedding est absente
Les étapes 1–3 concernent uniquement la base. Les étapes 4–8 nécessitent OPENAI_API_KEY et peuvent générer des coûts API.
Une dimension vectorielle ne correspond pas
Exécutez 04_check_embedding_dimension.py, mettez à jour EMBEDDING_DIM, relancez 03_create_documents_table.py et rechargez les embeddings avec 05_insert_embeddings.py.
Échec d’un bind de vecteur
Assurez-vous que chaque bind de vecteur en FLOAT32 utilise array.array("f", values). Le tutoriel applique ce format pour les vecteurs manuels, les embeddings stockés et les vecteurs de requête.
Les classements sémantiques diffèrent de l’exemple
C’est attendu. Les fournisseurs d’embedding peuvent mettre à jour les modèles, et les distances flottantes peuvent varier entre exécutions.
La création de l’index vectoriel échoue
Confirmez que la table documents existe, qu’elle appartient au schéma vector_demo et que DOCUMENT_EMBEDDING_IDX n’est pas laissé par une exécution partielle.
Se préparer à la production
Utilisez oracledb.create_pool() pour le pooling de connexions, mesurez sur des volumes réalistes, révisez sécurité et gestion des secrets, et ajustez les index selon des patrons de requêtes réels.
Arrêter et supprimer le conteneur
Une fois le tutoriel terminé, arrêtez et supprimez le conteneur local.
docker stop oracle-free-26ai-vector
dockerrm oracle-free-26ai-vectorPropulsé par
Conclusion
Nous avons construit un flux local de recherche sémantique avec Oracle AI Vector Search, Oracle Database Free 26ai et Python.
Nous avons commencé avec des valeurs VECTOR(3, FLOAT32) écrites à la main, inséré des embeddings issus d’un modèle via array.array("f", values), interrogé des documents similaires avec VECTOR_DISTANCE(), comparé la récupération sémantique à un prédicat d’expression exacte, et validé un index vectoriel via USER_INDEXES.
Cette approche convient bien lorsque les embeddings doivent rester à côté des données relationnelles et que l’on souhaite un stockage et une recherche visibles en SQL sans ajouter de base vectorielle séparée pour le flux local.
La démo est volontairement petite : elle enseigne les briques fondamentales, pas l’échelle de production. Pour des applications plus grandes, mesurez avec des données réalistes, révisez sécurité et privilèges, utilisez le pooling de connexions et validez les choix d’indexation sur des requêtes réelles.
Pour aller plus loin :
Oracle AI Vector Search User’s Guide est la référence principale pour le stockage, la recherche, l’indexation vectorielle et les fonctionnalités SQL associées.
Oracle AI Vector Search LiveLabs propose des ateliers pratiques sur les embeddings, la recherche exacte et approchée, la recherche d’images et la génération augmentée par récupération.
FAQs
Qu’est-ce qu’Oracle AI Vector Search ?⌄
Oracle AI Vector Search regroupe des fonctionnalités d’Oracle Database pour stocker, indexer et interroger des embeddings vectoriels aux côtés de données relationnelles.
Ai-je besoin d’une clé API OpenAI pour suivre le tutoriel ?⌄
Les étapes de vecteurs manuels et de configuration de la base ne requièrent pas de clé API. Les étapes 4 à 8 nécessitent un fournisseur d’embedding et la variable OPENAI_API_KEY configurée.
Pourquoi EMBEDDING_DIM doit-il correspondre au modèle d’embedding ?⌄
La dimension de la colonne VECTOR doit être égale au nombre de valeurs renvoyées par le modèle d’embedding. Un écart entraîne un échec à l’insertion.
Quelles métriques de distance le tutoriel utilise-t-il ?⌄
L’exemple avec vecteurs manuels utilise la distance euclidienne. Les exemples de recherche sémantique utilisent la distance cosinus.
Un index vectoriel valide prouve‑t‑il qu’une requête l’a utilisé ?⌄
Non. USER_INDEXES confirme que l’index existe et qu’il est valide, mais cela ne prouve pas qu’une requête donnée l’a utilisé.
Mark Nelson est architecte et Developer Evangelist chez Oracle. Il travaille à la convergence de l'IA, des microservices et des technologies de bases de données. Blogueur actif, auteur publié, relecteur technique chez Manning Publications, Section Leader pour Stanford Code in Place et mentor chez DeepLearning.ai. Il intervient régulièrement auprès des Java User Groups et Oracle User Groups, dans des meetups IA et lors de grandes conférences. Passionné par l'apprentissage et la transmission, il cumule plus de trente ans d'expérience dans l'industrie, chez IBM et Oracle.
Initiez-vous aux structures de données de Python : apprenez-en plus sur les types de données et les structures de données primitives et non primitives, telles que les chaînes de caractères, les listes, les piles, etc.
Tutoriel complet d'introduction aux boucles Python. Apprenez et pratiquez les boucles while et for, les boucles imbriquées, les mots-clés break et continue, la fonction range et bien plus encore.
Apprenez à intégrer l'IA dans des applications logicielles en utilisant des API et des bibliothèques open source. Commencez dès aujourd'hui votre parcours pour devenir AI Engineer !
Dans ce tutoriel, nous allons construire une démo locale de recherche sémantique avec Oracle AI Vector Search, Python et Oracle Database Free 26ai.
Nous commencerons avec des vecteurs tridimensionnels saisis à la main pour visualiser le calcul de distance, puis nous générerons des embeddings de texte et les interrogerons depuis Oracle Database avec SQL.
Ce tutoriel s’adresse aux développeurs Python et SQL qui découvrent la recherche vectorielle et qui sont à l’aise avec Docker, les variables d’environnement, les packages Python et l’installation d’une base locale.
Les applications dopées à l’IA ont besoin d’une recherche qui comprend le sens, pas seulement les mots exacts. Une application de support, un portail de documentation ou un outil interne de connaissance doit pouvoir retrouver « stockage de base de données pour la recherche IA » même si le meilleur document correspondant dit « store vector embeddings in native columns ».
Vector embeddings rendent cela possible en représentant le texte sous forme de vecteurs numériques. Oracle AI Vector Search permet de stocker ces vecteurs directement dans Oracle Database, de les interroger en SQL et de conserver les embeddings à côté des données relationnelles de l’application.
Dans ce flux de travail local, nous n’avons pas besoin d’une base de données vectorielle séparée.
Nous exécuterons Oracle Database Free 26ai en local, nous connecterons Python en mode
oracledbThin, stockerons d’abord des vecteurs manuels, puis des embeddings OpenAI, lancerons une recherche sémantique, comparerons la récupération sémantique à un prédicat d’exacte correspondance de phrase, et créerons un index vectoriel validé viaUSER_INDEXES.À la fin, nous aurons un flux de travail de recherche sémantique piloté par Python qui stocke les embeddings dans Oracle Database et récupère localement les
documentsles plus similaires.Qu’est-ce qu’Oracle AI Vector Search ?
Oracle AI Vector Search regroupe des fonctionnalités d’Oracle Database pour stocker, indexer et interroger des embeddings vectoriels. Un embedding est une liste de taille fixe de nombres qui représente le sens d’un texte, d’images ou d’autres données dans une forme que la base peut comparer mathématiquement.
Un modèle d’embedding génère ces vecteurs numériques. Il prend en entrée une phrase, un paragraphe, la description d’une image ou un extrait de code, et renvoie un vecteur avec un nombre fixe de dimensions.
Des entrées similaires doivent produire des vecteurs proches, tandis que des entrées sans rapport doivent être plus éloignées. Il faut donc utiliser le même modèle d’embedding pour les documents stockés et les requêtes entrantes, car les distances n’ont de sens que si les vecteurs partagent le même repère.
Dans ce tutoriel, les vecteurs manuels sont volontairement petits pour que nous puissions inspecter les calculs. Les véritables embeddings de texte sont bien plus grands, car le modèle a besoin de suffisamment de dimensions pour encoder des relations plus fines entre les mots, les expressions et les sujets.
La recherche vectorielle classe les lignes selon la distance entre vecteurs. Pour les requêtes de distance euclidienne et cosinus, plus la distance est petite, plus la correspondance est proche. Dans ce tutoriel, nous commencerons avec une petite colonne
VECTOR(3, FLOAT32)afin d’observer directement le comportement des distances, puis nous passerons à des embeddingsVECTOR(1536, FLOAT32)générés à partir de texte.Figure 1. Flux Oracle AI Vector Search
Oracle AI Vector Search stocke les embeddings dans une colonne VECTOR native et classe les résultats par distance vectorielle.
Oracle Database est utile lorsque les embeddings doivent vivre à côté des données relationnelles de l’application comme les identifiants de documents, titres, contenus, utilisateurs, produits, tickets ou métadonnées.
Certaines applications utilisent une base vectorielle ou un moteur de recherche séparé pour des charges de travail spécialisées, mais pour ce flux local de recherche sémantique, Oracle Database fournit le stockage vectoriel et les fonctions de recherche nécessaires.
Fonctionnalités clés d’Oracle AI Vector Search
Nous utiliserons quatre fonctionnalités dans la démo : stockage vectoriel natif, fonctions de distance, index vectoriels et intégration relationnelle.
Type de données vectorielles natif
Oracle Database prend en charge des colonnes
VECTORnatives avec dimensions explicites et formats d’éléments. Dans la démo, nous utiliseronsVECTOR(3, FLOAT32)pour les vecteurs manuels etVECTOR(1536, FLOAT32)pour le modèle d’embedding par défauttext-embedding-3-small.Fonctions et opérateurs de distance
Les exemples exécutables utilisent
VECTOR_DISTANCE()car la métrique de distance reste explicite en SQL.Nous utiliserons la distance euclidienne pour l’exemple manuel, puis la distance cosinus pour les embeddings de texte.
Oracle Database inclut également des opérateurs abrégés de distance vectorielle et des comportements liés au produit scalaire, mais ce tutoriel conserve du SQL exécutable avec la fonction explicite
VECTOR_DISTANCE().Différentes métriques répondent à des nuances différentes de « proximité ».
Pour un petit tutoriel, la distance cosinus est un bon défaut pour des embeddings de texte car elle se concentre sur la direction, souvent bien corrélée à la similarité sémantique.
La distance euclidienne est plus facile à visualiser avec des vecteurs écrits à la main, et les comparaisons de type produit scalaire sont utiles dans certains systèmes lorsque la magnitude ou la normalisation des vecteurs fait partie du design du modèle.
Métrique
Ce qu’elle compare
Bon usage
Points d’attention
Cosinus
Direction du vecteur
Embeddings de texte et similarité sémantique
Résultats dépendants du même modèle d’embedding et d’un prétraitement cohérent
Euclidienne
Distance en ligne droite
Petits exemples, intuition géométrique, certains vecteurs de caractéristiques numériques
La magnitude influe sur la distance, donc l’échelle peut compter
Produit scalaire
Direction et magnitude ensemble
Flux pensés autour de vecteurs normalisés ou d’un scoring par produit interne
Le sens du score et les règles de normalisation doivent être comprises avant toute comparaison
Index vectoriels
La recherche vectorielle exacte est utile pour la justesse et les petits jeux de données. Quand les données grossissent, les index vectoriels permettent des recherches approchées de plus proches voisins.
Oracle AI Vector Search inclut des index en mémoire sous forme de graphes de voisins, souvent associés aux recherches de type HNSW, et des index par partitions de voisins, souvent associés au partitionnement de type IVF.
Dans cette démo locale, nous utilisons
ORGANIZATION NEIGHBOR PARTITIONSet validons l’index avecUSER_INDEXES.Les index approximatifs échangent un peu de certitude d’une recherche exhaustive contre une récupération plus rapide à l’échelle.
Le bon type d’index dépend de la charge, du volume, du rythme de mise à jour et de l’objectif de rappel.
Ce tutoriel utilise un index de type IVF par partitions de voisins pour garder l’installation locale simple et illustrer concrètement la création d’index sans transformer le tutoriel en guide d’optimisation.
Famille d’index
Principe
Forces
Compromis
Quand l’utiliser
IVF / partitions de voisins
Partitionner l’espace vectoriel, puis chercher dans les partitions probables
Modèle mental simple, pratique pour beaucoup de jeux chargés par lots
Le rappel et la vitesse dépendent du partitionnement et des réglages de recherche
Nous voulons une voie simple de recherche approchée pour un jeu de données en croissance
HNSW / graphe de voisins
Construire un graphe reliant les vecteurs proches pour une traversée rapide
Bon profil rappel/latence pour de nombreuses charges de plus proches voisins
Plus orienté mémoire, et la configuration peut compter davantage
Nous avons besoin d’une faible latence et pouvons allouer mémoire et efforts de tuning
Intégration aux requêtes relationnelles
Une colonne vectorielle peut cohabiter avec des colonnes relationnelles classiques. Notre table documents stockera le titre, le contenu et l’embedding ensemble, afin que SQL renvoie à la fois le score de similarité et le texte d’origine.
Comment démarrer avec Oracle AI Vector Search
Nous utiliserons un chemin d’installation local : Oracle Database Free 26ai dans Docker, le service
FREEPDB1et un utilisateur applicatif dédiévector_demo.Les concepts de recherche vectorielle sont accessibles, mais la mise en place est intermédiaire : nous utilisons Docker, un schéma de base, des packages Python, des variables d’environnement et une clé d’API d’embedding.
Prérequis
Il vous faudra :
Cette démo nécessite une version/environnement Oracle Database incluant les fonctionnalités vectorielles utilisées ici, notamment les colonnes
VECTOR,VECTOR_DISTANCE()etCREATE VECTOR INDEX.Le chemin local utilise Oracle Database Free 26ai avec le tag d’image ci-dessous, et le DSN utilise le service de base enfichable
FREEPDB1.Les étapes avec vecteurs manuels ne nécessitent pas de clé
OpenAI. Les étapes sémantiques envoient le texte d’exemple des documents et des requêtes au fournisseur d’embedding configuré, donc nous n’utiliserons que du texte d’exemple/non sensible.Ce tutoriel utilise
oracledb, le pilote Python actuel pour Oracle Database.python-oracledbs’exécute en mode Thin par défaut, donc cette démo locale ne nécessite pas les bibliothèques Oracle Client. Le mode Thick est utile dans d’autres déploiements Oracle Database, mais nous n’appellerons pasoracledb.init_oracle_client()ici.Démarrer Oracle Database Free 26ai en local
Créez un répertoire de projet pour les scripts que nous allons écrire.
Démarrez Oracle Database Free 26ai avec l’image locale du conteneur.
Consultez les journaux du conteneur et attendez que la base indique que le démarrage est terminé.
FREEPDB1est le service de base enfichable utilisé par ce chemin local avec Oracle Database Free. Notre DSN Python seralocalhost:1521/FREEPDB1.Créer le schéma vector_demo dans FREEPDB1
Utilisez
SYSuniquement pour l’étape de configuration du schéma. Le mot de passe dans la commande sqlplus correspond à la valeur ORACLE_PWD de la commande docker run ; le mot de passe dans CREATE USER est le mot de passe applicatif que nous exporterons enDB_PASSWORD.Exécutez la configuration dans le conteneur de base de données.
Il s’agit d’un raccourci de développement local pour la démo. CREATE SEQUENCE est nécessaire car les tables utilisent des colonnes identité.
En production, nous reverrions les privilèges avec un administrateur de base et appliquerions le principe du moindre privilège adapté à la charge applicative.
Installer les dépendances Python
Créez et activez un environnement virtuel.
Installez les packages Python utilisés par la démo.
Définir les variables d’environnement
Stockez les identifiants de base et les réglages d’embedding dans des variables d’environnement plutôt que de les coder en dur dans les fichiers Python.
OPENAI_API_KEYn’est requis que pour les étapes d’embedding et de recherche sémantique.EMBEDDING_DIMdoit correspondre au nombre de dimensions renvoyées par le modèle choisi.Projet démo Oracle AI Vector Search
Nous construirons la démo en huit jalons. Chaque script ajoute un concept et produit une sortie à vérifier avant d’avancer.
La partie « base uniquement » est complète après les étapes 1 à 3. À ce stade, nous nous serons connectés à Oracle Database, aurons stocké des vecteurs manuels, les aurons interrogés par distance et créé la table sémantique. La clé API
OpenAIdevient nécessaire à l’étape 4.Étape 1 : se connecter à la base locale
Nous allons d’abord vérifier que Python peut se connecter à Oracle Database en tant qu’utilisateur applicatif
vector_demo. Ce script litDB_USER, DB_PASSWORDetDB_DSNà partir de l’environnement, puis affiche le mode du pilote et la version de la base.Créer le script
Enregistrez le code suivant sous
01_check_connection.py.Exécuter le script
Lancez la vérification de connexion.
Sortie attendue
La sortie doit confirmer que la connexion fonctionne et que le pilote est en mode Thin.
Nous savons maintenant que la base locale, le nom de service, les identifiants et le pilote Python fonctionnent avant de créer des tables vectorielles.
Étape 2 : se forger une intuition avec des vecteurs manuels
Avant d’introduire les modèles d’embedding, stockons trois petits vecteurs faciles à raisonner. L’appel
array.array("f", values)crée un tableau de flottants 32 bits quepython-oracledbpeut lier à une colonneVECTOR(..., FLOAT32).Figure 2. Vecteurs manuels et distance euclidienne.
L’exemple manuel utilise la distance euclidienne. Le vecteur « apple » a une distance de 0,0000 car il correspond au vecteur de requête. Le vecteur « banana » est classé second car sqrt((1.0 - 0.9)^2 + (0.0 - 0.1)^2 + (0.0 - 0.0)^2) = 0,1414.
Créer le script
Enregistrez le code suivant sous
02_manual_vectors.py.Exécuter le script
Lancez le script de vecteurs manuels.
Sortie attendue
Le vecteur identique apparaît en premier avec une distance de 0,0000, et « banana » en second.
C’est l’idée centrale de la recherche vectorielle : les lignes sont classées par proximité mathématique avec un vecteur de requête. Les modèles d’embedding génèrent des vecteurs plus grands, mais le comportement côté base reste le même.
Étape 3 : créer la table de documents sémantiques
Maintenant que les vecteurs fonctionnent, créons une table de type applicatif. Le point clé est que la dimension de la colonne vectorielle doit correspondre à la dimension de sortie du modèle d’embedding.
La dimension fait partie du contrat de la table. Si un modèle renvoie 1 536 nombres, la colonne doit être déclarée en
VECTOR(1536, FLOAT32).Si nous passons ensuite à un modèle avec une longueur différente, il faudra recréer ou migrer la colonne vectorielle pour conserver la compatibilité des insertions et requêtes.
Comme le DDL ne permet pas de lier la dimension vectorielle via une variable SQL classique, le script convertit
EMBEDDING_DIMen entier avant de l’utiliser dans CREATE TABLE.Créer le script
Enregistrez le code suivant sous
03_create_documents_table.py.Exécuter le script
Lancez le script de création de table.
Sortie attendue
La sortie doit afficher le modèle d’embedding configuré et la dimension vectorielle.
Nous avons terminé la partie base de données. Oracle Database peut stocker et comparer des vecteurs en local ; passons maintenant des vecteurs écrits à la main aux embeddings générés à partir de texte.
Étape 4 : vérifier la dimension du modèle d’embedding
Avant d’insérer des embeddings, demandons au modèle un vecteur et vérifions sa longueur. Cela évite l’erreur la plus courante des tables vectorielles : insérer un vecteur dont la longueur ne correspond pas à la dimension de la colonne
VECTOR.Un modèle d’embedding n’est pas qu’un convertisseur texte→nombres ; il définit l’espace de sens de l’application. Tous les embeddings de documents et de requêtes de cette démo doivent venir du même modèle.
Utiliser un seul modèle garantit qu’une petite distance signifie un sens similaire, plutôt que deux vecteurs sans lien qui auraient par hasard une forme proche. Le modèle détermine aussi la longueur du vecteur, d’où la vérification préalable.
Créer le script
Enregistrez le code suivant sous
04_check_embedding_dimension.py.Exécuter le script
Exécutez la vérification de dimension.
Sortie attendue
Pour le modèle et la dimension par défaut, la sortie doit ressembler à ceci.
Si nous choisissons plus tard un autre modèle d’embedding, mettez à jour
EMBEDDING_MODEL, réglezEMBEDDING_DIMà la longueur renvoyée et recréez la tabledocuments.Étape 5 : générer et insérer les embeddings des documents
Nous allons maintenant générer des embeddings pour un petit jeu de données autonome et les insérer dans Oracle Database.
Chaque embedding est converti en
array.array("f", embedding)avant liaison pour correspondre à la colonne vectorielle enFLOAT32.Créer le script
Enregistrez le code suivant sous
05_insert_embeddings.py.Exécuter le script
Lancez le script d’insertion.
Sortie attendue
Le nombre de lignes doit correspondre aux sept
documentsintégrés.Nous avons maintenant le texte et les embeddings stockés ensemble dans Oracle Database. Les
documentssans rapport sur la guitare et la soupe sont inclus, afin que les résultats présentent des correspondances proches et éloignées évidentes.Étape 6 : exécuter une requête de recherche sémantique
Ensuite, nous allons embedder une requête en langage naturel et la comparer aux embeddings stockés. Ce script utilise la distance cosinus, couramment utilisée pour les embeddings de texte car elle privilégie la direction du vecteur plutôt que sa magnitude brute.
Pour la recherche sémantique, la requête passe par le même modèle d’embedding que les
documents. Nous ne demandons pas à SQL de « comprendre » la phrase anglaise directement.Nous demandons au modèle de convertir la phrase en vecteur, puis à Oracle Database de classer les vecteurs stockés par leur distance à ce vecteur de requête.
Créer le script
Enregistrez le code suivant sous
06_semantic_search.py.Exécuter le script
Lancez le script de recherche sémantique.
Sortie attendue
Les classements et distances exacts peuvent varier si le modèle d’embedding change. Cependant, les
documentssur Oracle AI Vector Search, la recherche sémantique, le code Python et l’indexation vectorielle devraient figurer en tête.Pour les requêtes de distance euclidienne et cosinus de ce tutoriel, des valeurs plus faibles indiquent des correspondances plus proches.
Le produit scalaire est une autre approche utile dans de nombreux flux de recherche vectorielle, notamment quand la magnitude ou la normalisation importent, mais le sens du score et la normalisation doivent être traités avec soin.
Nous garderons du code exécutable avec euclidienne et cosinus pour faciliter l’interprétation.
Si nous normalisons nous‑mêmes les embeddings dans une future application, il faudra normaliser de la même façon les embeddings stockés et ceux des requêtes ; sinon, distances et classements peuvent changer.
Étape 7 : comparer la recherche sémantique à une correspondance de phrase
La recherche sémantique est utile car elle ne requiert pas la présence exacte de la même expression dans le document.
Comparons la requête sémantique à un simple prédicat d’expression exacte.
Ce n’est pas une démo de moteur de recherche plein texte ; c’est une petite comparaison SQL qui met en évidence la différence entre appariement littéral et classement fondé sur le sens.
Créer le script
Enregistrez le code suivant sous
07_semantic_vs_keyword.py.Exécuter le script
Lancez le script de comparaison.
Sortie attendue
La recherche sémantique doit retourner des
documentspertinents même si l’expression exacte n’est pas présente.Les prédicats SQL traditionnels restent essentiels pour les filtres, jointures, droits et correspondances exactes. La recherche vectorielle ajoute un signal de classement fondé sur le sens, que l’on peut combiner aux données relationnelles quand l’application a besoin de récupération sémantique.
Étape 8 : ajouter et valider un index vectoriel
Enfin, nous allons créer un index vectoriel et valider qu’Oracle Database le signale comme un index valide détenu par le schéma de démo.
Cette étape illustre la création d’index ; notre jeu de données minuscule n’est pas suffisant pour tirer des conclusions de performance.
Sans index, Oracle Database peut comparer exactement le vecteur de requête à chaque vecteur stocké. Cette approche convient aux très petits jeux et pour l’apprentissage.
Avec de grands jeux, les index vectoriels approchés réduisent l’espace de recherche pour des réponses rapides tout en trouvant des voisins proches.
Choisissez la famille d’index après avoir considéré taille de données, objectifs de latence, exigences de rappel, budget mémoire et fréquence de mise à jour des vecteurs.
La requête finale confirme que la recherche sémantique renvoie toujours des résultats après la création de l’index.
Nous n’utiliserons pas EXPLAIN PLAN ni DBMS_XPLAN ici : le tutoriel valide la création via les métadonnées de schéma, pas via le plan d’exécution.
Créer le script
Enregistrez le code suivant sous
08_create_vector_index.py.Exécuter le script
Lancez le script d’indexation.
Sortie attendue
La sortie doit inclure une ligne pour
DOCUMENT_EMBEDDING_IDX, avecINDEX_TYPEàVECTORetSTATUSàVALID.USER_INDEXESconfirme que l’index existe et est valide. Cela ne prouve pas qu’une requête particulière l’a utilisé, et ce tutoriel n’emploie pas la sortie de plan d’exécution comme méthode de validation.En production, nous testerions avec un volume réaliste, des patrons de requêtes réels et des objectifs de performance.
Astuces et dépannage pour Oracle AI Vector Search
Le conteneur de base est encore en démarrage
Attendez la fin du démarrage, puis relancez
docker logs oracle-free-26ai-vector. La base doit être prête avant que Python puisse se connecter àlocalhost:1521/FREEPDB1.Le port 1521 est déjà utilisé
Arrêtez le service local en conflit ou modifiez le mapping de ports Docker. Mettez à jour
DB_DSNsi le port hôte change.La connexion à la base échoue
Vérifiez
DB_USER, DB_PASSWORDetDB_DSN. UtilisezFREEPDB1dans le DSN, et connectez les scripts applicatifs en tant quevector_demo, pasSYS, SYSTEMouPDBADMIN.La clé API d’embedding est absente
Les étapes 1–3 concernent uniquement la base. Les étapes 4–8 nécessitent
OPENAI_API_KEYet peuvent générer des coûts API.Une dimension vectorielle ne correspond pas
Exécutez
04_check_embedding_dimension.py, mettez à jourEMBEDDING_DIM, relancez03_create_documents_table.pyet rechargez les embeddings avec05_insert_embeddings.py.Échec d’un bind de vecteur
Assurez-vous que chaque bind de vecteur en
FLOAT32utilisearray.array("f", values). Le tutoriel applique ce format pour les vecteurs manuels, les embeddings stockés et les vecteurs de requête.Les classements sémantiques diffèrent de l’exemple
C’est attendu. Les fournisseurs d’embedding peuvent mettre à jour les modèles, et les distances flottantes peuvent varier entre exécutions.
La création de l’index vectoriel échoue
Confirmez que la table
documentsexiste, qu’elle appartient au schémavector_demoet queDOCUMENT_EMBEDDING_IDXn’est pas laissé par une exécution partielle.Se préparer à la production
Utilisez
oracledb.create_pool()pour le pooling de connexions, mesurez sur des volumes réalistes, révisez sécurité et gestion des secrets, et ajustez les index selon des patrons de requêtes réels.Arrêter et supprimer le conteneur
Une fois le tutoriel terminé, arrêtez et supprimez le conteneur local.
Conclusion
Nous avons construit un flux local de recherche sémantique avec Oracle AI Vector Search, Oracle Database Free 26ai et Python.
Nous avons commencé avec des valeurs
VECTOR(3, FLOAT32)écrites à la main, inséré des embeddings issus d’un modèle viaarray.array("f", values), interrogé desdocumentssimilaires avecVECTOR_DISTANCE(), comparé la récupération sémantique à un prédicat d’expression exacte, et validé un index vectoriel viaUSER_INDEXES.Cette approche convient bien lorsque les embeddings doivent rester à côté des données relationnelles et que l’on souhaite un stockage et une recherche visibles en SQL sans ajouter de base vectorielle séparée pour le flux local.
La démo est volontairement petite : elle enseigne les briques fondamentales, pas l’échelle de production. Pour des applications plus grandes, mesurez avec des données réalistes, révisez sécurité et privilèges, utilisez le pooling de connexions et validez les choix d’indexation sur des requêtes réelles.
Pour aller plus loin :