Oracle AI Vector Search Tutorial: Embeddings mit Python speichern und abfragen
Dieses Tutorial führt in Oracle AI Vector Search ein, erklärt die Kernfunktionen und begleitet dich durch ein praxisnahes lokales Projekt. Außerdem behandelt es Setup, semantische Suche, Vektorindizes und häufige Fehlerbehebung.
In diesem Tutorial bauen wir eine lokale Semantic-Search-Demo mit Oracle AI Vector Search, Python und Oracle Database Free 26ai.
Wir starten mit handgeschriebenen dreidimensionalen Vektoren, damit die Distanzberechnung nachvollziehbar ist, erzeugen dann Text-Embeddings und fragen sie per SQL aus Oracle Database ab.
Dieses Tutorial richtet sich an Python- und SQL-Entwickler, die neu bei Vektorsuche sind und sich mit Docker, Umgebungsvariablen, Python-Paketen und lokaler Datenbankeinrichtung wohlfühlen.
KI-gestützte Anwendungen brauchen Suche, die Bedeutung versteht – nicht nur exakte Wörter. Eine Support-App, ein Doku-Portal oder ein internes Wissenstool sollte „Datenbankspeicher für KI-Suche“ finden, auch wenn im besten Treffer „Vektor-Embeddings in nativen Spalten speichern“ steht.
Vektor-Embeddings machen das möglich, indem sie Text als numerische Vektoren darstellen. Oracle AI Vector Search erlaubt es, diese Vektoren direkt in Oracle Database zu speichern, mit SQL abzufragen und Embeddings neben relationalen Anwendungsdaten zu halten.
Für diesen lokalen Workflow brauchen wir keine separate Vektordatenbank.
Wir starten Oracle Database Free 26ai lokal, verbinden uns aus Python im oracledb Thin-Modus, speichern zuerst manuelle Vektoren, dann OpenAI-Embeddings, führen semantische Suche aus, vergleichen semantische Ergebnisse mit einem einfachen exakten Phrasenprädikat und erstellen einen Vektorindex, den wir über USER_INDEXES validieren.
Am Ende haben wir einen funktionierenden, Python-basierten Semantic-Search-Workflow, der Embeddings in Oracle Database speichert und die ähnlichsten documents lokal abruft.
Was ist Oracle AI Vector Search?
Oracle AI Vector Search ist ein Funktionsumfang in Oracle Database zum Speichern, Indizieren und Abfragen von Vektor-Embeddings. Ein Vektor-Embedding ist eine Liste fester Länge mit Zahlen, die die Bedeutung von Text, Bildern oder anderen Daten so repräsentiert, dass eine Datenbank sie mathematisch vergleichen kann.
Ein Embedding-Modell erzeugt die numerischen Vektoren. Es nimmt als Eingabe z. B. einen Satz, Absatz, eine Bildbeschreibung oder einen Code-Snippet und gibt einen Vektor mit fester Dimensionalität zurück.
Ähnliche Eingaben sollten Vektoren nahe beieinander ergeben, während Unzusammenhängendes weiter auseinanderliegt. Deshalb müssen wir dasselbe Embedding-Modell für gespeicherte documents und ankommende Queries verwenden – Distanzen sind nur sinnvoll, wenn die Vektoren dasselbe Koordinatensystem teilen.
In diesem Tutorial sind die manuellen Vektoren bewusst klein, damit wir die Mathematik begutachten können. Die echten Text-Embeddings sind deutlich größer, damit das Modell feinere Beziehungen zwischen Wörtern, Phrasen und Themen abbilden kann.
Die Vektorsuche sortiert Zeilen nach Distanz zwischen Vektoren. Für euklidische und Kosinus-Distanzen bedeuten kleinere Werte engere Übereinstimmungen. In diesem Tutorial beginnen wir mit einer kleinen VECTOR(3, FLOAT32)-Spalte, um das Distanzverhalten direkt zu sehen, und wechseln dann zu VECTOR(1536, FLOAT32)-Embeddings aus Text.
Abbildung 1. Ablauf von Oracle AI Vector Search
Oracle AI Vector Search speichert Embeddings in einer nativen VECTOR-Spalte und sortiert Ergebnisse nach Vektordistanz.
Oracle Database ist hilfreich, wenn Embeddings neben relationalen Anwendungsdaten wie Dokument-IDs, Titeln, Inhalten, Nutzern, Produkten, Tickets oder Metadaten liegen sollen.
Manche Anwendungen nutzen eine separate Vektordatenbank oder Suchengine für spezialisierte Retrieval-Workloads. Für den lokalen Semantic-Search-Workflow in diesem Tutorial liefert Oracle Database jedoch die benötigten Speicher- und Suchfunktionen.
Kernfunktionen von Oracle AI Vector Search
In der Demo verwenden wir vier Funktionen von Oracle AI Vector Search: nativen Vektorspeicher, Distanzfunktionen, Vektorindizes und relationale Integration.
Nativer Vektordatentyp
Oracle Database unterstützt native VECTOR-Spalten mit expliziten Dimensionen und Elementformaten. In der Demo nutzen wir VECTOR(3, FLOAT32) für manuelle Vektoren und VECTOR(1536, FLOAT32) für das Standard-Embedding-Modell text-embedding-3-small.
Distanzfunktionen und -operatoren
Die ausführbaren Beispiele nutzen VECTOR_DISTANCE(), weil die Distanzmetrik dadurch im SQL explizit bleibt.
Wir verwenden euklidische Distanz für das manuelle Vektorbeispiel und Kosinus-Distanz für Text-Embeddings.
Oracle Database bietet auch Kurzschreibweisen für Vektordistanz-Operatoren sowie dot-product-bezogenes Distanzverhalten. In diesem Tutorial bleiben wir jedoch bei explizitem VECTOR_DISTANCE().
Unterschiedliche Distanzmetriken beantworten leicht unterschiedliche Fragen zur „Nähe“.
Für ein kompaktes Tutorial ist Kosinus-Distanz ein guter Standard für Text-Embeddings, weil sie sich auf die Richtung konzentriert – das passt oft gut zu semantischer Ähnlichkeit.
Euklidische Distanz lässt sich mit handgeschriebenen Vektoren leichter visualisieren, und Dot-Product-Vergleiche sind in manchen Retrieval-Systemen nützlich, wenn Vektorlängen oder Normalisierung Teil des Modelldesigns sind.
Metrik
Vergleicht
Gut geeignet für
Zu beachten
Kosinus
Vektorrichtung
Text-Embeddings und semantische Ähnlichkeit
Ergebnisse hängen von demselben Embedding-Modell und konsistenter Vorverarbeitung ab
Euklidisch
Luftliniendistanz
Kleine Beispiele, Geometrie-Intuition, einige numerische Feature-Vektoren
Die Größe beeinflusst die Distanz – Skalierung kann wichtig sein
Dot Product
Richtung und Größe zusammen
Workflows mit normalisierten Vektoren oder Inner-Product-Scoring
Score-Richtung und Normalisierungsregeln verstehen, bevor Ergebnisse verglichen werden
Vektorindizes
Exakte Vektorsuche ist für Korrektheit und kleine Datensätze nützlich. Mit wachsendem Datenvolumen unterstützen Vektorindizes Approximative-Nearest-Neighbor-Workloads.
Oracle AI Vector Search bietet In-Memory-Nachbargraph-Indizes (häufig mit HNSW verbunden) und Nachbar-Partitionsindizes (häufig mit IVF-Partitionierung verbunden).
In dieser lokalen Demo verwenden wir ORGANIZATION NEIGHBOR PARTITIONS und validieren den Index mit USER_INDEXES.
Approximative Indizes tauschen ein wenig Vollständigkeit gegen schnellere Abfragezeiten in großem Maßstab.
Die passende Indexfamilie hängt von Workload, Datenmenge, Update-Muster und Recall-Ziel ab.
Dieses Tutorial nutzt einen IVF-ähnlichen Nachbar-Partitionsindex, weil der lokale Aufbau damit einfach bleibt und wir einen konkreten Index-Erstellungsschritt zeigen können, ohne in einen Index-Tuning-Leitfaden abzudriften.
Indexfamilie
Grundidee
Stärken
Trade-offs
Wann einsetzen
IVF / Neighbor Partitions
Vektorraum partitionieren, dann wahrscheinliche Partitionen durchsuchen
Einfaches mentales Modell, praktikabel für viele batch-geladene Datensätze
Recall und Geschwindigkeit hängen von Partitionierung und Sucheinstellungen ab
Wir wollen einen unkomplizierten Approximate-Search-Pfad für wachsende Daten
HNSW / Neighbor Graph
Graph aufbauen, der nahe Vektoren für schnelle Traversierung verknüpft
Gute Recall-/Latenz-Profile für viele Nearest-Neighbor-Workloads
Stärker speicherorientiert; Konfiguration kann wichtiger sein
Wir brauchen niedrige Latenz und können Speicher/Tuning budgetieren
Integration mit relationalen Abfragen
Eine Vektorspalte kann neben gewöhnlichen relationalen Spalten leben. Unsere documents-Tabelle speichert Titel, Inhalt und Embedding zusammen, sodass SQL sowohl den Similarity-Score als auch den Originaltext zurückgeben kann.
Erste Schritte mit Oracle AI Vector Search
Wir nutzen einen lokalen Setup-Pfad: Oracle Database Free 26ai in Docker, den Dienst FREEPDB1 und einen dedizierten vector_demo-Anwendungsnutzer.
Die Vektorsuch-Konzepte sind gut zugänglich, das Setup ist mittelstufig: Wir verwenden Docker, ein Datenbankschema, Python-Pakete, Umgebungsvariablen und einen Embedding-API-Schlüssel.
Voraussetzungen
Wir benötigen:
Docker Desktop oder Docker Engine.
Zugriff auf Oracle Container Registry.
Lokale Ports 1521 und 5500 frei.
Python 3.10 oder neuer.
Grundkenntnisse in Python und SQL.
Grundlegende Docker- und Umgebungsvariablen-Kenntnisse.
Einen OpenAI-API-Schlüssel für die Embedding-Schritte.
Diese Demo benötigt eine Oracle-Database-Version bzw. -Umgebung mit den hier genutzten Vektorfeatures, darunter native VECTOR-Spalten, VECTOR_DISTANCE() und CREATE VECTOR INDEX.
Der lokale Pfad nutzt Oracle Database Free 26ai mit dem unten gezeigten Image-Tag, und der DSN verwendet den Pluggable-Database-Dienst FREEPDB1.
Die manuellen Vektorschritte benötigen keinen OpenAI-API-Schlüssel. Die semantischen Schritte senden Beispiel-Text der Dokumente und der Query an den konfigurierten Embedding-Anbieter, daher verwenden wir nur Beispiel- bzw. nicht sensible Texte.
In diesem Tutorial verwenden wir oracledb, den aktuellen Python-Treiber für Oracle Database. python-oracledb läuft standardmäßig im Thin-Modus. Für diese lokale Demo sind daher keine Oracle-Client-Bibliotheken nötig. Thick-Modus ist in anderen Deployments sinnvoll, aber wir rufen hier oracledb.init_oracle_client() nicht auf.
Oracle Database Free 26ai lokal starten
Lege ein Projektverzeichnis für die Skripte an, die wir bauen.
mkdir oracle-ai-vector-search-python
cd oracle-ai-vector-search-pythonBereitgestellt von
Starte Oracle Database Free 26ai mit dem lokalen Container-Image.
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-amd64Bereitgestellt von
Prüfe die Container-Logs und warte, bis die Datenbank meldet, dass der Start abgeschlossen ist.
FREEPDB1 ist der Pluggable-Database-Dienst für diesen lokalen Oracle-Database-Free-Pfad. Unser Python-DSN lautet localhost:1521/FREEPDB1.
Schema vector_demo in FREEPDB1 anlegen
Verwende SYS nur für den Schema-Setup-Schritt. Das Passwort im sqlplus-Befehl ist der ORACLE_PWD-Wert aus dem Docker-Run-Kommando; das Passwort in CREATE USER ist das Anwendungspasswort, das wir als DB_PASSWORD exportieren.
Führe das Setup im Datenbank-Container aus.
# Lege den Anwendungsnutzer an und gewähre die für die Demo nötigen Rechte.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
SQLBereitgestellt von
Das ist eine lokale Development-Abkürzung für den Demo-Container. CREATE SEQUENCE wird benötigt, da die Tabellen Identitätsspalten verwenden.
Für die Produktion würden wir die Rechte mit einem Datenbankadministrator prüfen und nach dem Least-Privilege-Prinzip genau auf den Anwendungskontext zuschneiden.
Speichere Datenbankzugang und Embedding-Einstellungen in Umgebungsvariablen statt sie in Python-Dateien zu hardcoden.
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"Bereitgestellt von
OPENAI_API_KEY ist nur für die Embedding- und Semantic-Search-Schritte erforderlich. EMBEDDING_DIM muss der Dimensionalität des gewählten Embedding-Modells entsprechen.
Oracle AI Vector Search Demo-Projekt
Wir bauen die Demo in acht Checkpoints. Jedes Skript bringt ein Konzept mit und erzeugt Ausgaben, die wir vor dem Weitergehen prüfen können.
Der reiner-Datenbank-Teil ist nach Schritt 1–3 abgeschlossen. Dann haben wir die Verbindung zu Oracle Database getestet, manuelle Vektoren gespeichert, sie nach Distanz abgefragt und die semantische Tabelle erstellt. Der OpenAI-API-Schlüssel wird ab Schritt 4 benötigt.
Schritt 1: Verbindung zur lokalen Datenbank
Zuerst prüfen wir, ob Python sich als vector_demo-Anwendungsnutzer mit Oracle Database verbinden kann. Dieses Skript liest DB_USER, DB_PASSWORD und DB_DSN aus der Umgebung und gibt Modus des Treibers und Datenbankversion aus.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Die Ausgabe sollte bestätigen, dass die Verbindung funktioniert und der Treiber im Thin-Modus läuft.
Connected to Oracle Database.
Driver mode: thin
Database version: 23.26.1.0.0Bereitgestellt von
Wir wissen nun, dass lokale Datenbank, Service-Name, Zugangsdaten und Python-Treiber funktionieren, bevor wir Vektortabellen anlegen.
Schritt 2: Intuition mit manuellen Vektoren aufbauen
Bevor wir Embedding-Modelle einführen, speichern wir drei kleine Vektoren, über die wir gut nachdenken können. Der Aufruf array.array("f", values) erzeugt ein 32-Bit-Gleitkomma-Array, das python-oracledb in eine VECTOR(..., FLOAT32)-Spalte binden kann.
Abbildung 2. Manuelle Vektoren und euklidische Distanz.
Im manuellen Beispiel nutzen wir euklidische Distanz. Der Apfel-Vektor hat eine Distanz von 0,0000, weil er dem Query-Vektor entspricht. Der Bananen-Vektor liegt auf Platz zwei, weil sqrt((1,0 - 0,9)^2 + (0,0 - 0,1)^2 + (0,0 - 0,0)^2) = 0,1414.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Der identische Vektor steht zuerst mit Distanz 0,0000, der nahe Bananen-Vektor folgt.
Created manual_vectors.
Inserted 3 manual vectors.
Nearest manual vectors:
1. apple distance=0.0000
2. banana distance=0.1414Bereitgestellt von
Das ist die Kernidee hinter Vektorsuche: Zeilen werden nach mathematischer Nähe zum Query-Vektor sortiert. Embedding-Modelle erzeugen größere Vektoren, aber das Datenbankverhalten bleibt gleich.
Schritt 3: Die semantische Dokumenttabelle erstellen
Jetzt, da Vektoren funktionieren, legen wir eine anwendungsnahe Tabelle an. Wichtig ist, dass die Dimension der Vektorspalte der Ausgabelänge des Embedding-Modells entspricht.
Die Dimension ist Teil des Tabellenvertrags. Wenn ein Embedding-Modell 1.536 Zahlen zurückgibt, muss die Spalte als VECTOR(1536, FLOAT32) deklariert sein.
Wechseln wir später zu einem Modell mit anderer Ausgabelänge, müssen wir die Vektorspalte neu anlegen oder migrieren, damit Inserts und Abfragen weiter kompatible Vektoren verwenden.
Da DDL die Vektordimension nicht als reguläres Bind-Variable unterstützt, wandelt das Skript EMBEDDING_DIM vor der Verwendung in CREATE TABLE in eine ganze Zahl um.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Die Ausgabe sollte das konfigurierte Embedding-Modell und die Vektordimension anzeigen.
Embedding model: text-embedding-3-small
Embedding dimension: 1536
Recreated documents table.Bereitgestellt von
Damit ist der reine Datenbankteil abgeschlossen. Oracle Database kann Vektoren lokal speichern und vergleichen; als Nächstes ersetzen wir handgeschriebene Vektoren durch aus Text generierte Embeddings.
Schritt 4: Embedding-Modell-Dimension prüfen
Bevor wir Embeddings einfügen, fragen wir das Embedding-Modell nach genau einem Vektor und prüfen dessen Länge. So verhindern wir den häufigsten Fehler bei Vektortabellen: einen Vektor mit falscher Länge in Bezug auf die Dimension der VECTOR-Spalte einzufügen.
Ein Embedding-Modell ist mehr als ein Text-zu-Zahl-Konverter; es definiert den Bedeutungsraum der Anwendung. Alle Dokument- und Query-Embeddings in dieser Demo müssen vom selben Modell stammen.
Ein einziges Modell stellt sicher, dass eine kleine Distanz ähnliche Bedeutung widerspiegelt – nicht zwei zufällige Vektoren mit ähnlicher Form. Das Modell legt auch die Vektorlänge fest. Deshalb prüfen wir die Dimension, bevor wir Daten laden.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Für das Standardmodell und die Dimension sollte die Ausgabe so aussehen.
Embedding model: text-embedding-3-small
Returned embedding length: 1536
Configured EMBEDDING_DIM: 1536
Dimension check passed.Bereitgestellt von
Wenn wir später ein anderes Embedding-Modell wählen, sollten wir EMBEDDING_MODEL anpassen, EMBEDDING_DIM auf die zurückgegebene Vektorlänge setzen und die Tabelle documents neu erstellen.
Schritt 5: Dokument-Embeddings erzeugen und einfügen
Jetzt erzeugen wir Embeddings für einen kleinen, in sich geschlossenen Datensatz und fügen sie in Oracle Database ein.
Jedes Embedding wird vor dem Binden zu array.array("f", embedding) konvertiert, damit es zur FLOAT32-Vektorspalte passt.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Die Zeilenanzahl sollte den sieben Inline-documents entsprechen.
Embedding model: text-embedding-3-small
Generated embeddings for 7 documents.
Inserted 7 documents.
documents row count: 7Bereitgestellt von
Jetzt liegen Text und Embeddings gemeinsam in Oracle Database. Die themenfremden documents zu Gitarre und Suppe sind enthalten, damit die Suchergebnisse klare nahe und ferne Treffer zeigen.
Schritt 6: Eine semantische Suchabfrage ausführen
Als Nächstes betten wir eine natürlichsprachliche Query ein und vergleichen sie mit gespeicherten Dokument-Embeddings. Dieses Skript verwendet Kosinus-Distanz, die für Text-Embeddings gängig ist, weil sie sich auf die Richtung statt auf die Rohgröße konzentriert.
Für semantische Suche läuft die Query durch dasselbe Embedding-Modell wie die documents. Wir bitten SQL nicht, den englischen Satz direkt zu verstehen.
Wir bitten das Embedding-Modell, den Satz in einen Vektor zu verwandeln – und Oracle Database, gespeicherte Vektoren nach ihrer Distanz zu diesem Query-Vektor zu sortieren.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Exakte Platzierungen und Distanzen können je nach Embedding-Modell variieren. Dennoch sollten documents zu Oracle AI Vector Search, semantischer Suche, Python-Datenbankcode und Vektorindizierung weit oben rangieren.
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...Bereitgestellt von
Für die euklidischen und Kosinus-Distanzen in diesem Tutorial gilt: Kleinere Werte bedeuten nähere Treffer.
Dot Product ist ein weiterer hilfreicher Vektorvergleich in vielen Workflows, besonders wenn Größe oder Normalisierung wichtig sind – Score-Richtung und Normalisierung erfordern dabei sorgfältige Behandlung.
Wir bleiben bei ausführbarem Code mit euklidischer Distanz und Kosinus-Distanz, damit die Ergebnisinterpretation einfach bleibt.
Wenn wir Embeddings künftig selbst normalisieren, müssen sowohl gespeicherte Dokument-Embeddings als auch Query-Embeddings konsistent normalisiert werden – sonst verändern sich Distanzen und Rankings.
Schritt 7: Semantische Suche mit Phrasenmatch vergleichen
Semantische Suche ist hilfreich, weil sie keine exakte Phrase im Dokument erfordert.
Vergleichen wir die semantische Query mit einem einfachen exakten Phrasenprädikat.
Das ist keine Volltextsuche-Demo, sondern ein kleiner SQL-Vergleich, der den Unterschied zwischen wörtlichem Matching und bedeutungsbasierter Sortierung sichtbar macht.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Die semantische Suche sollte relevante documents liefern, obwohl die exakte Keyword-Phrase nicht vorkommt.
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 matchesBereitgestellt von
Traditionelle SQL-Prädikate bleiben wichtig für Filter, Joins, Berechtigungen und exakte Treffer. Vektorsuche ergänzt das um ein bedeutungsbasiertes Rankingsignal, das wir bei Bedarf mit relationalen Daten kombinieren können.
Schritt 8: Einen Vektorindex hinzufügen und validieren
Zum Schluss erstellen wir einen Vektorindex und prüfen, dass Oracle Database ihn als gültigen Index im Demoschema ausweist.
Dieser Schritt demonstriert die Index-Erstellung; unser Mini-Datensatz ist zu klein für belastbare Performance-Schlüsse.
Ohne Index kann Oracle Database den Query-Vektor exakt mit jedem gespeicherten Vektor vergleichen. Das eignet sich für winzige Datensätze und zum Lernen.
Bei größeren Datensätzen reduzieren approximative Vektorindizes den Suchraum, damit Abfragen schnell bleiben und dennoch nahe Nachbarn finden.
Wähle die Indexfamilie anhand von Datengröße, Latenzzielen, Recall-Anforderungen, Speicherbudget und Änderungsfrequenz der Vektoren.
Die Query am Ende bestätigt, dass die semantische Suche auch nach der Indexerstellung Ergebnisse liefert.
Wir verwenden hier kein EXPLAIN PLAN oder DBMS_XPLAN, da dieses Tutorial die Indexerstellung über Schemametadaten validiert, nicht über Ausführungspläne.
Skript erstellen
Speichere den folgenden Code als 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()Bereitgestellt von
Die Ausgabe sollte einen Eintrag für DOCUMENT_EMBEDDING_IDX enthalten – mit INDEX_TYPE = VECTOR und 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.Bereitgestellt von
USER_INDEXES bestätigt, dass der Index existiert und gültig ist. Das beweist nicht, dass eine bestimmte Abfrage den Index verwendet hat; dieses Tutorial nutzt keine Ausführungsplan-Ausgabe als Validierung.
Für Produktions-Workloads testen wir mit realistischen Datenvolumina, Abfragemustern und Performancezielen.
Oracle AI Vector Search: Tipps und Troubleshooting
Der Datenbankcontainer startet noch
Warte, bis der Start abgeschlossen ist, und führe dann docker logs oracle-free-26ai-vector erneut aus. Die Datenbank muss bereit sein, bevor Python sich mit localhost:1521/FREEPDB1 verbinden kann.
Port 1521 ist bereits belegt
Stoppe den kollidierenden lokalen Dienst oder ändere das Docker-Port-Mapping. Aktualisiere DB_DSN, falls sich der Host-Port ändert.
Die Datenbankverbindung schlägt fehl
Prüfe DB_USER, DB_PASSWORD und DB_DSN. Verwende im DSN FREEPDB1 und verbinde Anwendungsskripte als vector_demo, nicht als SYS, SYSTEM oder PDBADMIN.
Der Embedding-API-Schlüssel fehlt
Schritte 1–3 sind nur Datenbank. Schritte 4–8 benötigen OPENAI_API_KEY und können API-Kosten verursachen.
Eine Vektordimension passt nicht
Führe 04_check_embedding_dimension.py aus, aktualisiere EMBEDDING_DIM, führe 03_create_documents_table.py erneut aus und lade die Embeddings mit 05_insert_embeddings.py neu.
Ein Vektor-Bind schlägt fehl
Stelle sicher, dass jeder FLOAT32-Vektorbind array.array("f", values) verwendet. Das Tutorial nutzt dieses Format für manuelle Vektoren, gespeicherte Dokument-Embeddings und Query-Embeddings.
Semantische Rankings weichen vom Beispiel ab
Das ist zu erwarten. Embedding-Anbieter können Modelle aktualisieren, und Fließkomma-Distanzen können zwischen Läufen variieren.
Vektorindex-Erstellung schlägt fehl
Stelle sicher, dass die Tabelle documents existiert, das Schema vector_demo ihr Eigentümer ist und DOCUMENT_EMBEDDING_IDX nicht von einem abgebrochenen Lauf übrig geblieben ist.
Vorbereitung auf Produktion
Verwende oracledb.create_pool() für Connection-Pooling, benchmarke mit realistischen Datenmengen, prüfe Sicherheit und Secret-Management und tune Indizes anhand echter Abfragemuster.
Container stoppen und entfernen
Wenn das Tutorial abgeschlossen ist, stoppe und entferne den lokalen Container.
docker stop oracle-free-26ai-vector
dockerrm oracle-free-26ai-vectorBereitgestellt von
Fazit
Wir haben einen lokalen Semantic-Search-Workflow mit Oracle AI Vector Search, Oracle Database Free 26ai und Python aufgebaut.
Wir starteten mit handgeschriebenen VECTOR(3, FLOAT32)-Werten, fügten modellgenerierte Embeddings mit array.array("f", values) ein, fragten ähnliche documents mit VECTOR_DISTANCE() ab, verglichen semantische Ergebnisse mit einem simplen Phrasenprädikat und validierten einen Vektorindex über USER_INDEXES.
Dieser Ansatz passt gut, wenn Embeddings neben relationalen Daten liegen sollen und wir für den lokalen Workflow Speicher und Suche per SQL sichtbar halten möchten – ohne zusätzliche Vektordatenbank.
Die Demo ist bewusst klein: Sie vermittelt die Bausteine, nicht die Produktion im Großmaßstab. Größere Anwendungen sollten mit realistischen Daten benchmarken, Sicherheit und Rechte prüfen, Connection-Pooling nutzen und Indexauswahl unter echten Abfragemustern validieren.
Als Nächstes können wir mit diesen Ressourcen vertiefen:
Oracle AI Vector Search LiveLabs bietet praktische Workshops zu Vektor-Embeddings, exakter und approximativer Suche, Bildsuche und Retrieval-Augmented Generation.
FAQs
Was ist Oracle AI Vector Search?⌄
Oracle AI Vector Search ist ein Funktionspaket in Oracle Database zum Speichern, Indizieren und Abfragen von Vektor-Embeddings neben relationalen Daten.
Brauche ich einen OpenAI-API-Schlüssel, um das Tutorial abzuschließen?⌄
Die Schritte mit manuellen Vektoren und dem Datenbank-Setup brauchen keinen API-Schlüssel. Schritte 4–8 erfordern einen Embedding-Anbieter und den konfigurierten OPENAI_API_KEY.
Warum muss EMBEDDING_DIM zum Embedding-Modell passen?⌄
Die Dimension der VECTOR-Spalte muss der Anzahl der Werte entsprechen, die das Embedding-Modell zurückgibt. Eine Abweichung führt zu Einfügefehlern bei Vektoren.
Welche Distanzmetriken verwendet das Tutorial?⌄
Das Beispiel mit manuellen Vektoren nutzt euklidische Distanz. Die semantischen Beispiele verwenden Kosinus-Distanz.
Beweist ein gültiger Vektorindex, dass eine Abfrage den Index verwendet hat?⌄
Nein. USER_INDEXES bestätigt, dass der Index existiert und gültig ist, aber nicht, dass eine bestimmte Abfrage ihn genutzt hat.
Mark Nelson ist Architekt und Developer Evangelist bei Oracle. Er arbeitet an der Schnittstelle von KI, Microservices und Datenbanktechnologien. Er ist aktiver Blogger, veröffentlichter Autor, technischer Gutachter bei Manning Publications, Section Leader bei Stanford Code in Place und Mentor bei DeepLearning.ai. Er spricht regelmäßig bei Java- und Oracle-User-Groups, KI-Meetups und großen Konferenzen. Seine Leidenschaft gilt dem Lernen und Lehren. Er verfügt über mehr als dreißig Jahre Branchenerfahrung bei IBM und Oracle.
Erforsche Pythons match-case: eine Anleitung zu seiner Syntax, Anwendungen in Data Science und ML sowie eine vergleichende Analyse mit dem traditionellen switch-case.
Mach dich mit Python-Datenstrukturen vertraut: Lerne mehr über Datentypen und primitive sowie nicht-primitive Datenstrukturen wie Strings, Listen, Stapel usw.
In diesem Tutorial bauen wir eine lokale Semantic-Search-Demo mit Oracle AI Vector Search, Python und Oracle Database Free 26ai.
Wir starten mit handgeschriebenen dreidimensionalen Vektoren, damit die Distanzberechnung nachvollziehbar ist, erzeugen dann Text-Embeddings und fragen sie per SQL aus Oracle Database ab.
Dieses Tutorial richtet sich an Python- und SQL-Entwickler, die neu bei Vektorsuche sind und sich mit Docker, Umgebungsvariablen, Python-Paketen und lokaler Datenbankeinrichtung wohlfühlen.
KI-gestützte Anwendungen brauchen Suche, die Bedeutung versteht – nicht nur exakte Wörter. Eine Support-App, ein Doku-Portal oder ein internes Wissenstool sollte „Datenbankspeicher für KI-Suche“ finden, auch wenn im besten Treffer „Vektor-Embeddings in nativen Spalten speichern“ steht.
Vektor-Embeddings machen das möglich, indem sie Text als numerische Vektoren darstellen. Oracle AI Vector Search erlaubt es, diese Vektoren direkt in Oracle Database zu speichern, mit SQL abzufragen und Embeddings neben relationalen Anwendungsdaten zu halten.
Für diesen lokalen Workflow brauchen wir keine separate Vektordatenbank.
Wir starten Oracle Database Free 26ai lokal, verbinden uns aus Python im
oracledbThin-Modus, speichern zuerst manuelle Vektoren, dann OpenAI-Embeddings, führen semantische Suche aus, vergleichen semantische Ergebnisse mit einem einfachen exakten Phrasenprädikat und erstellen einen Vektorindex, den wir überUSER_INDEXESvalidieren.Am Ende haben wir einen funktionierenden, Python-basierten Semantic-Search-Workflow, der Embeddings in Oracle Database speichert und die ähnlichsten
documentslokal abruft.Was ist Oracle AI Vector Search?
Oracle AI Vector Search ist ein Funktionsumfang in Oracle Database zum Speichern, Indizieren und Abfragen von Vektor-Embeddings. Ein Vektor-Embedding ist eine Liste fester Länge mit Zahlen, die die Bedeutung von Text, Bildern oder anderen Daten so repräsentiert, dass eine Datenbank sie mathematisch vergleichen kann.
Ein Embedding-Modell erzeugt die numerischen Vektoren. Es nimmt als Eingabe z. B. einen Satz, Absatz, eine Bildbeschreibung oder einen Code-Snippet und gibt einen Vektor mit fester Dimensionalität zurück.
Ähnliche Eingaben sollten Vektoren nahe beieinander ergeben, während Unzusammenhängendes weiter auseinanderliegt. Deshalb müssen wir dasselbe Embedding-Modell für gespeicherte documents und ankommende Queries verwenden – Distanzen sind nur sinnvoll, wenn die Vektoren dasselbe Koordinatensystem teilen.
In diesem Tutorial sind die manuellen Vektoren bewusst klein, damit wir die Mathematik begutachten können. Die echten Text-Embeddings sind deutlich größer, damit das Modell feinere Beziehungen zwischen Wörtern, Phrasen und Themen abbilden kann.
Die Vektorsuche sortiert Zeilen nach Distanz zwischen Vektoren. Für euklidische und Kosinus-Distanzen bedeuten kleinere Werte engere Übereinstimmungen. In diesem Tutorial beginnen wir mit einer kleinen
VECTOR(3, FLOAT32)-Spalte, um das Distanzverhalten direkt zu sehen, und wechseln dann zuVECTOR(1536, FLOAT32)-Embeddings aus Text.Abbildung 1. Ablauf von Oracle AI Vector Search
Oracle AI Vector Search speichert Embeddings in einer nativen VECTOR-Spalte und sortiert Ergebnisse nach Vektordistanz.
Oracle Database ist hilfreich, wenn Embeddings neben relationalen Anwendungsdaten wie Dokument-IDs, Titeln, Inhalten, Nutzern, Produkten, Tickets oder Metadaten liegen sollen.
Manche Anwendungen nutzen eine separate Vektordatenbank oder Suchengine für spezialisierte Retrieval-Workloads. Für den lokalen Semantic-Search-Workflow in diesem Tutorial liefert Oracle Database jedoch die benötigten Speicher- und Suchfunktionen.
Kernfunktionen von Oracle AI Vector Search
In der Demo verwenden wir vier Funktionen von Oracle AI Vector Search: nativen Vektorspeicher, Distanzfunktionen, Vektorindizes und relationale Integration.
Nativer Vektordatentyp
Oracle Database unterstützt native
VECTOR-Spalten mit expliziten Dimensionen und Elementformaten. In der Demo nutzen wirVECTOR(3, FLOAT32)für manuelle Vektoren undVECTOR(1536, FLOAT32)für das Standard-Embedding-Modelltext-embedding-3-small.Distanzfunktionen und -operatoren
Die ausführbaren Beispiele nutzen
VECTOR_DISTANCE(), weil die Distanzmetrik dadurch im SQL explizit bleibt.Wir verwenden euklidische Distanz für das manuelle Vektorbeispiel und Kosinus-Distanz für Text-Embeddings.
Oracle Database bietet auch Kurzschreibweisen für Vektordistanz-Operatoren sowie dot-product-bezogenes Distanzverhalten. In diesem Tutorial bleiben wir jedoch bei explizitem
VECTOR_DISTANCE().Unterschiedliche Distanzmetriken beantworten leicht unterschiedliche Fragen zur „Nähe“.
Für ein kompaktes Tutorial ist Kosinus-Distanz ein guter Standard für Text-Embeddings, weil sie sich auf die Richtung konzentriert – das passt oft gut zu semantischer Ähnlichkeit.
Euklidische Distanz lässt sich mit handgeschriebenen Vektoren leichter visualisieren, und Dot-Product-Vergleiche sind in manchen Retrieval-Systemen nützlich, wenn Vektorlängen oder Normalisierung Teil des Modelldesigns sind.
Metrik
Vergleicht
Gut geeignet für
Zu beachten
Kosinus
Vektorrichtung
Text-Embeddings und semantische Ähnlichkeit
Ergebnisse hängen von demselben Embedding-Modell und konsistenter Vorverarbeitung ab
Euklidisch
Luftliniendistanz
Kleine Beispiele, Geometrie-Intuition, einige numerische Feature-Vektoren
Die Größe beeinflusst die Distanz – Skalierung kann wichtig sein
Dot Product
Richtung und Größe zusammen
Workflows mit normalisierten Vektoren oder Inner-Product-Scoring
Score-Richtung und Normalisierungsregeln verstehen, bevor Ergebnisse verglichen werden
Vektorindizes
Exakte Vektorsuche ist für Korrektheit und kleine Datensätze nützlich. Mit wachsendem Datenvolumen unterstützen Vektorindizes Approximative-Nearest-Neighbor-Workloads.
Oracle AI Vector Search bietet In-Memory-Nachbargraph-Indizes (häufig mit HNSW verbunden) und Nachbar-Partitionsindizes (häufig mit IVF-Partitionierung verbunden).
In dieser lokalen Demo verwenden wir
ORGANIZATION NEIGHBOR PARTITIONSund validieren den Index mitUSER_INDEXES.Approximative Indizes tauschen ein wenig Vollständigkeit gegen schnellere Abfragezeiten in großem Maßstab.
Die passende Indexfamilie hängt von Workload, Datenmenge, Update-Muster und Recall-Ziel ab.
Dieses Tutorial nutzt einen IVF-ähnlichen Nachbar-Partitionsindex, weil der lokale Aufbau damit einfach bleibt und wir einen konkreten Index-Erstellungsschritt zeigen können, ohne in einen Index-Tuning-Leitfaden abzudriften.
Indexfamilie
Grundidee
Stärken
Trade-offs
Wann einsetzen
IVF / Neighbor Partitions
Vektorraum partitionieren, dann wahrscheinliche Partitionen durchsuchen
Einfaches mentales Modell, praktikabel für viele batch-geladene Datensätze
Recall und Geschwindigkeit hängen von Partitionierung und Sucheinstellungen ab
Wir wollen einen unkomplizierten Approximate-Search-Pfad für wachsende Daten
HNSW / Neighbor Graph
Graph aufbauen, der nahe Vektoren für schnelle Traversierung verknüpft
Gute Recall-/Latenz-Profile für viele Nearest-Neighbor-Workloads
Stärker speicherorientiert; Konfiguration kann wichtiger sein
Wir brauchen niedrige Latenz und können Speicher/Tuning budgetieren
Integration mit relationalen Abfragen
Eine Vektorspalte kann neben gewöhnlichen relationalen Spalten leben. Unsere documents-Tabelle speichert Titel, Inhalt und Embedding zusammen, sodass SQL sowohl den Similarity-Score als auch den Originaltext zurückgeben kann.
Erste Schritte mit Oracle AI Vector Search
Wir nutzen einen lokalen Setup-Pfad: Oracle Database Free 26ai in Docker, den Dienst
FREEPDB1und einen dediziertenvector_demo-Anwendungsnutzer.Die Vektorsuch-Konzepte sind gut zugänglich, das Setup ist mittelstufig: Wir verwenden Docker, ein Datenbankschema, Python-Pakete, Umgebungsvariablen und einen Embedding-API-Schlüssel.
Voraussetzungen
Wir benötigen:
Diese Demo benötigt eine Oracle-Database-Version bzw. -Umgebung mit den hier genutzten Vektorfeatures, darunter native
VECTOR-Spalten,VECTOR_DISTANCE()undCREATE VECTOR INDEX.Der lokale Pfad nutzt Oracle Database Free 26ai mit dem unten gezeigten Image-Tag, und der DSN verwendet den Pluggable-Database-Dienst
FREEPDB1.Die manuellen Vektorschritte benötigen keinen
OpenAI-API-Schlüssel. Die semantischen Schritte senden Beispiel-Text der Dokumente und der Query an den konfigurierten Embedding-Anbieter, daher verwenden wir nur Beispiel- bzw. nicht sensible Texte.In diesem Tutorial verwenden wir
oracledb, den aktuellen Python-Treiber für Oracle Database.python-oracledbläuft standardmäßig im Thin-Modus. Für diese lokale Demo sind daher keine Oracle-Client-Bibliotheken nötig. Thick-Modus ist in anderen Deployments sinnvoll, aber wir rufen hieroracledb.init_oracle_client()nicht auf.Oracle Database Free 26ai lokal starten
Lege ein Projektverzeichnis für die Skripte an, die wir bauen.
Starte Oracle Database Free 26ai mit dem lokalen Container-Image.
Prüfe die Container-Logs und warte, bis die Datenbank meldet, dass der Start abgeschlossen ist.
FREEPDB1ist der Pluggable-Database-Dienst für diesen lokalen Oracle-Database-Free-Pfad. Unser Python-DSN lautetlocalhost:1521/FREEPDB1.Schema vector_demo in FREEPDB1 anlegen
Verwende
SYSnur für den Schema-Setup-Schritt. Das Passwort im sqlplus-Befehl ist der ORACLE_PWD-Wert aus dem Docker-Run-Kommando; das Passwort in CREATE USER ist das Anwendungspasswort, das wir alsDB_PASSWORDexportieren.Führe das Setup im Datenbank-Container aus.
Das ist eine lokale Development-Abkürzung für den Demo-Container. CREATE SEQUENCE wird benötigt, da die Tabellen Identitätsspalten verwenden.
Für die Produktion würden wir die Rechte mit einem Datenbankadministrator prüfen und nach dem Least-Privilege-Prinzip genau auf den Anwendungskontext zuschneiden.
Python-Abhängigkeiten installieren
Erstelle und aktiviere eine virtuelle Umgebung.
Installiere die in der Demo verwendeten Python-Pakete.
Umgebungsvariablen setzen
Speichere Datenbankzugang und Embedding-Einstellungen in Umgebungsvariablen statt sie in Python-Dateien zu hardcoden.
OPENAI_API_KEYist nur für die Embedding- und Semantic-Search-Schritte erforderlich.EMBEDDING_DIMmuss der Dimensionalität des gewählten Embedding-Modells entsprechen.Oracle AI Vector Search Demo-Projekt
Wir bauen die Demo in acht Checkpoints. Jedes Skript bringt ein Konzept mit und erzeugt Ausgaben, die wir vor dem Weitergehen prüfen können.
Der reiner-Datenbank-Teil ist nach Schritt 1–3 abgeschlossen. Dann haben wir die Verbindung zu Oracle Database getestet, manuelle Vektoren gespeichert, sie nach Distanz abgefragt und die semantische Tabelle erstellt. Der
OpenAI-API-Schlüssel wird ab Schritt 4 benötigt.Schritt 1: Verbindung zur lokalen Datenbank
Zuerst prüfen wir, ob Python sich als
vector_demo-Anwendungsnutzer mit Oracle Database verbinden kann. Dieses Skript liestDB_USER, DB_PASSWORDundDB_DSNaus der Umgebung und gibt Modus des Treibers und Datenbankversion aus.Skript erstellen
Speichere den folgenden Code als
01_check_connection.py.Skript ausführen
Führe den Verbindungstest aus.
Erwartete Ausgabe
Die Ausgabe sollte bestätigen, dass die Verbindung funktioniert und der Treiber im Thin-Modus läuft.
Wir wissen nun, dass lokale Datenbank, Service-Name, Zugangsdaten und Python-Treiber funktionieren, bevor wir Vektortabellen anlegen.
Schritt 2: Intuition mit manuellen Vektoren aufbauen
Bevor wir Embedding-Modelle einführen, speichern wir drei kleine Vektoren, über die wir gut nachdenken können. Der Aufruf
array.array("f", values)erzeugt ein 32-Bit-Gleitkomma-Array, daspython-oracledbin eineVECTOR(..., FLOAT32)-Spalte binden kann.Abbildung 2. Manuelle Vektoren und euklidische Distanz.
Im manuellen Beispiel nutzen wir euklidische Distanz. Der Apfel-Vektor hat eine Distanz von 0,0000, weil er dem Query-Vektor entspricht. Der Bananen-Vektor liegt auf Platz zwei, weil sqrt((1,0 - 0,9)^2 + (0,0 - 0,1)^2 + (0,0 - 0,0)^2) = 0,1414.
Skript erstellen
Speichere den folgenden Code als
02_manual_vectors.py.Skript ausführen
Führe das Skript für manuelle Vektoren aus.
Erwartete Ausgabe
Der identische Vektor steht zuerst mit Distanz 0,0000, der nahe Bananen-Vektor folgt.
Das ist die Kernidee hinter Vektorsuche: Zeilen werden nach mathematischer Nähe zum Query-Vektor sortiert. Embedding-Modelle erzeugen größere Vektoren, aber das Datenbankverhalten bleibt gleich.
Schritt 3: Die semantische Dokumenttabelle erstellen
Jetzt, da Vektoren funktionieren, legen wir eine anwendungsnahe Tabelle an. Wichtig ist, dass die Dimension der Vektorspalte der Ausgabelänge des Embedding-Modells entspricht.
Die Dimension ist Teil des Tabellenvertrags. Wenn ein Embedding-Modell 1.536 Zahlen zurückgibt, muss die Spalte als
VECTOR(1536, FLOAT32)deklariert sein.Wechseln wir später zu einem Modell mit anderer Ausgabelänge, müssen wir die Vektorspalte neu anlegen oder migrieren, damit Inserts und Abfragen weiter kompatible Vektoren verwenden.
Da DDL die Vektordimension nicht als reguläres Bind-Variable unterstützt, wandelt das Skript
EMBEDDING_DIMvor der Verwendung in CREATE TABLE in eine ganze Zahl um.Skript erstellen
Speichere den folgenden Code als
03_create_documents_table.py.Skript ausführen
Führe das Tabellenerstellungsskript aus.
Erwartete Ausgabe
Die Ausgabe sollte das konfigurierte Embedding-Modell und die Vektordimension anzeigen.
Damit ist der reine Datenbankteil abgeschlossen. Oracle Database kann Vektoren lokal speichern und vergleichen; als Nächstes ersetzen wir handgeschriebene Vektoren durch aus Text generierte Embeddings.
Schritt 4: Embedding-Modell-Dimension prüfen
Bevor wir Embeddings einfügen, fragen wir das Embedding-Modell nach genau einem Vektor und prüfen dessen Länge. So verhindern wir den häufigsten Fehler bei Vektortabellen: einen Vektor mit falscher Länge in Bezug auf die Dimension der
VECTOR-Spalte einzufügen.Ein Embedding-Modell ist mehr als ein Text-zu-Zahl-Konverter; es definiert den Bedeutungsraum der Anwendung. Alle Dokument- und Query-Embeddings in dieser Demo müssen vom selben Modell stammen.
Ein einziges Modell stellt sicher, dass eine kleine Distanz ähnliche Bedeutung widerspiegelt – nicht zwei zufällige Vektoren mit ähnlicher Form. Das Modell legt auch die Vektorlänge fest. Deshalb prüfen wir die Dimension, bevor wir Daten laden.
Skript erstellen
Speichere den folgenden Code als
04_check_embedding_dimension.py.Skript ausführen
Führe den Dimensionscheck aus.
Erwartete Ausgabe
Für das Standardmodell und die Dimension sollte die Ausgabe so aussehen.
Wenn wir später ein anderes Embedding-Modell wählen, sollten wir
EMBEDDING_MODELanpassen,EMBEDDING_DIMauf die zurückgegebene Vektorlänge setzen und die Tabelledocumentsneu erstellen.Schritt 5: Dokument-Embeddings erzeugen und einfügen
Jetzt erzeugen wir Embeddings für einen kleinen, in sich geschlossenen Datensatz und fügen sie in Oracle Database ein.
Jedes Embedding wird vor dem Binden zu
array.array("f", embedding)konvertiert, damit es zurFLOAT32-Vektorspalte passt.Skript erstellen
Speichere den folgenden Code als
05_insert_embeddings.py.Skript ausführen
Führe das Insert-Skript aus.
Erwartete Ausgabe
Die Zeilenanzahl sollte den sieben Inline-
documentsentsprechen.Jetzt liegen Text und Embeddings gemeinsam in Oracle Database. Die themenfremden
documentszu Gitarre und Suppe sind enthalten, damit die Suchergebnisse klare nahe und ferne Treffer zeigen.Schritt 6: Eine semantische Suchabfrage ausführen
Als Nächstes betten wir eine natürlichsprachliche Query ein und vergleichen sie mit gespeicherten Dokument-Embeddings. Dieses Skript verwendet Kosinus-Distanz, die für Text-Embeddings gängig ist, weil sie sich auf die Richtung statt auf die Rohgröße konzentriert.
Für semantische Suche läuft die Query durch dasselbe Embedding-Modell wie die
documents. Wir bitten SQL nicht, den englischen Satz direkt zu verstehen.Wir bitten das Embedding-Modell, den Satz in einen Vektor zu verwandeln – und Oracle Database, gespeicherte Vektoren nach ihrer Distanz zu diesem Query-Vektor zu sortieren.
Skript erstellen
Speichere den folgenden Code als
06_semantic_search.py.Skript ausführen
Führe das Semantic-Search-Skript aus.
Erwartete Ausgabe
Exakte Platzierungen und Distanzen können je nach Embedding-Modell variieren. Dennoch sollten
documentszu Oracle AI Vector Search, semantischer Suche, Python-Datenbankcode und Vektorindizierung weit oben rangieren.Für die euklidischen und Kosinus-Distanzen in diesem Tutorial gilt: Kleinere Werte bedeuten nähere Treffer.
Dot Product ist ein weiterer hilfreicher Vektorvergleich in vielen Workflows, besonders wenn Größe oder Normalisierung wichtig sind – Score-Richtung und Normalisierung erfordern dabei sorgfältige Behandlung.
Wir bleiben bei ausführbarem Code mit euklidischer Distanz und Kosinus-Distanz, damit die Ergebnisinterpretation einfach bleibt.
Wenn wir Embeddings künftig selbst normalisieren, müssen sowohl gespeicherte Dokument-Embeddings als auch Query-Embeddings konsistent normalisiert werden – sonst verändern sich Distanzen und Rankings.
Schritt 7: Semantische Suche mit Phrasenmatch vergleichen
Semantische Suche ist hilfreich, weil sie keine exakte Phrase im Dokument erfordert.
Vergleichen wir die semantische Query mit einem einfachen exakten Phrasenprädikat.
Das ist keine Volltextsuche-Demo, sondern ein kleiner SQL-Vergleich, der den Unterschied zwischen wörtlichem Matching und bedeutungsbasierter Sortierung sichtbar macht.
Skript erstellen
Speichere den folgenden Code als
07_semantic_vs_keyword.py.Skript ausführen
Führe das Vergleichsskript aus.
Erwartete Ausgabe
Die semantische Suche sollte relevante
documentsliefern, obwohl die exakte Keyword-Phrase nicht vorkommt.Traditionelle SQL-Prädikate bleiben wichtig für Filter, Joins, Berechtigungen und exakte Treffer. Vektorsuche ergänzt das um ein bedeutungsbasiertes Rankingsignal, das wir bei Bedarf mit relationalen Daten kombinieren können.
Schritt 8: Einen Vektorindex hinzufügen und validieren
Zum Schluss erstellen wir einen Vektorindex und prüfen, dass Oracle Database ihn als gültigen Index im Demoschema ausweist.
Dieser Schritt demonstriert die Index-Erstellung; unser Mini-Datensatz ist zu klein für belastbare Performance-Schlüsse.
Ohne Index kann Oracle Database den Query-Vektor exakt mit jedem gespeicherten Vektor vergleichen. Das eignet sich für winzige Datensätze und zum Lernen.
Bei größeren Datensätzen reduzieren approximative Vektorindizes den Suchraum, damit Abfragen schnell bleiben und dennoch nahe Nachbarn finden.
Wähle die Indexfamilie anhand von Datengröße, Latenzzielen, Recall-Anforderungen, Speicherbudget und Änderungsfrequenz der Vektoren.
Die Query am Ende bestätigt, dass die semantische Suche auch nach der Indexerstellung Ergebnisse liefert.
Wir verwenden hier kein EXPLAIN PLAN oder DBMS_XPLAN, da dieses Tutorial die Indexerstellung über Schemametadaten validiert, nicht über Ausführungspläne.
Skript erstellen
Speichere den folgenden Code als
08_create_vector_index.py.Skript ausführen
Führe das Indexskript aus.
Erwartete Ausgabe
Die Ausgabe sollte einen Eintrag für
DOCUMENT_EMBEDDING_IDXenthalten – mitINDEX_TYPE=VECTORundSTATUS=VALID.USER_INDEXESbestätigt, dass der Index existiert und gültig ist. Das beweist nicht, dass eine bestimmte Abfrage den Index verwendet hat; dieses Tutorial nutzt keine Ausführungsplan-Ausgabe als Validierung.Für Produktions-Workloads testen wir mit realistischen Datenvolumina, Abfragemustern und Performancezielen.
Oracle AI Vector Search: Tipps und Troubleshooting
Der Datenbankcontainer startet noch
Warte, bis der Start abgeschlossen ist, und führe dann
docker logs oracle-free-26ai-vectorerneut aus. Die Datenbank muss bereit sein, bevor Python sich mitlocalhost:1521/FREEPDB1verbinden kann.Port 1521 ist bereits belegt
Stoppe den kollidierenden lokalen Dienst oder ändere das Docker-Port-Mapping. Aktualisiere
DB_DSN, falls sich der Host-Port ändert.Die Datenbankverbindung schlägt fehl
Prüfe
DB_USER, DB_PASSWORDundDB_DSN. Verwende im DSNFREEPDB1und verbinde Anwendungsskripte alsvector_demo, nicht alsSYS, SYSTEModerPDBADMIN.Der Embedding-API-Schlüssel fehlt
Schritte 1–3 sind nur Datenbank. Schritte 4–8 benötigen
OPENAI_API_KEYund können API-Kosten verursachen.Eine Vektordimension passt nicht
Führe
04_check_embedding_dimension.pyaus, aktualisiereEMBEDDING_DIM, führe03_create_documents_table.pyerneut aus und lade die Embeddings mit05_insert_embeddings.pyneu.Ein Vektor-Bind schlägt fehl
Stelle sicher, dass jeder
FLOAT32-Vektorbindarray.array("f", values)verwendet. Das Tutorial nutzt dieses Format für manuelle Vektoren, gespeicherte Dokument-Embeddings und Query-Embeddings.Semantische Rankings weichen vom Beispiel ab
Das ist zu erwarten. Embedding-Anbieter können Modelle aktualisieren, und Fließkomma-Distanzen können zwischen Läufen variieren.
Vektorindex-Erstellung schlägt fehl
Stelle sicher, dass die Tabelle
documentsexistiert, das Schemavector_demoihr Eigentümer ist undDOCUMENT_EMBEDDING_IDXnicht von einem abgebrochenen Lauf übrig geblieben ist.Vorbereitung auf Produktion
Verwende
oracledb.create_pool()für Connection-Pooling, benchmarke mit realistischen Datenmengen, prüfe Sicherheit und Secret-Management und tune Indizes anhand echter Abfragemuster.Container stoppen und entfernen
Wenn das Tutorial abgeschlossen ist, stoppe und entferne den lokalen Container.
Fazit
Wir haben einen lokalen Semantic-Search-Workflow mit Oracle AI Vector Search, Oracle Database Free 26ai und Python aufgebaut.
Wir starteten mit handgeschriebenen
VECTOR(3, FLOAT32)-Werten, fügten modellgenerierte Embeddings mitarray.array("f", values)ein, fragten ähnlichedocumentsmitVECTOR_DISTANCE()ab, verglichen semantische Ergebnisse mit einem simplen Phrasenprädikat und validierten einen Vektorindex überUSER_INDEXES.Dieser Ansatz passt gut, wenn Embeddings neben relationalen Daten liegen sollen und wir für den lokalen Workflow Speicher und Suche per SQL sichtbar halten möchten – ohne zusätzliche Vektordatenbank.
Die Demo ist bewusst klein: Sie vermittelt die Bausteine, nicht die Produktion im Großmaßstab. Größere Anwendungen sollten mit realistischen Daten benchmarken, Sicherheit und Rechte prüfen, Connection-Pooling nutzen und Indexauswahl unter echten Abfragemustern validieren.
Als Nächstes können wir mit diesen Ressourcen vertiefen: