Armazenamentos de Vetores¶
O Armazenamento de Vetores Rememberizer simplifica o processo de lidar com dados vetoriais, permitindo que você se concentre na entrada de texto e aproveite o poder dos vetores para várias aplicações, como pesquisa e análise de dados.
Introdução¶
O Rememberizer Vector Store fornece uma interface fácil de usar para lidar com dados vetoriais, enquanto abstrai a complexidade das incorporações vetoriais. Alimentado pelo PostgreSQL com a extensão pgvector, o Rememberizer Vector Store permite que você trabalhe diretamente com texto. O serviço lida com a fragmentação, vetorização e armazenamento dos dados de texto, facilitando para você se concentrar na lógica central de sua aplicação.
Para uma compreensão mais profunda dos conceitos teóricos por trás das incorporações vetoriais e bancos de dados vetoriais, veja O que são Incorporações Vetoriais e Bancos de Dados Vetoriais?.
Visão Técnica¶
Como Funcionam os Armazenamentos de Vetores¶
Os Armazenamentos de Vetores Rememberizer convertem texto em representações vetoriais de alta dimensão (embeddings) que capturam o significado semântico. Isso possibilita:
- Busca Semântica: Encontrar documentos com base no significado em vez de apenas palavras-chave
- Correspondência de Similaridade: Identificar conteúdo conceitualmente relacionado
- Recuperação Eficiente: Localizar rapidamente informações relevantes em grandes conjuntos de dados
Componentes Chave¶
- Processamento de Documentos: O texto é dividido em pedaços de tamanho otimizado com limites sobrepostos para preservação de contexto
- Vetorização: Os pedaços são convertidos em embeddings usando modelos de ponta
- Indexação: Algoritmos especializados organizam vetores para busca de similaridade eficiente
- Processamento de Consultas: Consultas de busca são vetorizadas e comparadas com embeddings armazenados
Arquitetura¶
Rememberizer implementa armazenamentos de vetores usando:
- PostgreSQL com extensão pgvector: Para armazenamento e busca de vetores eficientes
- Organização baseada em coleções: Cada armazenamento de vetores tem sua própria coleção isolada
- Acesso orientado a API: Pontos finais RESTful simples para todas as operações
Começando¶
Criando um Armazenamento de Vetores¶
- Navegue até a Seção de Armazenamentos de Vetores no seu painel
- Clique em "Criar novo Armazenamento de Vetores":
- Um formulário aparecerá solicitando que você insira os detalhes.
- Preencha os Detalhes:
- Nome: Forneça um nome único para o seu armazenamento de vetores.
- Descrição: Escreva uma breve descrição do armazenamento de vetores.
- Modelo de Embedding: Selecione o modelo que converte texto em vetores.
- Algoritmo de Indexação: Escolha como os vetores serão organizados para busca.
- Métrica de Busca: Defina como a similaridade entre vetores é calculada.
- Dimensão do Vetor: O tamanho das embeddings de vetores (tipicamente 768-1536).
- Envie o Formulário:
- Clique no botão "Criar". Você receberá uma notificação de sucesso, e o novo armazenamento aparecerá na sua lista de armazenamentos de vetores.

Criar um Novo Armazenamento de Vetores
Opções de Configuração¶
Modelos de Embedding¶
| Modelo | Dimensões | Descrição | Melhor Para |
|---|---|---|---|
| openai/text-embedding-3-large | 1536 | Modelo de embedding de alta precisão da OpenAI | Aplicações de produção que exigem máxima precisão |
| openai/text-embedding-3-small | 1536 | Modelo de embedding menor e mais rápido da OpenAI | Aplicações com requisitos de maior taxa de transferência |
Algoritmos de Indexação¶
| Algoritmo | Descrição | Compensações |
|---|---|---|
| IVFFLAT (padrão) | Arquivo invertido com compressão plana | Bom equilíbrio entre velocidade e precisão; funciona bem para a maioria dos conjuntos de dados |
| HNSW | Mundo Pequeno Navegável Hierárquico | Melhor precisão para grandes conjuntos de dados; maiores requisitos de memória |
Métricas de Busca¶
| Métrica | Descrição | Melhor Para |
|---|---|---|
| cosseno (padrão) | Mede o ângulo entre vetores | Correspondência de similaridade de propósito geral |
| produto interno (ip) | Produto escalar entre vetores | Quando a magnitude do vetor é importante |
| L2 (Euclidiana) | Distância em linha reta entre vetores | Quando relações espaciais são importantes |
Gerenciando Armazenamentos de Vetores¶
- Visualizar e Editar Armazenamentos de Vetores:
- Acesse o painel de gerenciamento para visualizar, editar ou excluir armazenamentos de vetores.
- Visualizando Documentos:
- Navegue por documentos individuais e seus metadados associados dentro de um armazenamento de vetores específico.
- Estatísticas:
- Veja estatísticas detalhadas, como o número de vetores armazenados, desempenho de consultas e métricas operacionais.

Ver Detalhes de um Armazenamento de Vetores
Gerenciamento de Chaves de API¶
As chaves de API são usadas para autenticar e autorizar o acesso aos endpoints da API do Rememberizer Vector Store. O gerenciamento adequado das chaves de API é essencial para manter a segurança e a integridade dos seus armazéns de vetores.
Criando Chaves de API¶
- Vá para a página de detalhes do seu Vector Store
- Navegue até a Seção de Gerenciamento de Chaves de API:
- Ela pode ser encontrada na aba "Configuração"
- Clique em "Adicionar Chave de API":
- Um formulário aparecerá solicitando que você insira os detalhes.
- Preencha os Detalhes:
- Nome: Forneça um nome para a chave de API para ajudá-lo a identificar seu caso de uso.
- Envie o Formulário:
- Clique no botão "Criar". A nova chave de API será gerada e exibida. Certifique-se de copiá-la e armazená-la com segurança. Esta chave é usada para autenticar solicitações a esse vetor store específico.

Criar uma Nova Chave de API
Revogando Chaves de API¶
Se uma chave de API não for mais necessária, você pode excluí-la para evitar qualquer uso indevido potencial.
Por razões de segurança, você pode querer girar suas chaves de API periodicamente. Isso envolve gerar uma nova chave e revogar a antiga.
Usando a API do Armazenamento Vetorial¶
Após criar um Armazenamento Vetorial e gerar uma chave de API, você pode interagir com ele usando a API REST.
Exemplos de Código¶
import requests
import json
API_KEY = "sua_chave_api_aqui"
VECTOR_STORE_ID = "vs_abc123" # Substitua pelo seu ID de armazenamento de vetores
BASE_URL = "https://api.rememberizer.a
# Carregar um documento para o armazenamento vetorial
def upload_document(file_path, document_name=None):
if document_name is None:
document_name = file_path.split("/")[-1]
with open(file_path, "rb") as f:
files = {"file": (document_name, f)}
headers = {"x-api-key": API_KEY}
response = requests.post(
f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents",
headers=headers,
files=files
)
if response.status_code == 201:
print(f"Documento '{document_name}' carregado com sucesso!")
return response.json()
else:
print(f"Erro ao carregar o documento: {response.text}")
return None
# Carregar conteúdo de texto para o armazenamento vetorial
def upload_text(content, document_name):
headers = {
"x-api-key": API_KEY,
"Content-Type": "application/json"
}
data = {
"name": document_name,
"content": content
}
response = requests.post(
f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
headers=headers,
json=data
)
if response.status_code == 201:
print(f"Documento de texto '{document_name}' carregado com sucesso!")
return response.json()
else:
print(f"Erro ao carregar texto: {response.text}")
return None
# Pesquisar no armazenamento vetorial
def search_vector_store(query, num_results=5, prev_chunks=1, next_chunks=1):
headers = {"x-api-key": API_KEY}
params = {
"q": query,
"n": num_results,
"prev_chunks": prev_chunks,
"next_chunks": next_chunks
}
response = requests.get(
f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/search",
headers=headers,
params=params
)
if response.status_code == 200:
results = response.json()
print(f"Encontrados {len(results['matched_chunks'])} correspondências para '{query}'")
# Imprimir o melhor resultado
if results['matched_chunks']:
top_match = results['matched_chunks'][0]
print(f"Melhor correspondência (distância: {top_match['distance']}):")
print(f"Documento: {top_match['document']['name']}")
print(f"Conteúdo: {top_match['matched_content']}")
return results
else:
print(f"Erro ao pesquisar: {response.text}")
return None
# Exemplo de uso
# upload_document("path/to/document.pdf")
# upload_text("Este é um texto de exemplo para ser vetorizado", "sample-document.txt")
# search_vector_store("Como funciona a similaridade de vetores?")
// Cliente da API do Armazenamento de Vetores
class VectorStoreClient {
constructor(apiKey, vectorStoreId) {
this.apiKey = apiKey;
this.vectorStoreId = vectorStoreId;
this.baseUrl = 'https://api.rememberizer.ai/api/v1';
}
// Obter informações do armazenamento de vetores
async getVectorStoreInfo() {
const response = await fetch(`${this.baseUrl}/vector-stores/${this.vectorStoreId}`, {
method: 'GET',
headers: {
'x-api-key': this.apiKey
}
});
if (!response.ok) {
throw new Error(`Falha ao obter informações do armazenamento de vetores: ${response.statusText}`);
}
return response.json();
}
// Fazer upload de um documento de texto
async uploadTextDocument(name, content) {
const response = await fetch(`${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/text`, {
method: 'POST',
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
content
})
});
if (!response.ok) {
throw new Error(`Falha ao fazer upload do documento de texto: ${response.statusText}`);
}
return response.json();
}
// Fazer upload de um arquivo
async uploadFile(file, onProgress) {
const formData = new FormData();
formData.append('file', file);
const xhr = new XMLHttpRequest();
return new Promise((resolve, reject) => {
xhr.open('POST', `${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents`);
xhr.setRequestHeader('x-api-key', this.apiKey);
xhr.upload.onprogress = (event) => {
if (event.lengthComputable && onProgress) {
const percentComplete = (event.loaded / event.total) * 100;
onProgress(percentComplete);
}
};
xhr.onload = () => {
if (xhr.status === 201) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`Falha ao fazer upload do arquivo: ${xhr.statusText}`));
}
};
xhr.onerror = () => {
reject(new Error('Erro de rede durante o upload do arquivo'));
};
xhr.send(formData);
});
}
// Pesquisar documentos no armazenamento de vetores
async searchDocuments(query, options = {}) {
const params = new URLSearchParams({
q: query,
n: options.numResults || 10,
prev_chunks: options.prevChunks || 1,
next_chunks: options.nextChunks || 1
});
if (options.threshold) {
params.append('t', options.threshold);
}
const response = await fetch(
`${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/search?${params}`,
{
method: 'GET',
headers: {
'x-api-key': this.apiKey
}
}
);
if (!response.ok) {
throw new Error(`Falha na pesquisa: ${response.statusText}`);
}
return response.json();
}
// Listar todos os documentos no armazenamento de vetores
async listDocuments() {
const response = await fetch(
`${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents`,
{
method: 'GET',
headers: {
'x-api-key': this.apiKey
}
}
);
if (!response.ok) {
throw new Error(`Falha ao listar documentos: ${response.statusText}`);
}
return response.json();
}
// Deletar um documento
async deleteDocument(documentId) {
const response = await fetch(
`${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/${documentId}`,
{
method: 'DELETE',
headers: {
'x-api-key': this.apiKey
}
}
);
if (!response.ok) {
throw new Error(`Falha ao deletar documento: ${response.statusText}`);
}
return true;
}
}
// Exemplo de uso
/*
const client = new VectorStoreClient('your_api_key', 'vs_abc123');
// Pesquisar documentos
client.searchDocuments('Como funciona a pesquisa semântica?')
.then(results => {
console.log(`Encontrados ${results.matched_chunks.length} correspondências`);
results.matched_chunks.forEach(match => {
console.log(`Documento: ${match.document.name}`);
console.log(`Pontuação: ${match.distance}`);
console.log(`Conteúdo: ${match.matched_content}`);
console.log('---');
});
})
.catch(error => console.error(error));
*/
require 'net/http'
require 'uri'
require 'json'
class VectorStoreClient
def initialize(api_key, vector_store_id)
@api_key = api_key
@vector_store_id = vector_store_id
@base_url = 'https://api.rememberizer.ai/api/v1'
end
# Obter detalhes do armazenamento de vetores
def get_vector_store_info
uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}")
request = Net::HTTP::Get.new(uri)
request['x-api-key'] = @api_key
response = send_request(uri, request)
JSON.parse(response.body)
end
# Fazer upload de conteúdo de texto
def upload_text(name, content)
uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents/text")
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['x-api-key'] = @api_key
request.body = {
name: name,
content: content
}.to_json
response = send_request(uri, request)
JSON.parse(response.body)
end
# Pesquisar documentos
def search(query, num_results: 5, prev_chunks: 1, next_chunks: 1, threshold: nil)
uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents/search")
params = {
q: query,
n: num_results,
prev_chunks: prev_chunks,
next_chunks: next_chunks
}
params[:t] = threshold if threshold
uri.query = URI.encode_www_form(params)
request = Net::HTTP::Get.new(uri)
request['x-api-key'] = @api_key
response = send_request(uri, request)
JSON.parse(response.body)
end
# Listar documentos
def list_documents
uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents")
request = Net::HTTP::Get.new(uri)
request['x-api-key'] = @api_key
response = send_request(uri, request)
JSON.parse(response.body)
end
# Fazer upload de arquivo (formulário multipart)
def upload_file(file_path)
uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents")
file_name = File.basename(file_path)
file_content = File.binread(file_path)
boundary = "RememberizerBoundary#{rand(1000000)}"
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
request['x-api-key'] = @api_key
post_body = []
post_body << "--#{boundary}\r\n"
post_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{file_name}\"\r\n"
post_body << "Content-Type: application/octet-stream\r\n\r\n"
post_body << file_content
post_body << "\r\n--#{boundary}--\r\n"
request.body = post_body.join
response = send_request(uri, request)
JSON.parse(response.body)
end
private
def send_request(uri, request)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
response = http.request(request)
unless response.is_a?(Net::HTTPSuccess)
raise "A solicitação da API falhou: #{response.code} #{response.message}\n#{response.body}"
end
response
end
end
Exemplo de uso¶
=begin client = VectorStoreClient.new('your_api_key', 'vs_abc123')
Pesquisar documentos¶
results = client.search('Quais são as melhores práticas para segurança de dados?') puts "Encontrados #{results['matched_chunks'].length} resultados"
Exibir o melhor resultado¶
if results['matched_chunks'].any? top_match = results['matched_chunks'].first puts "Melhor correspondência (distância: #{top_match['distance']}):" puts "Documento: #{top_match['document']['name']}" puts "Conteúdo: #{top_match['matched_content']}" end =end ```
# Defina sua chave de API e ID do Armazenamento Vetorial
API_KEY="your_api_key_here"
VECTOR_STORE_ID="vs_abc123"
BASE_URL="https://api.rememberizer.ai/api/v1"
# Obter informações do armazenamento de vetores
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}"
-H "x-api-key: ${API_KEY}"
# Carregar um documento de texto
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/text"
-H "x-api-key: ${API_KEY}"
-H "Content-Type: application/json"
-d '{
"name": "example-document.txt",
"content": "Este é um documento de exemplo que será vetorizado e armazenado no banco de dados vetorial para busca semântica."
}'
# Carregar um arquivo
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents"
-H "x-api-key: ${API_KEY}"
-F "file=@/caminho/para/seu/documento.pdf"
# Pesquisar documentos
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/search?q=semantic%20search&n=5&prev_chunks=1&next_chunks=1"
-H "x-api-key: ${API_KEY}"
# Listar todos os documentos
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents"
-H "x-api-key: ${API_KEY}"
# Excluir um documento
curl -X DELETE "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/123"
-H "x-api-key: ${API_KEY}"
Considerações de Desempenho¶
Em breve: Diagrama de Arquitetura do Armazenamento Vetorial
Este diagrama de arquitetura técnica ilustrará:
- A arquitetura de fundação PostgreSQL + pgvector
- Estruturas de algoritmos de indexação (IVFFLAT vs. HNSW)
- Como as métricas de busca funcionam no espaço vetorial (comparação visual)
- Processo de fragmentação de documentos com visualização de sobreposição
- Considerações de desempenho visualizadas em diferentes escalas
Otimizando para Diferentes Volumes de Dados¶
| Volume de Dados | Configuração Recomendada | Notas |
|---|---|---|
| Pequeno (<10k documentos) | IVFFLAT, similaridade cosseno | Configuração simples proporciona bom desempenho |
| Médio (10k-100k documentos) | IVFFLAT, garantir reindexação regular | Equilíbrio entre velocidade de busca e manutenção do índice |
| Grande (>100k documentos) | HNSW, considerar aumentar as dimensões do vetor | Maior uso de memória, mas mantém desempenho em escala |
Estratégias de Fragmentação¶
O processo de fragmentação impacta significativamente a qualidade da busca:
- Tamanho do Fragmento: Rememberizer utiliza um tamanho de fragmento padrão de 1024 bytes com uma sobreposição de 200 bytes
- Fragmentos Menores (512-1024 bytes): Correspondências mais precisas, melhores para perguntas específicas
- Fragmentos Maiores (1500-2048 bytes): Mais contexto em cada correspondência, melhores para tópicos mais amplos
- Sobreposição: Garante que o contexto não seja perdido nas fronteiras dos fragmentos
Otimização de Consulta¶
- Janelas de Contexto: Use
prev_chunksenext_chunkspara recuperar conteúdo ao redor - Contagem de Resultados: Comece com 3-5 resultados (
nparameter) e ajuste com base nas necessidades de precisão - Limite: Ajuste o parâmetro
tpara filtrar resultados por pontuação de similaridade
Uso Avançado¶
Reindexação¶
Rememberizer aciona automaticamente a reindexação quando a contagem de vetores excede os limites predefinidos, mas considere a reindexação manual após:
- Carregar um grande número de documentos
- Alterar o modelo de incorporação
- Modificar o algoritmo de indexação
Aprimoramento de Consulta¶
Para melhores resultados de busca:
- Seja específico nas consultas de busca
- Inclua contexto quando possível
- Use linguagem natural em vez de palavras-chave
- Ajuste parâmetros com base na qualidade do resultado
Migrando de Outras Bases de Dados Vetoriais¶
Se você está atualmente usando outras soluções de banco de dados vetoriais e deseja migrar para o Rememberizer Vector Store, os seguintes guias o ajudarão a transitar seus dados de forma eficiente.
Visão Geral da Migração¶
Migrar dados vetoriais envolve: 1. Exportar dados do seu banco de dados vetorial de origem 2. Converter os dados para um formato compatível com o Rememberizer 3. Importar os dados para o seu Armazenamento Vetorial Rememberizer 4. Verificar se a migração foi bem-sucedida
Benefícios da Migração para Rememberizer¶
- Fundação PostgreSQL: Construído sobre tecnologia de banco de dados madura com backup e recuperação integrados
- Ecossistema Integrado: Conexão perfeita com outros componentes do Rememberizer
- Gerenciamento Simplificado: Interface unificada para operações vetoriais
- Segurança Avançada: Segurança em nível de linha e controles de acesso granulares
- Arquitetura Escalável: Otimização de desempenho à medida que seus dados crescem
Migrando do Pinecone¶
import os
import pinecone
import requests
import json
import time
# Configurar cliente Pinecone
pinecone.init(api_key="PINECONE_API_KEY", environment="PINECONE_ENV")
source_index = pinecone.Index("seu-indice-pinecone")
# Configurar cliente do Armazenamento Vetorial Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123" # Seu ID de armazenamento vetorial Rememberizer
BASE_URL = "https://api.rememberizer.ai/api/v1"
# 1. Defina o tamanho do lote para migração (ajuste com base no tamanho dos seus dados)
BATCH_SIZE = 100
# 2. Função para obter vetores do Pinecone
def fetch_vectors_from_pinecone(index_name, batch_size, cursor=None):
# Use a operação de lista se disponível na sua versão do Pinecone
try:
result = source_index.list(limit=batch_size, cursor=cursor)
vectors = result.get("vectors", {})
next_cursor = result.get("cursor")
return vectors, next_cursor
except AttributeError:
# Para versões mais antigas do Pinecone sem operação de lista
# Esta é uma abordagem simplificada; a implementação real depende do seu padrão de acesso a dados
query_response = source_index.query(
vector=[0] * source_index.describe_index_stats()["dimension"],
top_k=batch_size,
include_metadata=True,
include_values=True
)
return {item.id: {"id": item.id, "values": item.values, "metadata": item.metadata}
for item in query_response.matches}, None
# 3. Função para enviar vetores para Rememberizer
def upload_to_rememberizer(vectors):
headers = {
"x-api-key": REMEMBERIZER_API_KEY,
"Content-Type": "application/json"
}
for vector_id, vector_data in vectors.items():
# Converter dados do vetor Pinecone para o formato Rememberizer
document_name = vector_data.get("metadata", {}).get("filename", f"pinecone_doc_{vector_id}")
content = vector_data.get("metadata", {}).get("text", "")
if not content:
print(f"Pulando {vector_id} - nenhum conteúdo de texto encontrado nos metadados")
continue
data = {
"name": document_name,
"content": content,
# Opcional: incluir metadados adicionais
"metadata": vector_data.get("metadata", {})
}
response = requests.post(
f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
headers=headers,
json=data
)
if response.status_code == 201:
print(f"Documento '{document_name}' enviado com sucesso!")
else:
print(f"Erro ao enviar o documento {document_name}: {response.text}")
# Adicionar um pequeno atraso para evitar limitação de taxa
time.sleep(0.1)
# 4. Função principal de migração
def migrate_pinecone_to_rememberizer():
cursor = None
total_migrated = 0
print("Iniciando a migração do Pinecone para o Rememberizer...")
while True:
vectors, cursor = fetch_vectors_from_pinecone("your-pinecone-index", BATCH_SIZE, cursor)
if not vectors:
break
print(f"Buscou {len(vectors)} vetores do Pinecone")
upload_to_rememberizer(vectors)
total_migrated += len(vectors)
print(f"Progresso: {total_migrated} vetores migrados")
if not cursor:
break
print(f"Migração completa! {total_migrated} vetores migrados para o Rememberizer")
# Execute a migração
# migrate_pinecone_to_rememberizer()
const { PineconeClient } = require('@pinecone-database/pinecone');
const axios = require('axios');
// Configuração do Pinecone
const pineconeApiKey = 'PINECONE_API_KEY';
const pineconeEnvironment = 'PINECONE_ENVIRONMENT';
const pineconeIndexName = 'YOUR_PINECONE_INDEX';
// Configuração do Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Configuração do tamanho do lote
const BATCH_SIZE = 100;
// Inicializar cliente Pinecone
async function initPinecone() {
const pinecone = new PineconeClient();
await pinecone.init({
apiKey: pineconeApiKey,
environment: pineconeEnvironment,
});
return pinecone;
}
// Buscar vetores do Pinecone
async function fetchVectorsFromPinecone(pinecone, batchSize, paginationToken = null) {
const index = pinecone.Index(pineconeIndexName);
try {
// Para versões mais novas do Pinecone
const listResponse = await index.list({
limit: batchSize,
paginationToken: paginationToken
});
return {
vectors: listResponse.vectors || {},
nextToken: listResponse.paginationToken
};
} catch (error) {
// Fallback para versões mais antigas do Pinecone
// Isso é simplificado; a implementação real depende do seu padrão de acesso a dados
const stats = await index.describeIndexStats();
const dimension = stats.dimension;
const queryResponse = await index.query({
vector: Array(dimension).fill(0),
topK: batchSize,
includeMetadata: true,
includeValues: true
});
const vectors = {};
queryResponse.matches.forEach(match => {
vectors[match.id] = {
id: match.id,
values: match.values,
metadata: match.metadata
};
});
return { vectors, nextToken: null };
}
}
// Fazer upload de vetores para o Rememberizer
async function uploadToRememberizer(vectors) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const [vectorId, vectorData] of Object.entries(vectors)) {
const documentName = vectorData.metadata?.filename || `pinecone_doc_${vectorId}`;
const content = vectorData.metadata?.text || '';
if (!content) {
console.log(`Ignorando ${vectorId} - nenhum conteúdo de texto encontrado nos metadados`);
continue;
}
const data = {
name: documentName,
content: content,
// Opcional: incluir metadados adicionais
metadata: vectorData.metadata || {}
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Documento '${documentName}' enviado com sucesso!`);
results.push({ id: vectorId, success: true });
} else {
console.error(`Erro ao enviar documento ${documentName}: ${response.statusText}`);
results.push({ id: vectorId, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Erro ao enviar documento ${documentName}: ${error.message}`);
results.push({ id: vectorId, success: false, error: error.message });
}
// Adicionar um pequeno atraso para evitar limitação de taxa
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Função principal de migração
async function migratePineconeToRememberizer() {
try {
console.log('Iniciando a migração do Pinecone para o Rememberizer...');
const pinecone = await initPinecone();
let nextToken = null;
let totalMigrated = 0;
do {
const { vectors, nextToken: token } = await fetchVectorsFromPinecone(
pinecone,
BATCH_SIZE,
nextToken
);
nextToken = token;
if (Object.keys(vectors).length === 0) {
break;
}
console.log(`Buscou ${Object.keys(vectors).length} vetores do Pinecone`);
const results = await uploadToRememberizer(vectors);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Progresso: ${totalMigrated} vetores migrados com sucesso`);
} while (nextToken);
console.log(`Migração completa! ${totalMigrated} vetores migrados para o Rememberizer`);
} catch (error) {
console.error('Migração falhou:', error);
}
}
// Executar a migração
// migratePineconeToRememberizer();
Migrando do Qdrant¶
import requests
import json
import time
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
# Configurar cliente Qdrant
QDRANT_URL = "http://localhost:6333" # ou sua URL da nuvem Qdrant
QDRANT_API_KEY = "your_qdrant_api_key" # se estiver usando a nuvem Qdrant
QDRANT_COLLECTION_NAME = "sua_colecao"
qdrant_client = QdrantClient(
url=QDRANT_URL,
api_key=QDRANT_API_KEY # Apenas para a nuvem Qdrant
)
# Configurar cliente do Armazenamento Vetorial Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123" # Seu ID de armazenamento vetorial Rememberizer
BASE_URL = "https://api.rememberizer.ai/api/v1"
# Tamanho do lote para processamento
BATCH_SIZE = 100
# Função para buscar pontos do Qdrant
def fetch_points_from_qdrant(collection_name, batch_size, offset=0):
try:
# Obter informações da coleção para determinar a dimensão do vetor
collection_info = qdrant_client.get_collection(collection_name=collection_name)
# Rolagem através dos pontos
scroll_result = qdrant_client.scroll(
collection_name=collection_name,
limit=batch_size,
offset=offset,
with_payload=True,
with_vectors=True
)
points = scroll_result[0] # Tupla de (pontos, próximo_offset)
next_offset = scroll_result[1]
return points, next_offset
except Exception as e:
print(f"Erro ao buscar pontos do Qdrant: {e}")
return [], None
# Função para enviar vetores para Rememberizer
def upload_to_rememberizer(points):
headers = {
"x-api-key": REMEMBERIZER_API_KEY,
"Content-Type": "application/json"
}
results = []
for point in points:
# Extrair dados do ponto Qdrant
point_id = point.id
metadata = point.payload
text_content = metadata.get("text", "")
document_name = metadata.get("filename", f"qdrant_doc_{point_id}")
if not text_content:
print(f"Pulando {point_id} - nenhum conteúdo de texto encontrado na carga útil")
continue
data = {
"name": document_name,
"content": text_content,
# Opcional: incluir metadados adicionais
"metadata": metadata
}
try:
response = requests.post(
f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
headers=headers,
json=data
)
if response.status_code == 201:
print(f"Documento '{document_name}' enviado com sucesso!")
results.append({"id": point_id, "success": True})
else:
print(f"Erro ao enviar o documento {document_name}: {response.text}")
results.append({"id": point_id, "success": False, "error": response.text})
except Exception as e:
print(f"Exceção ao enviar o documento {document_name}: {str(e)}")
results.append({"id": point_id, "success": False, "error": str(e)})
# Adicionar um pequeno atraso para evitar limitação de taxa
time.sleep(0.1)
return results
# Função principal de migração
def migrate_qdrant_to_rememberizer():
offset = None
total_migrated = 0
print("Iniciando a migração do Qdrant para o Rememberizer...")
while True:
points, next_offset = fetch_points_from_qdrant(
QDRANT_COLLECTION_NAME,
BATCH_SIZE,
offset
)
if not points:
break
print(f"Buscou {len(points)} pontos do Qdrant")
results = upload_to_rememberizer(points)
success_count = sum(1 for r in results if r.get("success", False))
total_migrated += success_count
print(f"Progresso: {total_migrated} pontos migrados com sucesso")
if next_offset is None:
break
offset = next_offset
print(f"Migração completa! {total_migrated} pontos totais migrados para o Rememberizer")
# Execute a migração
# migrate_qdrant_to_rememberizer()
const { QdrantClient } = require('@qdrant/js-client-rest');
const axios = require('axios');
// Configuração do Qdrant
const qdrantUrl = 'http://localhost:6333'; // ou sua URL da nuvem Qdrant
const qdrantApiKey = 'your_qdrant_api_key'; // se estiver usando a nuvem Qdrant
const qdrantCollectionName = 'sua_colecao';
// Configuração do Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Configuração do tamanho do lote
const BATCH_SIZE = 100;
// Inicializa o cliente Qdrant
const qdrantClient = new QdrantClient({
url: qdrantUrl,
apiKey: qdrantApiKey // Apenas para a nuvem Qdrant
});
// Busca pontos do Qdrant
async function fetchPointsFromQdrant(collectionName, batchSize, offset = 0) {
try {
// Obtém informações da coleção
const collectionInfo = await qdrantClient.getCollection(collectionName);
// Rola pelos pontos
const scrollResult = await qdrantClient.scroll(collectionName, {
limit: batchSize,
offset: offset,
with_payload: true,
with_vectors: true
});
return {
points: scrollResult.points,
nextOffset: scrollResult.next_page_offset
};
} catch (error) {
console.error(`Erro ao buscar pontos do Qdrant: ${error.message}`);
return { points: [], nextOffset: null };
}
}
// Envia vetores para o Rememberizer
async function uploadToRememberizer(points) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const point of points) {
// Extrai dados do ponto do Qdrant
const pointId = point.id;
const metadata = point.payload || {};
const textContent = metadata.text || '';
const documentName = metadata.filename || `qdrant_doc_${pointId}`;
if (!textContent) {
console.log(`Ignorando ${pointId} - nenhum conteúdo de texto encontrado na carga útil`);
continue;
}
const data = {
name: documentName,
content: textContent,
// Opcional: incluir metadados adicionais
metadata: metadata
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Documento '${documentName}' enviado com sucesso!`);
results.push({ id: pointId, success: true });
} else {
console.error(`Erro ao enviar documento ${documentName}: ${response.statusText}`);
results.push({ id: pointId, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Erro ao enviar documento ${documentName}: ${error.message}`);
results.push({ id: pointId, success: false, error: error.message });
}
// Adiciona um pequeno atraso para evitar limitação de taxa
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Função principal de migração
async function migrateQdrantToRememberizer() {
try {
console.log('Iniciando migração do Qdrant para o Rememberizer...');
let offset = null;
let totalMigrated = 0;
do {
const { points, nextOffset } = await fetchPointsFromQdrant(
qdrantCollectionName,
BATCH_SIZE,
offset
);
offset = nextOffset;
if (points.length === 0) {
break;
}
console.log(`Buscou ${points.length} pontos do Qdrant`);
const results = await uploadToRememberizer(points);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Progresso: ${totalMigrated} pontos migrados com sucesso`);
} while (offset !== null);
console.log(`Migração completa! ${totalMigrated} pontos totais migrados para o Rememberizer`);
} catch (error) {
console.error('Migração falhou:', error);
}
}
// Executa a migração
// migrateQdrantToRememberizer();
Migrando do Supabase pgvector¶
Se você já está usando o Supabase com pgvector, a migração para o Rememberizer é particularmente simples, uma vez que ambos usam PostgreSQL com a extensão pgvector.
import psycopg2
import requests
import json
import time
import os
from dotenv import load_dotenv
# Carregar variáveis de ambiente
load_dotenv()
# Configuração do PostgreSQL do Supabase
SUPABASE_DB_HOST = os.getenv("SUPABASE_DB_HOST")
SUPABASE_DB_PORT = os.getenv("SUPABASE_DB_PORT", "5432")
SUPABASE_DB_NAME = os.getenv("SUPABASE_DB_NAME")
SUPABASE_DB_USER = os.getenv("SUPABASE_DB_USER")
SUPABASE_DB_PASSWORD = os.getenv("SUPABASE_DB_PASSWORD")
SUPABASE_VECTOR_TABLE = os.getenv("SUPABASE_VECTOR_TABLE", "documents")
# Configuração do Rememberizer
REMEMBERIZER_API_KEY = os.getenv("REMEMBERIZER_API_KEY")
VECTOR_STORE_ID = os.getenv("VECTOR_STORE_ID") # por exemplo, "vs_abc123"
BASE_URL = "https://api.rememberizer.ai/api/v1"
# Tamanho do lote para processamento
BATCH_SIZE = 100
# Conectar ao Supabase PostgreSQL
def connect_to_supabase():
try:
conn = psycopg2.connect(
host=SUPABASE_DB_HOST,
port=SUPABASE_DB_PORT,
dbname=SUPABASE_DB_NAME,
user=SUPABASE_DB_USER,
password=SUPABASE_DB_PASSWORD
)
return conn
except Exception as e:
print(f"Erro ao conectar ao Supabase PostgreSQL: {e}")
return None
# Buscar documentos do Supabase pgvector
def fetch_documents_from_supabase(conn, batch_size, offset=0):
try:
cursor = conn.cursor()
# Ajuste esta consulta com base na estrutura da sua tabela
query = f"""
SELECT id, content, metadata, embedding
FROM {SUPABASE_VECTOR_TABLE}
ORDER BY id
LIMIT %s OFFSET %s
"""
cursor.execute(query, (batch_size, offset))
documents = cursor.fetchall()
cursor.close()
return documents
except Exception as e:
print(f"Erro ao buscar documentos do Supabase: {e}")
return []
# Carregar documentos para o Rememberizer
def upload_to_rememberizer(documents):
headers = {
"x-api-key": REMEMBERIZER_API_KEY,
"Content-Type": "application/json"
}
results = []
for doc in documents:
doc_id, content, metadata, embedding = doc
# Analisar metadados se estiver armazenado como string JSON
if isinstance(metadata, str):
try:
metadata = json.loads(metadata)
except:
metadata = {}
elif metadata is None:
metadata = {}
document_name = metadata.get("filename", f"supabase_doc_{doc_id}")
if not content:
print(f"Pulando {doc_id} - nenhum conteúdo encontrado")
continue
data = {
"name": document_name,
"content": content,
"metadata": metadata
}
try:
response = requests.post(
f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
headers=headers,
json=data
)
if response.status_code == 201:
print(f"Documento '{document_name}' carregado com sucesso!")
results.append({"id": doc_id, "success": True})
else:
print(f"Erro ao carregar o documento {document_name}: {response.text}")
results.append({"id": doc_id, "success": False, "error": response.text})
except Exception as e:
print(f"Exceção ao carregar o documento {document_name}: {str(e)}")
results.append({"id": doc_id, "success": False, "error": str(e)})
# Adicionar um pequeno atraso para evitar limitação de taxa
time.sleep(0.1)
return results
# Função principal de migração
def migrate_supabase_to_rememberizer():
conn = connect_to_supabase()
if not conn:
print("Falha ao conectar ao Supabase. Abortando a migração.")
return
offset = 0
total_migrated = 0
print("Iniciando a migração do pgvector do Supabase para o Rememberizer...")
try:
while True:
documents = fetch_documents_from_supabase(conn, BATCH_SIZE, offset)
if not documents:
break
print(f"Buscou {len(documents)} documentos do Supabase")
results = upload_to_rememberizer(documents)
success_count = sum(1 for r in results if r.get("success", False))
total_migrated += success_count
print(f"Progresso: {total_migrated} documentos migrados com sucesso")
offset += BATCH_SIZE
finally:
conn.close()
print(f"Migração completa! {total_migrated} documentos migrados para o Rememberizer")
# Execute a migração
# migrate_supabase_to_rememberizer()
const { Pool } = require('pg');
const axios = require('axios');
require('dotenv').config();
// Configuração do PostgreSQL do Supabase
const supabasePool = new Pool({
host: process.env.SUPABASE_DB_HOST,
port: process.env.SUPABASE_DB_PORT || 5432,
database: process.env.SUPABASE_DB_NAME,
user: process.env.SUPABASE_DB_USER,
password: process.env.SUPABASE_DB_PASSWORD,
ssl: {
rejectUnauthorized: false
}
});
const supabaseVectorTable = process.env.SUPABASE_VECTOR_TABLE || 'documents';
// Configuração do Rememberizer
const rememberizerApiKey = process.env.REMEMBERIZER_API_KEY;
const vectorStoreId = process.env.VECTOR_STORE_ID; // e.g., "vs_abc123"
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Configuração do tamanho do lote
const BATCH_SIZE = 100;
// Buscar documentos do Supabase pgvector
async function fetchDocumentsFromSupabase(batchSize, offset = 0) {
try {
// Ajuste esta consulta com base na estrutura da sua tabela
const query = `
SELECT id, content, metadata, embedding
FROM ${supabaseVectorTable}
ORDER BY id
LIMIT $1 OFFSET $2
`;
const result = await supabasePool.query(query, [batchSize, offset]);
return result.rows;
} catch (error) {
console.error(`Erro ao buscar documentos do Supabase: ${error.message}`);
return [];
}
}
// Fazer upload de documentos para o Rememberizer
async function uploadToRememberizer(documents) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const doc of documents) {
// Analisar metadata se estiver armazenado como string JSON
let metadata = doc.metadata;
if (typeof metadata === 'string') {
try {
metadata = JSON.parse(metadata);
} catch (e) {
metadata = {};
}
} else if (metadata === null) {
metadata = {};
}
const documentName = metadata.filename || `supabase_doc_${doc.id}`;
if (!doc.content) {
console.log(`Ignorando ${doc.id} - nenhum conteúdo encontrado`);
continue;
}
const data = {
name: documentName,
content: doc.content,
metadata: metadata
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Documento '${documentName}' enviado com sucesso!`);
results.push({ id: doc.id, success: true });
} else {
console.error(`Erro ao enviar documento ${documentName}: ${response.statusText}`);
results.push({ id: doc.id, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Erro ao enviar documento ${documentName}: ${error.message}`);
results.push({ id: doc.id, success: false, error: error.message });
}
// Adicionar um pequeno atraso para evitar limitação de taxa
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Função principal de migração
async function migrateSupabaseToRememberizer() {
try {
console.log('Iniciando a migração do Supabase pgvector para o Rememberizer...');
let offset = 0;
let totalMigrated = 0;
while (true) {
const documents = await fetchDocumentsFromSupabase(BATCH_SIZE, offset);
if (documents.length === 0) {
break;
}
console.log(`Buscou ${documents.length} documentos do Supabase`);
const results = await uploadToRememberizer(documents);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Progresso: ${totalMigrated} documentos migrados com sucesso`);
offset += BATCH_SIZE;
}
console.log(`Migração completa! ${totalMigrated} documentos migrados para o Rememberizer`);
} catch (error) {
console.error('Migração falhou:', error);
} finally {
await supabasePool.end();
}
}
// Executar a migração
// migrateSupabaseToRememberizer();
Melhores Práticas de Migração¶
Siga estas recomendações para uma migração bem-sucedida:
- Planeje com Antecedência:
- Estime o volume de dados e o tempo necessário para a migração
- Programe a migração durante períodos de baixo tráfego
-
Aumente o espaço em disco antes de iniciar grandes migrações
-
Teste Primeiro:
- Crie um vetor de teste no Rememberizer
- Migre um pequeno subconjunto de dados (100-1000 vetores)
-
Verifique a funcionalidade de busca com consultas-chave
-
Validação de Dados:
- Compare a contagem de documentos antes e depois da migração
- Execute consultas de benchmark para garantir resultados semelhantes
-
Valide se os metadados estão corretamente preservados
-
Otimize para Desempenho:
- Use operações em lote para eficiência
- Considere a colocação geográfica dos bancos de dados de origem e destino
-
Monitore os limites de taxa da API e ajuste os tamanhos dos lotes conforme necessário
-
Etapas Pós-Migração:
- Verifique a criação do índice no Rememberizer
- Atualize as configurações do aplicativo para apontar para o novo vetor de armazenamento
- Mantenha o banco de dados de origem como backup até que a migração seja verificada
Para referência detalhada da API e documentação de endpoints, visite a página vector-store.
Certifique-se de manusear as chaves da API de forma segura e siga as melhores práticas para gerenciamento de chaves da API.