Tutorial Oracle AI Vector Search: armazene e consulte embeddings com Python
Este tutorial apresenta o Oracle AI Vector Search, explica seus recursos centrais e conduz um projeto prático local. Cobre requisitos de setup, busca semântica, indexação vetorial e passos comuns de troubleshooting.
Neste tutorial, vamos criar um demo local de busca semântica com Oracle AI Vector Search, Python e Oracle Database Free 26ai.
Começaremos com vetores tridimensionais escritos à mão para que o cálculo de distância fique visível; depois, vamos gerar embeddings de texto e consultá-los no Oracle Database com SQL.
Este tutorial é para desenvolvedores Python e SQL que estão começando com busca vetorial e têm familiaridade com Docker, variáveis de ambiente, pacotes Python e configuração de banco de dados local.
Aplicativos com IA precisam de busca que entenda significado, não só palavras exatas. Um app de suporte, portal de documentação ou ferramenta interna de conhecimento deve conseguir encontrar “armazenamento de banco de dados para busca em IA” mesmo quando o melhor documento diz “armazenar embeddings vetoriais em colunas nativas”.
Vector embeddings tornam isso possível ao representar texto como vetores numéricos. O Oracle AI Vector Search permite armazenar esses vetores diretamente no Oracle Database, consultá-los com SQL e manter embeddings ao lado dos dados relacionais do aplicativo.
Para este fluxo local, não precisamos de um banco vetorial separado.
Vamos executar o Oracle Database Free 26ai localmente, conectar a partir do Python no modo Thin do oracledb, armazenar primeiro vetores manuais, depois armazenar embeddings da OpenAI, rodar busca semântica, comparar a recuperação semântica com um predicado simples de frase exata e criar um índice vetorial validado por meio de USER_INDEXES.
Ao final, teremos um fluxo de busca semântica em Python que armazena embeddings no Oracle Database e recupera localmente os documents mais similares.
O que é o Oracle AI Vector Search?
Oracle AI Vector Search é um conjunto de recursos do Oracle Database para armazenar, indexar e consultar embeddings vetoriais. Um embedding vetorial é uma lista de números de tamanho fixo que representa o significado de textos, imagens ou outros dados em uma forma que o banco consegue comparar matematicamente.
Um modelo de embedding cria os vetores numéricos. Ele recebe como entrada uma sentença, parágrafo, descrição de imagem ou trecho de código e retorna um vetor com um número fixo de dimensões.
Entradas similares devem produzir vetores próximos entre si, enquanto entradas não relacionadas devem ficar mais distantes. Por isso, precisamos usar o mesmo modelo de embedding para os documents armazenados e para as consultas, pois as distâncias só fazem sentido quando os vetores compartilham o mesmo sistema de coordenadas.
Neste tutorial, os vetores manuais são deliberadamente pequenos para inspecionarmos a matemática. Os embeddings reais de texto são bem maiores porque o modelo precisa de dimensões suficientes para codificar relações sutis entre palavras, frases e tópicos.
A busca vetorial ranqueia linhas pela distância entre vetores. Para consultas de distância euclidiana e de cosseno, valores menores significam correspondências mais próximas. Neste tutorial, começaremos com uma coluna VECTOR(3, FLOAT32) pequena para ver o comportamento da distância diretamente e depois passaremos para embeddings VECTOR(1536, FLOAT32) gerados a partir de texto.
Figura 1. Fluxo do Oracle AI Vector Search
Oracle AI Vector Search armazena embeddings em uma coluna nativa VECTOR e ranqueia os resultados pela distância vetorial.
Oracle Database é útil quando embeddings precisam ficar ao lado de dados relacionais do app, como IDs de documentos, títulos, conteúdo, usuários, produtos, tickets ou metadados.
Alguns aplicativos usam um banco vetorial ou mecanismo de busca separado para cargas especializadas de recuperação; mas, para o fluxo local deste tutorial, o Oracle Database oferece os recursos de armazenamento e busca vetorial de que precisamos.
Principais recursos do Oracle AI Vector Search
Usaremos quatro recursos do Oracle AI Vector Search no demo: armazenamento vetorial nativo, funções de distância, índices vetoriais e integração relacional.
Tipo de dado vetorial nativo
Oracle Database suporta colunas nativas VECTOR com dimensões explícitas e formatos de elemento. No demo, usaremos VECTOR(3, FLOAT32) para vetores manuais e VECTOR(1536, FLOAT32) para o modelo de embedding padrão text-embedding-3-small.
Funções e operadores de distância
Os exemplos executáveis usam VECTOR_DISTANCE() porque mantém a métrica de distância explícita no SQL.
Usaremos distância euclidiana para o exemplo manual e distância de cosseno para embeddings de texto.
Oracle Database também inclui operadores abreviados de distância vetorial e comportamento relacionado a produto interno, mas este tutorial mantém o SQL executável no caminho explícito com VECTOR_DISTANCE().
Métricas de distância diferentes respondem a perguntas ligeiramente diferentes sobre “proximidade”.
Para um tutorial curto, distância de cosseno é um bom padrão para embeddings de texto porque foca na direção, o que costuma mapear bem para similaridade semântica.
A distância euclidiana é mais fácil de visualizar com vetores escritos à mão, e comparações no estilo produto interno são úteis em alguns sistemas quando a magnitude do vetor ou a normalização fazem parte do desenho do modelo.
Métrica
O que compara
Bom para
Fique atento a
Cosseno
Direção do vetor
Embeddings de texto e similaridade semântica
Os resultados dependem do mesmo modelo de embedding e de pré-processamento consistente
Euclidiana
Distância em linha reta
Exemplos pequenos, intuição geométrica, alguns vetores de features numéricas
A magnitude afeta a distância; o escalonamento pode importar
Produto interno
Direção e magnitude juntas
Workflows baseados em vetores normalizados ou pontuação por produto interno
É preciso entender direção do score e regras de normalização antes de comparar resultados
Índices vetoriais
A busca vetorial exata é útil para correção e datasets pequenos. À medida que os dados crescem, índices vetoriais dão suporte a buscas aproximadas de vizinhos mais próximos.
Oracle AI Vector Search inclui índices de grafo de vizinhos em memória, frequentemente associados a buscas no estilo HNSW, e índices de partições de vizinhos, associados à partição no estilo IVF.
Neste demo local, usamos ORGANIZATION NEIGHBOR PARTITIONS e validamos o índice com USER_INDEXES.
Índices aproximados trocam um pouco da exatidão da busca exaustiva por mais velocidade em escala.
A família de índice certa depende da carga, volume de dados, padrão de atualização e meta de recall.
Este tutorial usa um índice de partições de vizinhos no estilo IVF porque simplifica o setup local e oferece um passo concreto de criação de índice sem transformar o tutorial em um guia de tuning.
Família de índice
Ideia básica
Pontos fortes
Trade-offs
Quando usar
IVF / partições de vizinhos
Particionar o espaço vetorial e buscar nas partições prováveis
Modelo mental simples, prático para muitos datasets carregados em lote
Recall e velocidade dependem da partição e das configurações de busca
Queremos um caminho direto de busca aproximada para um dataset em crescimento
HNSW / grafo de vizinhos
Construir um grafo que liga vetores próximos para travessia rápida
Ótimo perfil de recall e latência para muitos workloads de vizinhos mais próximos
Mais orientado a memória; a configuração pode importar mais
Precisamos de baixa latência e podemos investir memória e esforço de tuning
Integração com consultas relacionais
Uma coluna vetorial pode viver ao lado de colunas relacionais comuns. Nossa tabela de documents vai armazenar título, conteúdo e embedding juntos, para que o SQL retorne tanto o score de similaridade quanto o texto original.
Como começar com Oracle AI Vector Search
Vamos usar um caminho local: Oracle Database Free 26ai no Docker, o serviço FREEPDB1 e um usuário de aplicação dedicado vector_demo.
Os conceitos de busca vetorial são acessíveis, mas a configuração é intermediária porque usamos Docker, um schema de banco, pacotes Python, variáveis de ambiente e uma chave de API de embedding.
Pré-requisitos
Vamos precisar de:
Docker Desktop ou Docker Engine.
Acesso ao Oracle Container Registry.
Portas locais 1521 e 5500 livres.
Python 3.10 ou superior.
Noções de Python e SQL.
Familiaridade básica com Docker e variáveis de ambiente.
Uma chave de API da OpenAI para as etapas de embedding.
Este demo requer uma versão/ambiente do Oracle Database que inclua os recursos vetoriais usados aqui, incluindo colunas nativas VECTOR, VECTOR_DISTANCE() e CREATE VECTOR INDEX.
O caminho local usa Oracle Database Free 26ai com a tag de imagem mostrada abaixo, e o DSN usa o serviço de banco plugável FREEPDB1.
As etapas com vetores manuais não exigem uma chave de API da OpenAI. As etapas semânticas enviam o texto de exemplo e a consulta para o provedor de embedding configurado, então usaremos apenas textos de amostra ou não sensíveis.
Este tutorial usa o oracledb, o driver Python atual para Oracle Database. O python-oracledb roda em modo Thin por padrão, então este demo local não requer bibliotecas do Oracle Client. O modo Thick é útil em outras implantações, mas aqui não chamaremos oracledb.init_oracle_client().
Iniciar o Oracle Database Free 26ai localmente
Crie um diretório de projeto para os scripts que vamos construir.
mkdir oracle-ai-vector-search-python
cd oracle-ai-vector-search-pythonTecnologia
Inicie o Oracle Database Free 26ai com a imagem local do container.
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-amd64Tecnologia
Verifique os logs do container e aguarde até o banco indicar que a inicialização foi concluída.
FREEPDB1 é o serviço de database plugável usado por este caminho local do Oracle Database Free. Nosso DSN no Python será localhost:1521/FREEPDB1.
Criar o schema vector_demo no FREEPDB1
Use SYS apenas para a etapa de configuração do schema. A senha no comando sqlplus é o valor de ORACLE_PWD do comando docker run; a senha no CREATE USER é a senha da aplicação que vamos exportar como DB_PASSWORD.
Rode a configuração dentro do container do banco.
# Crie o usuário da aplicação e conceda os privilégios necessários para o 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
SQLTecnologia
Este é um atalho local de desenvolvimento para o container de demo. CREATE SEQUENCE é necessário porque as tabelas usam colunas identity.
Em produção, revisaríamos privilégios com um DBA e aplicaríamos privilégio mínimo para a carga exata da aplicação.
OPENAI_API_KEY é exigida apenas para as etapas de embedding e busca semântica. EMBEDDING_DIM deve corresponder ao número de dimensões retornado pelo modelo escolhido.
Projeto demo do Oracle AI Vector Search
Vamos construir o demo em oito checkpoints. Cada script adiciona um conceito e gera uma saída que podemos verificar antes de avançar.
O checkpoint “apenas banco” termina após os Passos 1–3. Nesse ponto, teremos conectado ao Oracle Database, armazenado vetores manuais, consultado por distância e criado a tabela semântica. A chave de API da OpenAI passa a ser necessária no Passo 4.
Passo 1: conectar ao banco local
Primeiro, vamos verificar se o Python consegue conectar ao Oracle Database como o usuário de aplicação vector_demo. Este script lê DB_USER, DB_PASSWORD e DB_DSN do ambiente e imprime o modo do driver e a versão do banco.
Criar o script
Salve o código a seguir como 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()Tecnologia
A saída deve confirmar que a conexão funciona e que o driver está em modo Thin.
Connected to Oracle Database.
Driver mode: thin
Database version: 23.26.1.0.0Tecnologia
Agora sabemos que o banco local, o nome do serviço, as credenciais e o driver Python estão funcionando antes de criar as tabelas vetoriais.
Passo 2: criar intuição com vetores manuais
Antes de introduzirmos modelos de embedding, vamos armazenar três vetores pequenos que conseguimos entender. A chamada array.array("f", values) cria um array de ponto flutuante 32-bit que o python-oracledb consegue associar a uma coluna VECTOR(..., FLOAT32).
Figura 2. Vetores manuais e distância euclidiana.
O exemplo manual usa distância euclidiana. O vetor “apple” tem distância 0,0000 porque coincide com o vetor de consulta. O vetor “banana” fica em segundo porque sqrt((1.0 - 0.9)^2 + (0.0 - 0.1)^2 + (0.0 - 0.0)^2) = 0,1414.
Criar o script
Salve o código a seguir como 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()Tecnologia
O vetor idêntico aparece primeiro com distância 0,0000 e o vetor “banana” aparece em segundo.
Created manual_vectors.
Inserted 3 manual vectors.
Nearest manual vectors:
1. apple distance=0.0000
2. banana distance=0.1414Tecnologia
Esta é a ideia central da busca vetorial: as linhas são ranqueadas pela proximidade matemática a um vetor de consulta. Modelos de embedding geram vetores maiores, mas o comportamento no banco é o mesmo.
Passo 3: criar a tabela semântica de documentos
Agora que sabemos que vetores funcionam, vamos criar uma tabela no estilo de aplicação. O detalhe importante é que a dimensão da coluna vetorial deve corresponder à dimensão de saída do modelo de embedding.
A dimensão faz parte do contrato da tabela. Se um modelo retorna 1.536 números, a coluna deve ser declarada como VECTOR(1536, FLOAT32).
Se depois trocarmos para um modelo com comprimento diferente, precisamos recriar ou migrar a coluna vetorial para que inserts e consultas continuem compatíveis.
Como DDL não permite associar a dimensão vetorial como bind normal, o script converte EMBEDDING_DIM em inteiro antes de usar no CREATE TABLE.
Criar o script
Salve o código a seguir como 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()Tecnologia
Concluímos a parte apenas de banco. O Oracle Database consegue armazenar e comparar vetores localmente; em seguida, vamos trocar vetores escritos à mão por embeddings gerados a partir de texto.
Passo 4: verificar a dimensão do modelo de embedding
Antes de inserir embeddings, vamos pedir um vetor ao modelo e verificar seu comprimento. Isso evita o erro vetorial mais comum: inserir um vetor cujo comprimento não corresponde à dimensão da coluna VECTOR.
Um modelo de embedding não é apenas um conversor texto→número; ele define o espaço de significado da aplicação. Todos os embeddings de documentos e consultas neste demo devem vir do mesmo modelo.
Usar um único modelo garante que uma distância pequena represente significados similares, e não vetores não relacionados que por acaso tenham forma parecida. O modelo também determina o comprimento do vetor, por isso checamos a dimensão retornada antes de carregar dados.
Criar o script
Salve o código a seguir como 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()Tecnologia
Se escolhermos um modelo de embedding diferente mais tarde, devemos atualizar EMBEDDING_MODEL, definir EMBEDDING_DIM para o comprimento retornado e recriar a tabela documents.
Passo 5: gerar e inserir embeddings de documentos
Agora vamos gerar embeddings para um pequeno dataset autocontido e inseri-los no Oracle Database.
Cada embedding é convertido para array.array("f", embedding) antes de associar, para corresponder à coluna vetorial FLOAT32.
Criar o script
Salve o código a seguir como 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()Tecnologia
Agora temos texto e embeddings armazenados juntos no Oracle Database. Os documents não relacionados sobre violão e sopa foram incluídos para que os resultados tenham correspondências obviamente próximas e distantes.
Passo 6: rodar uma consulta de busca semântica
Em seguida, vamos embutir uma consulta em linguagem natural e compará-la com os embeddings dos documentos armazenados. Este script usa distância de cosseno, comumente usada em embeddings de texto porque foca na direção do vetor, não na magnitude bruta.
Para busca semântica, a consulta passa pelo mesmo modelo de embedding que os documents. Não estamos pedindo ao SQL que entenda a frase em inglês diretamente.
Estamos pedindo ao modelo de embedding que transforme a frase em um vetor e, então, pedindo ao Oracle Database que ranqueie os vetores armazenados pela distância a esse vetor de consulta.
Criar o script
Salve o código a seguir como 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()Tecnologia
Rankings e distâncias exatas podem variar quando o modelo muda. Porém, documents sobre Oracle AI Vector Search, busca semântica, código Python para banco e indexação vetorial devem ranquear no topo.
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...Tecnologia
Para as consultas de distância euclidiana e de cosseno deste tutorial, valores menores indicam correspondências mais próximas.
Produto interno é outra abordagem útil em muitos workflows de busca vetorial, especialmente quando a magnitude ou a normalização dos vetores importam, mas a direção do score e a normalização exigem cuidado.
Vamos manter o código executável em distância euclidiana e de cosseno para simplificar a interpretação.
Se normalizarmos embeddings em um app futuro, precisamos normalizar tanto os embeddings de documentos armazenados quanto os de consulta de forma consistente; do contrário, distâncias e rankings podem mudar.
Passo 7: comparar busca semântica com correspondência por frase
A busca semântica é útil porque não exige que a frase exata apareça no documento.
Vamos comparar a consulta semântica com um predicado simples de frase exata.
Isto não é um demo de mecanismo de busca full-text; é uma pequena comparação em SQL que torna visível a diferença entre correspondência literal e ranqueamento por significado.
Criar o script
Salve o código a seguir como 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()Tecnologia
A busca semântica deve retornar documents relevantes mesmo que a frase exata não esteja presente.
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 matchesTecnologia
Predicados SQL tradicionais continuam importantes para filtros, junções, permissões e correspondência exata. A busca vetorial adiciona um sinal de ranqueamento por significado que podemos combinar com dados relacionais quando a aplicação precisa de recuperação semântica.
Passo 8: adicionar e validar um índice vetorial
Por fim, vamos criar um índice vetorial e validar que o Oracle Database o reporta como um índice válido pertencente ao schema do demo.
Este passo demonstra o fluxo de criação do índice; nosso dataset minúsculo não é grande o suficiente para conclusões de performance.
Sem índice, o Oracle Database pode comparar o vetor de consulta com cada vetor armazenado exatamente. Essa abordagem é adequada para datasets minúsculos e útil durante o aprendizado.
Com datasets maiores, índices vetoriais aproximados reduzem o espaço de busca para que as consultas retornem rápido e ainda encontrem vizinhos próximos.
Escolha a família de índice considerando tamanho de dados, metas de latência, requisitos de recall, orçamento de memória e frequência de mudança dos vetores.
A consulta ao final confirma que a busca semântica ainda retorna resultados após a criação do índice.
Não usaremos EXPLAIN PLAN ou DBMS_XPLAN aqui porque este tutorial valida a criação do índice com metadados do schema, não com o plano de execução.
Criar o script
Salve o código a seguir como 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()Tecnologia
A saída deve incluir uma linha para DOCUMENT_EMBEDDING_IDX, com INDEX_TYPE definido como VECTOR e STATUS como 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.Tecnologia
USER_INDEXES confirma que o índice existe e é válido. Isso não prova que uma consulta específica usou o índice, e este tutorial não usa o plano de execução como método de validação.
Para workloads de produção, testaríamos com volume de dados, padrões de consulta e metas de performance realistas.
Dicas e solução de problemas do Oracle AI Vector Search
O container do banco ainda está iniciando
Espere a inicialização concluir e rode docker logs oracle-free-26ai-vector novamente. O banco precisa estar pronto antes de o Python conectar a localhost:1521/FREEPDB1.
A porta 1521 já está em uso
Pare o serviço local em conflito ou altere o mapeamento de portas do Docker. Atualize o DB_DSN se a porta do host mudar.
A conexão com o banco falha
Verifique DB_USER, DB_PASSWORD e DB_DSN. Use FREEPDB1 no DSN e conecte os scripts da aplicação como vector_demo, não como SYS, SYSTEM ou PDBADMIN.
A chave de API de embedding está ausente
Os passos 1–3 são apenas de banco. Os passos 4–8 exigem OPENAI_API_KEY e podem gerar custos de API.
Uma dimensão vetorial não corresponde
Rode 04_check_embedding_dimension.py, atualize EMBEDDING_DIM, rode novamente 03_create_documents_table.py e recarregue os embeddings com 05_insert_embeddings.py.
Falha ao associar um vetor (bind)
Garanta que todo bind de vetor FLOAT32 use array.array("f", values). O tutorial usa este formato para vetores manuais, embeddings armazenados e embeddings de consulta.
Os rankings semânticos diferem do exemplo
Isso é esperado. Provedores de embedding podem atualizar modelos, e distâncias de ponto flutuante podem variar entre execuções.
Falha na criação do índice vetorial
Confirme que a tabela documents existe, que o schema vector_demo é o dono e que DOCUMENT_EMBEDDING_IDX não ficou de uma execução anterior incompleta.
Preparando para produção
Use oracledb.create_pool() para pool de conexões, faça benchmark com volumes realistas, revise segurança e gestão de segredos e ajuste índices conforme padrões reais de consulta.
Parar e remover o container
Quando terminar o tutorial, pare e remova o container local.
Construímos um fluxo local de busca semântica com Oracle AI Vector Search, Oracle Database Free 26ai e Python.
Começamos com valores VECTOR(3, FLOAT32) escritos à mão, inserimos embeddings gerados por modelo com array.array("f", values), consultamos documents similares com VECTOR_DISTANCE(), comparamos a recuperação semântica com um predicado simples de frase exata e validamos um índice vetorial via USER_INDEXES.
Essa abordagem funciona bem quando embeddings devem ficar ao lado de dados relacionais e queremos armazenamento e busca visíveis em SQL sem adicionar um banco vetorial separado para o fluxo local.
O demo é pequeno de propósito: ensina os fundamentos, não escala de produção. Aplicativos maiores devem fazer benchmark com dados realistas, revisar segurança e privilégios, usar pool de conexões e validar escolhas de indexação sob padrões reais de consulta.
Depois, você pode aprofundar a implementação com estes recursos:
Oracle AI Vector Search LiveLabs oferece workshops práticos sobre embeddings vetoriais, busca exata e aproximada, busca por imagem e RAG.
FAQs
O que é o Oracle AI Vector Search?⌄
Oracle AI Vector Search é um conjunto de recursos do Oracle Database para armazenar, indexar e consultar embeddings vetoriais ao lado de dados relacionais.
Preciso de uma chave de API da OpenAI para concluir o tutorial?⌄
As etapas de vetores manuais e configuração do banco não exigem chave de API. As etapas 4–8 exigem um provedor de embedding e a variável OPENAI_API_KEY configurada.
Por que EMBEDDING_DIM deve corresponder ao modelo de embedding?⌄
A dimensão da coluna VECTOR deve ser igual ao número de valores retornados pelo modelo de embedding. Uma inconsistência faz a inserção vetorial falhar.
Quais métricas de distância o tutorial usa?⌄
O exemplo com vetores manuais usa distância euclidiana. Os exemplos de busca semântica usam distância de cosseno.
Um índice vetorial válido prova que a consulta usou o índice?⌄
Não. USER_INDEXES confirma que o índice existe e está válido, mas não confirma que uma consulta específica o utilizou.
Mark Nelson é arquiteto e developer evangelist na Oracle. Atua na convergência entre IA, microsserviços e tecnologias de banco de dados. É blogueiro ativo, autor publicado, revisor técnico na Manning Publications, Section Leader no Stanford Code in Place e mentor na DeepLearning.ai. Ele apresenta regularmente em Java e Oracle User Groups, encontros de IA e grandes conferências. Tem paixão por aprender e ensinar. Soma mais de trinta anos de experiência no mercado, na IBM e na Oracle.
Um guia completo com os melhores bancos de dados vetoriais. Domine o armazenamento de dados de alta dimensão, decifrar informações não estruturadas e aproveitar as incorporações vetoriais para aplicações de IA.
As incorporações de vetores são representações numéricas de palavras ou frases que capturam seus significados e relacionamentos, ajudando os modelos de machine learning a entender o texto com mais eficiência.
Descubra como melhorar o PostgreSQL com recursos de pesquisa vetorial usando o pgvector. Este tutorial te mostra como instalar, usar as funções básicas e integrar com ferramentas de IA.
Explore nosso guia sobre como usar a API OpenAI para criar incorporações de texto. Descubra suas aplicações na classificação de textos, recuperação de informações e detecção de similaridade semântica.
Uma visão geral abrangente da API Assistants com nosso artigo, que oferece uma análise aprofundada de seus recursos, usos no setor, orientação de configuração e práticas recomendadas para maximizar seu potencial em vários aplicativos de negócios.
Neste tutorial, vamos criar um demo local de busca semântica com Oracle AI Vector Search, Python e Oracle Database Free 26ai.
Começaremos com vetores tridimensionais escritos à mão para que o cálculo de distância fique visível; depois, vamos gerar embeddings de texto e consultá-los no Oracle Database com SQL.
Este tutorial é para desenvolvedores Python e SQL que estão começando com busca vetorial e têm familiaridade com Docker, variáveis de ambiente, pacotes Python e configuração de banco de dados local.
Aplicativos com IA precisam de busca que entenda significado, não só palavras exatas. Um app de suporte, portal de documentação ou ferramenta interna de conhecimento deve conseguir encontrar “armazenamento de banco de dados para busca em IA” mesmo quando o melhor documento diz “armazenar embeddings vetoriais em colunas nativas”.
Vector embeddings tornam isso possível ao representar texto como vetores numéricos. O Oracle AI Vector Search permite armazenar esses vetores diretamente no Oracle Database, consultá-los com SQL e manter embeddings ao lado dos dados relacionais do aplicativo.
Para este fluxo local, não precisamos de um banco vetorial separado.
Vamos executar o Oracle Database Free 26ai localmente, conectar a partir do Python no modo Thin do
oracledb, armazenar primeiro vetores manuais, depois armazenar embeddings da OpenAI, rodar busca semântica, comparar a recuperação semântica com um predicado simples de frase exata e criar um índice vetorial validado por meio deUSER_INDEXES.Ao final, teremos um fluxo de busca semântica em Python que armazena embeddings no Oracle Database e recupera localmente os
documentsmais similares.O que é o Oracle AI Vector Search?
Oracle AI Vector Search é um conjunto de recursos do Oracle Database para armazenar, indexar e consultar embeddings vetoriais. Um embedding vetorial é uma lista de números de tamanho fixo que representa o significado de textos, imagens ou outros dados em uma forma que o banco consegue comparar matematicamente.
Um modelo de embedding cria os vetores numéricos. Ele recebe como entrada uma sentença, parágrafo, descrição de imagem ou trecho de código e retorna um vetor com um número fixo de dimensões.
Entradas similares devem produzir vetores próximos entre si, enquanto entradas não relacionadas devem ficar mais distantes. Por isso, precisamos usar o mesmo modelo de embedding para os documents armazenados e para as consultas, pois as distâncias só fazem sentido quando os vetores compartilham o mesmo sistema de coordenadas.
Neste tutorial, os vetores manuais são deliberadamente pequenos para inspecionarmos a matemática. Os embeddings reais de texto são bem maiores porque o modelo precisa de dimensões suficientes para codificar relações sutis entre palavras, frases e tópicos.
A busca vetorial ranqueia linhas pela distância entre vetores. Para consultas de distância euclidiana e de cosseno, valores menores significam correspondências mais próximas. Neste tutorial, começaremos com uma coluna
VECTOR(3, FLOAT32)pequena para ver o comportamento da distância diretamente e depois passaremos para embeddingsVECTOR(1536, FLOAT32)gerados a partir de texto.Figura 1. Fluxo do Oracle AI Vector Search
Oracle AI Vector Search armazena embeddings em uma coluna nativa VECTOR e ranqueia os resultados pela distância vetorial.
Oracle Database é útil quando embeddings precisam ficar ao lado de dados relacionais do app, como IDs de documentos, títulos, conteúdo, usuários, produtos, tickets ou metadados.
Alguns aplicativos usam um banco vetorial ou mecanismo de busca separado para cargas especializadas de recuperação; mas, para o fluxo local deste tutorial, o Oracle Database oferece os recursos de armazenamento e busca vetorial de que precisamos.
Principais recursos do Oracle AI Vector Search
Usaremos quatro recursos do Oracle AI Vector Search no demo: armazenamento vetorial nativo, funções de distância, índices vetoriais e integração relacional.
Tipo de dado vetorial nativo
Oracle Database suporta colunas nativas
VECTORcom dimensões explícitas e formatos de elemento. No demo, usaremosVECTOR(3, FLOAT32)para vetores manuais eVECTOR(1536, FLOAT32)para o modelo de embedding padrãotext-embedding-3-small.Funções e operadores de distância
Os exemplos executáveis usam
VECTOR_DISTANCE()porque mantém a métrica de distância explícita no SQL.Usaremos distância euclidiana para o exemplo manual e distância de cosseno para embeddings de texto.
Oracle Database também inclui operadores abreviados de distância vetorial e comportamento relacionado a produto interno, mas este tutorial mantém o SQL executável no caminho explícito com
VECTOR_DISTANCE().Métricas de distância diferentes respondem a perguntas ligeiramente diferentes sobre “proximidade”.
Para um tutorial curto, distância de cosseno é um bom padrão para embeddings de texto porque foca na direção, o que costuma mapear bem para similaridade semântica.
A distância euclidiana é mais fácil de visualizar com vetores escritos à mão, e comparações no estilo produto interno são úteis em alguns sistemas quando a magnitude do vetor ou a normalização fazem parte do desenho do modelo.
Métrica
O que compara
Bom para
Fique atento a
Cosseno
Direção do vetor
Embeddings de texto e similaridade semântica
Os resultados dependem do mesmo modelo de embedding e de pré-processamento consistente
Euclidiana
Distância em linha reta
Exemplos pequenos, intuição geométrica, alguns vetores de features numéricas
A magnitude afeta a distância; o escalonamento pode importar
Produto interno
Direção e magnitude juntas
Workflows baseados em vetores normalizados ou pontuação por produto interno
É preciso entender direção do score e regras de normalização antes de comparar resultados
Índices vetoriais
A busca vetorial exata é útil para correção e datasets pequenos. À medida que os dados crescem, índices vetoriais dão suporte a buscas aproximadas de vizinhos mais próximos.
Oracle AI Vector Search inclui índices de grafo de vizinhos em memória, frequentemente associados a buscas no estilo HNSW, e índices de partições de vizinhos, associados à partição no estilo IVF.
Neste demo local, usamos
ORGANIZATION NEIGHBOR PARTITIONSe validamos o índice comUSER_INDEXES.Índices aproximados trocam um pouco da exatidão da busca exaustiva por mais velocidade em escala.
A família de índice certa depende da carga, volume de dados, padrão de atualização e meta de recall.
Este tutorial usa um índice de partições de vizinhos no estilo IVF porque simplifica o setup local e oferece um passo concreto de criação de índice sem transformar o tutorial em um guia de tuning.
Família de índice
Ideia básica
Pontos fortes
Trade-offs
Quando usar
IVF / partições de vizinhos
Particionar o espaço vetorial e buscar nas partições prováveis
Modelo mental simples, prático para muitos datasets carregados em lote
Recall e velocidade dependem da partição e das configurações de busca
Queremos um caminho direto de busca aproximada para um dataset em crescimento
HNSW / grafo de vizinhos
Construir um grafo que liga vetores próximos para travessia rápida
Ótimo perfil de recall e latência para muitos workloads de vizinhos mais próximos
Mais orientado a memória; a configuração pode importar mais
Precisamos de baixa latência e podemos investir memória e esforço de tuning
Integração com consultas relacionais
Uma coluna vetorial pode viver ao lado de colunas relacionais comuns. Nossa tabela de documents vai armazenar título, conteúdo e embedding juntos, para que o SQL retorne tanto o score de similaridade quanto o texto original.
Como começar com Oracle AI Vector Search
Vamos usar um caminho local: Oracle Database Free 26ai no Docker, o serviço
FREEPDB1e um usuário de aplicação dedicadovector_demo.Os conceitos de busca vetorial são acessíveis, mas a configuração é intermediária porque usamos Docker, um schema de banco, pacotes Python, variáveis de ambiente e uma chave de API de embedding.
Pré-requisitos
Vamos precisar de:
Este demo requer uma versão/ambiente do Oracle Database que inclua os recursos vetoriais usados aqui, incluindo colunas nativas
VECTOR,VECTOR_DISTANCE()eCREATE VECTOR INDEX.O caminho local usa Oracle Database Free 26ai com a tag de imagem mostrada abaixo, e o DSN usa o serviço de banco plugável
FREEPDB1.As etapas com vetores manuais não exigem uma chave de API da
OpenAI. As etapas semânticas enviam o texto de exemplo e a consulta para o provedor de embedding configurado, então usaremos apenas textos de amostra ou não sensíveis.Este tutorial usa o
oracledb, o driver Python atual para Oracle Database. Opython-oracledbroda em modo Thin por padrão, então este demo local não requer bibliotecas do Oracle Client. O modo Thick é útil em outras implantações, mas aqui não chamaremosoracledb.init_oracle_client().Iniciar o Oracle Database Free 26ai localmente
Crie um diretório de projeto para os scripts que vamos construir.
Inicie o Oracle Database Free 26ai com a imagem local do container.
Verifique os logs do container e aguarde até o banco indicar que a inicialização foi concluída.
FREEPDB1é o serviço de database plugável usado por este caminho local do Oracle Database Free. Nosso DSN no Python serálocalhost:1521/FREEPDB1.Criar o schema vector_demo no FREEPDB1
Use
SYSapenas para a etapa de configuração do schema. A senha no comando sqlplus é o valor de ORACLE_PWD do comando docker run; a senha no CREATE USER é a senha da aplicação que vamos exportar comoDB_PASSWORD.Rode a configuração dentro do container do banco.
Este é um atalho local de desenvolvimento para o container de demo. CREATE SEQUENCE é necessário porque as tabelas usam colunas identity.
Em produção, revisaríamos privilégios com um DBA e aplicaríamos privilégio mínimo para a carga exata da aplicação.
Instalar dependências Python
Crie e ative um ambiente virtual.
Instale os pacotes Python usados no demo.
Definir variáveis de ambiente
Guarde credenciais do banco e parâmetros de embedding em variáveis de ambiente em vez de fixá-los nos arquivos Python.
OPENAI_API_KEYé exigida apenas para as etapas de embedding e busca semântica.EMBEDDING_DIMdeve corresponder ao número de dimensões retornado pelo modelo escolhido.Projeto demo do Oracle AI Vector Search
Vamos construir o demo em oito checkpoints. Cada script adiciona um conceito e gera uma saída que podemos verificar antes de avançar.
O checkpoint “apenas banco” termina após os Passos 1–3. Nesse ponto, teremos conectado ao Oracle Database, armazenado vetores manuais, consultado por distância e criado a tabela semântica. A chave de API da
OpenAIpassa a ser necessária no Passo 4.Passo 1: conectar ao banco local
Primeiro, vamos verificar se o Python consegue conectar ao Oracle Database como o usuário de aplicação
vector_demo. Este script lêDB_USER, DB_PASSWORDeDB_DSNdo ambiente e imprime o modo do driver e a versão do banco.Criar o script
Salve o código a seguir como
01_check_connection.py.Executar o script
Rode a verificação de conexão.
Saída esperada
A saída deve confirmar que a conexão funciona e que o driver está em modo Thin.
Agora sabemos que o banco local, o nome do serviço, as credenciais e o driver Python estão funcionando antes de criar as tabelas vetoriais.
Passo 2: criar intuição com vetores manuais
Antes de introduzirmos modelos de embedding, vamos armazenar três vetores pequenos que conseguimos entender. A chamada
array.array("f", values)cria um array de ponto flutuante 32-bit que opython-oracledbconsegue associar a uma colunaVECTOR(..., FLOAT32).Figura 2. Vetores manuais e distância euclidiana.
O exemplo manual usa distância euclidiana. O vetor “apple” tem distância 0,0000 porque coincide com o vetor de consulta. O vetor “banana” fica em segundo porque sqrt((1.0 - 0.9)^2 + (0.0 - 0.1)^2 + (0.0 - 0.0)^2) = 0,1414.
Criar o script
Salve o código a seguir como
02_manual_vectors.py.Executar o script
Rode o script de vetores manuais.
Saída esperada
O vetor idêntico aparece primeiro com distância 0,0000 e o vetor “banana” aparece em segundo.
Esta é a ideia central da busca vetorial: as linhas são ranqueadas pela proximidade matemática a um vetor de consulta. Modelos de embedding geram vetores maiores, mas o comportamento no banco é o mesmo.
Passo 3: criar a tabela semântica de documentos
Agora que sabemos que vetores funcionam, vamos criar uma tabela no estilo de aplicação. O detalhe importante é que a dimensão da coluna vetorial deve corresponder à dimensão de saída do modelo de embedding.
A dimensão faz parte do contrato da tabela. Se um modelo retorna 1.536 números, a coluna deve ser declarada como
VECTOR(1536, FLOAT32).Se depois trocarmos para um modelo com comprimento diferente, precisamos recriar ou migrar a coluna vetorial para que inserts e consultas continuem compatíveis.
Como DDL não permite associar a dimensão vetorial como bind normal, o script converte
EMBEDDING_DIMem inteiro antes de usar no CREATE TABLE.Criar o script
Salve o código a seguir como
03_create_documents_table.py.Executar o script
Rode o script de criação da tabela.
Saída esperada
A saída deve mostrar o modelo de embedding configurado e a dimensão vetorial.
Concluímos a parte apenas de banco. O Oracle Database consegue armazenar e comparar vetores localmente; em seguida, vamos trocar vetores escritos à mão por embeddings gerados a partir de texto.
Passo 4: verificar a dimensão do modelo de embedding
Antes de inserir embeddings, vamos pedir um vetor ao modelo e verificar seu comprimento. Isso evita o erro vetorial mais comum: inserir um vetor cujo comprimento não corresponde à dimensão da coluna
VECTOR.Um modelo de embedding não é apenas um conversor texto→número; ele define o espaço de significado da aplicação. Todos os embeddings de documentos e consultas neste demo devem vir do mesmo modelo.
Usar um único modelo garante que uma distância pequena represente significados similares, e não vetores não relacionados que por acaso tenham forma parecida. O modelo também determina o comprimento do vetor, por isso checamos a dimensão retornada antes de carregar dados.
Criar o script
Salve o código a seguir como
04_check_embedding_dimension.py.Executar o script
Rode a checagem de dimensão.
Saída esperada
Para o modelo e dimensão padrão, a saída deve parecer com isto.
Se escolhermos um modelo de embedding diferente mais tarde, devemos atualizar
EMBEDDING_MODEL, definirEMBEDDING_DIMpara o comprimento retornado e recriar a tabeladocuments.Passo 5: gerar e inserir embeddings de documentos
Agora vamos gerar embeddings para um pequeno dataset autocontido e inseri-los no Oracle Database.
Cada embedding é convertido para
array.array("f", embedding)antes de associar, para corresponder à coluna vetorialFLOAT32.Criar o script
Salve o código a seguir como
05_insert_embeddings.py.Executar o script
Rode o script de insert.
Saída esperada
A contagem de linhas deve corresponder aos sete
documentsinline.Agora temos texto e embeddings armazenados juntos no Oracle Database. Os
documentsnão relacionados sobre violão e sopa foram incluídos para que os resultados tenham correspondências obviamente próximas e distantes.Passo 6: rodar uma consulta de busca semântica
Em seguida, vamos embutir uma consulta em linguagem natural e compará-la com os embeddings dos documentos armazenados. Este script usa distância de cosseno, comumente usada em embeddings de texto porque foca na direção do vetor, não na magnitude bruta.
Para busca semântica, a consulta passa pelo mesmo modelo de embedding que os
documents. Não estamos pedindo ao SQL que entenda a frase em inglês diretamente.Estamos pedindo ao modelo de embedding que transforme a frase em um vetor e, então, pedindo ao Oracle Database que ranqueie os vetores armazenados pela distância a esse vetor de consulta.
Criar o script
Salve o código a seguir como
06_semantic_search.py.Executar o script
Rode o script de busca semântica.
Saída esperada
Rankings e distâncias exatas podem variar quando o modelo muda. Porém,
documentssobre Oracle AI Vector Search, busca semântica, código Python para banco e indexação vetorial devem ranquear no topo.Para as consultas de distância euclidiana e de cosseno deste tutorial, valores menores indicam correspondências mais próximas.
Produto interno é outra abordagem útil em muitos workflows de busca vetorial, especialmente quando a magnitude ou a normalização dos vetores importam, mas a direção do score e a normalização exigem cuidado.
Vamos manter o código executável em distância euclidiana e de cosseno para simplificar a interpretação.
Se normalizarmos embeddings em um app futuro, precisamos normalizar tanto os embeddings de documentos armazenados quanto os de consulta de forma consistente; do contrário, distâncias e rankings podem mudar.
Passo 7: comparar busca semântica com correspondência por frase
A busca semântica é útil porque não exige que a frase exata apareça no documento.
Vamos comparar a consulta semântica com um predicado simples de frase exata.
Isto não é um demo de mecanismo de busca full-text; é uma pequena comparação em SQL que torna visível a diferença entre correspondência literal e ranqueamento por significado.
Criar o script
Salve o código a seguir como
07_semantic_vs_keyword.py.Executar o script
Rode o script de comparação.
Saída esperada
A busca semântica deve retornar
documentsrelevantes mesmo que a frase exata não esteja presente.Predicados SQL tradicionais continuam importantes para filtros, junções, permissões e correspondência exata. A busca vetorial adiciona um sinal de ranqueamento por significado que podemos combinar com dados relacionais quando a aplicação precisa de recuperação semântica.
Passo 8: adicionar e validar um índice vetorial
Por fim, vamos criar um índice vetorial e validar que o Oracle Database o reporta como um índice válido pertencente ao schema do demo.
Este passo demonstra o fluxo de criação do índice; nosso dataset minúsculo não é grande o suficiente para conclusões de performance.
Sem índice, o Oracle Database pode comparar o vetor de consulta com cada vetor armazenado exatamente. Essa abordagem é adequada para datasets minúsculos e útil durante o aprendizado.
Com datasets maiores, índices vetoriais aproximados reduzem o espaço de busca para que as consultas retornem rápido e ainda encontrem vizinhos próximos.
Escolha a família de índice considerando tamanho de dados, metas de latência, requisitos de recall, orçamento de memória e frequência de mudança dos vetores.
A consulta ao final confirma que a busca semântica ainda retorna resultados após a criação do índice.
Não usaremos EXPLAIN PLAN ou DBMS_XPLAN aqui porque este tutorial valida a criação do índice com metadados do schema, não com o plano de execução.
Criar o script
Salve o código a seguir como
08_create_vector_index.py.Executar o script
Rode o script do índice.
Saída esperada
A saída deve incluir uma linha para
DOCUMENT_EMBEDDING_IDX, comINDEX_TYPEdefinido comoVECTOReSTATUScomoVALID.USER_INDEXESconfirma que o índice existe e é válido. Isso não prova que uma consulta específica usou o índice, e este tutorial não usa o plano de execução como método de validação.Para workloads de produção, testaríamos com volume de dados, padrões de consulta e metas de performance realistas.
Dicas e solução de problemas do Oracle AI Vector Search
O container do banco ainda está iniciando
Espere a inicialização concluir e rode
docker logs oracle-free-26ai-vectornovamente. O banco precisa estar pronto antes de o Python conectar alocalhost:1521/FREEPDB1.A porta 1521 já está em uso
Pare o serviço local em conflito ou altere o mapeamento de portas do Docker. Atualize o
DB_DSNse a porta do host mudar.A conexão com o banco falha
Verifique
DB_USER, DB_PASSWORDeDB_DSN. UseFREEPDB1no DSN e conecte os scripts da aplicação comovector_demo, não comoSYS, SYSTEMouPDBADMIN.A chave de API de embedding está ausente
Os passos 1–3 são apenas de banco. Os passos 4–8 exigem
OPENAI_API_KEYe podem gerar custos de API.Uma dimensão vetorial não corresponde
Rode
04_check_embedding_dimension.py, atualizeEMBEDDING_DIM, rode novamente03_create_documents_table.pye recarregue os embeddings com05_insert_embeddings.py.Falha ao associar um vetor (bind)
Garanta que todo bind de vetor
FLOAT32usearray.array("f", values). O tutorial usa este formato para vetores manuais, embeddings armazenados e embeddings de consulta.Os rankings semânticos diferem do exemplo
Isso é esperado. Provedores de embedding podem atualizar modelos, e distâncias de ponto flutuante podem variar entre execuções.
Falha na criação do índice vetorial
Confirme que a tabela
documentsexiste, que o schemavector_demoé o dono e queDOCUMENT_EMBEDDING_IDXnão ficou de uma execução anterior incompleta.Preparando para produção
Use
oracledb.create_pool()para pool de conexões, faça benchmark com volumes realistas, revise segurança e gestão de segredos e ajuste índices conforme padrões reais de consulta.Parar e remover o container
Quando terminar o tutorial, pare e remova o container local.
Conclusão
Construímos um fluxo local de busca semântica com Oracle AI Vector Search, Oracle Database Free 26ai e Python.
Começamos com valores
VECTOR(3, FLOAT32)escritos à mão, inserimos embeddings gerados por modelo comarray.array("f", values), consultamosdocumentssimilares comVECTOR_DISTANCE(), comparamos a recuperação semântica com um predicado simples de frase exata e validamos um índice vetorial viaUSER_INDEXES.Essa abordagem funciona bem quando embeddings devem ficar ao lado de dados relacionais e queremos armazenamento e busca visíveis em SQL sem adicionar um banco vetorial separado para o fluxo local.
O demo é pequeno de propósito: ensina os fundamentos, não escala de produção. Aplicativos maiores devem fazer benchmark com dados realistas, revisar segurança e privilégios, usar pool de conexões e validar escolhas de indexação sob padrões reais de consulta.
Depois, você pode aprofundar a implementação com estes recursos: