Rememberizer Vektorbutik forenkler processen med at håndtere vektordata, så du kan fokusere på tekstinput og udnytte kraften i vektorer til forskellige applikationer såsom søgning og dataanalyse.
Introduktion
Rememberizer Vector Store tilbyder en brugervenlig grænseflade til håndtering af vektordata, mens kompleksiteten ved vektorindlejringer abstraheres. Drevet af PostgreSQL med pgvector-udvidelsen, giver Rememberizer Vector Store dig mulighed for at arbejde direkte med tekst. Tjenesten håndterer opdeling, vektorisering og lagring af tekstdata, hvilket gør det lettere for dig at fokusere på din kerneapplikationslogik.
For en dybere forståelse af de teoretiske koncepter bag vektorindlejringer og vektordatabaser, se .
Teknisk Oversigt
Hvordan Vektorbutikker Fungerer
Rememberizer Vektorbutikker konverterer tekst til højdimensionale vektorrepræsentationer (indlejring), der fanger semantisk betydning. Dette muliggør:
Semantisk Søgning: Find dokumenter baseret på betydning snarere end blot nøgleord
Effektiv Hentning: Hurtigt finde relevant information fra store datasæt
Nøglekomponenter
Dokumentbehandling: Teksten opdeles i optimalt størrelsesdelte bidder med overlappende grænser for at bevare konteksten
Vektorisering: Bidder konverteres til indlejringer ved hjælp af state-of-the-art modeller
Indeksering: Specialiserede algoritmer organiserer vektorer til effektiv lighedssøgning
Forespørgselsbehandling: Søgeforespørgsler vektorisers og sammenlignes med gemte indlejringer
Arkitektur
Rememberizer implementerer vektorbutikker ved hjælp af:
PostgreSQL med pgvector-udvidelse: Til effektiv vektoropbevaring og søgning
Samling-baseret organisering: Hver vektorbutik har sin egen isolerede samling
API-drevet adgang: Enkle RESTful slutpunkter til alle operationer
Kom godt i gang
Oprettelse af en Vektorbutik
Naviger til sektionen for Vektorbutikker i dit dashboard
Klik på "Opret ny Vektorbutik":
En formular vises, der beder dig om at indtaste oplysninger.
Udfyld oplysningerne:
Navn: Angiv et unikt navn til din vektorbutik.
Beskrivelse: Skriv en kort beskrivelse af vektorbutikken.
Indlejringsmodel: Vælg den model, der konverterer tekst til vektorer.
Indekseringsalgoritme: Vælg, hvordan vektorer vil blive organiseret til søgning.
Søgemetrik: Definer, hvordan lighed mellem vektorer beregnes.
Vektordimension: Størrelsen på vektorindlejringerne (typisk 768-1536).
Indsend formularen:
Klik på "Opret" knappen. Du vil modtage en succesmeddelelse, og den nye butik vil vises i din liste over vektorbutikker.
Konfigurationsmuligheder
Indlejringsmodeller
Model
Dimensioner
Beskrivelse
Bedst til
openai/text-embedding-3-large
1536
Højpræcisions indlejringsmodel fra OpenAI
Produktionsapplikationer, der kræver maksimal nøjagtighed
openai/text-embedding-3-small
1536
Mindre, hurtigere indlejringsmodel fra OpenAI
Applikationer med højere gennemstrømningskrav
Indekseringsalgoritmer
Algoritme
Beskrivelse
Afvejninger
IVFFLAT (standard)
Inverteret fil med flad kompression
God balance mellem hastighed og nøjagtighed; fungerer godt for de fleste datasæt
HNSW
Hierarkisk Navigerbar Lille Verden
Bedre nøjagtighed for store datasæt; højere hukommelseskrav
Søgemetrikker
Metode
Beskrivelse
Bedst til
cosine (standard)
Måler vinklen mellem vektorer
Generel formål lighedsmatch
indre produkt (ip)
Punktprodukt mellem vektorer
Når vektormagnituden er vigtig
L2 (Euclidean)
Lige afstand mellem vektorer
Når rumlige forhold betyder noget
Håndtering af Vektorbutikker
Vis og Rediger Vektorbutikker:
Få adgang til administrationsdashboardet for at se, redigere eller slette vektorbutikker.
Visning af Dokumenter:
Gennemse individuelle dokumenter og deres tilknyttede metadata inden for en specifik vektorbutik.
Statistik:
Se detaljerede statistikker såsom antallet af gemte vektorer, forespørgselsydelse og driftsmålinger.
API Nøglehåndtering
API-nøgler bruges til at autentificere og autorisere adgang til Rememberizer Vector Store's API-endepunkter. Korrekt håndtering af API-nøgler er afgørende for at opretholde sikkerheden og integriteten af dine vektorlager.
Oprettelse af API-nøgler
Gå til din Vector Store detaljer side
Naviger til sektionen for API-nøgleadministration:
Den kan findes under fanen "Konfiguration"
Klik på "Tilføj API-nøgle":
En formular vises, der beder dig om at indtaste oplysninger.
Udfyld oplysningerne:
Navn: Angiv et navn til API-nøglen for at hjælpe dig med at identificere dens anvendelsestilfælde.
Indsend formularen:
Klik på "Opret" knappen. Den nye API-nøgle vil blive genereret og vist. Sørg for at kopiere og opbevare den sikkert. Denne nøgle bruges til at godkende anmodninger til den specifikke vector store.
Tilbagetrækning af API-nøgler
Hvis en API-nøgle ikke længere er nødvendig, kan du slette den for at forhindre potentiel misbrug.
Af sikkerhedsmæssige årsager kan du overveje at rotere dine API-nøgler periodisk. Dette indebærer at generere en ny nøgle og tilbagetrække den gamle.
Brug af Vector Store API
Efter at have oprettet en Vector Store og genereret en API-nøgle, kan du interagere med den ved hjælp af REST API'en.
Kodeeksempler
import requests
import json
API_KEY = "your_api_key_here"
VECTOR_STORE_ID = "vs_abc123" # Erstat med dit vector store ID
BASE_URL = "https://api.rememberizer.a
# Upload et dokument til vektorbutikken
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"Dokument '{document_name}' uploadet med succes!")
return response.json()
else:
print(f"Fejl ved upload af dokument: {response.text}")
return None
# Upload tekstindhold til vektorbutikken
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"Tekstdokument '{document_name}' uploadet med succes!")
return response.json()
else:
print(f"Fejl ved upload af tekst: {response.text}")
return None
# Søg i vektorbutikken
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"Fundet {len(results['matched_chunks'])} match for '{query}'")
# Udskriv det bedste resultat
if results['matched_chunks']:
top_match = results['matched_chunks'][0]
print(f"Bedste match (afstand: {top_match['distance']}):")
print(f"Dokument: {top_match['document']['name']}")
print(f"Indhold: {top_match['matched_content']}")
return results
else:
print(f"Fejl ved søgning: {response.text}")
return None
# Eksempel på brug
# upload_document("path/to/document.pdf")
# upload_text("Dette er en prøve tekst, der skal vektorisere", "sample-document.txt")
# search_vector_store("Hvordan fungerer vektorsimilaritet?")
// Vektorbutik API-klient
class VectorStoreClient {
constructor(apiKey, vectorStoreId) {
this.apiKey = apiKey;
this.vectorStoreId = vectorStoreId;
this.baseUrl = 'https://api.rememberizer.ai/api/v1';
}
// Hent information om vektorbutikken
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(`Mislykkedes med at hente information om vektorbutikken: ${response.statusText}`);
}
return response.json();
}
// Upload et tekstdokument
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(`Mislykkedes med at uploade tekstdokument: ${response.statusText}`);
}
return response.json();
}
// Upload en fil
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(`Mislykkedes med at uploade fil: ${xhr.statusText}`));
}
};
xhr.onerror = () => {
reject(new Error('Netværksfejl under filupload'));
};
xhr.send(formData);
});
}
// Søg dokumenter i vektorbutikken
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(`Søgning mislykkedes: ${response.statusText}`);
}
return response.json();
}
// Liste alle dokumenter i vektorbutikken
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(`Mislykkedes med at liste dokumenter: ${response.statusText}`);
}
return response.json();
}
// Slet et dokument
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(`Mislykkedes med at slette dokument: ${response.statusText}`);
}
return true;
}
}
// Eksempel på brug
/*
const client = new VectorStoreClient('your_api_key', 'vs_abc123');
// Søg dokumenter
client.searchDocuments('Hvordan fungerer semantisk søgning?')
.then(results => {
console.log(`Fundet ${results.matched_chunks.length} matches`);
results.matched_chunks.forEach(match => {
console.log(`Dokument: ${match.document.name}`);
console.log(`Score: ${match.distance}`);
console.log(`Indhold: ${match.matched_content}`);
console.log('---');
});
})
.catch(error => console.error(error));
*/
results = client.search('Hvad er de bedste praksisser for datasikkerhed?')
puts "Fundet #{results['matched_chunks'].length} resultater"
Vis top resultat
if results['matched_chunks'].any?
top_match = results['matched_chunks'].first
puts "Top match (afstand: #{top_match['distance']}):"
puts "Dokument: #{top_match['document']['name']}"
puts "Indhold: #{top_match['matched_content']}"
end
=end
</div>
<div data-gb-custom-block data-tag="tab" data-title='cURL'>
```bash
# Indstil din API-nøgle og Vector Store ID
API_KEY="your_api_key_here"
VECTOR_STORE_ID="vs_abc123"
BASE_URL="https://api.rememberizer.ai/api/v1"
# Få vektorlagerinformation
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}" \
-H "x-api-key: ${API_KEY}"
# Upload et tekstdokument
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": "Dette er et eksempel på et dokument, der vil blive vektorisert og gemt i vektordatabasen til semantisk søgning."
}'
# Upload en fil
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
-H "x-api-key: ${API_KEY}" \
-F "file=@/path/to/your/document.pdf"
# Søg efter dokumenter
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}"
# Liste alle dokumenter
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
-H "x-api-key: ${API_KEY}"
# Slet et dokument
curl -X DELETE "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/123" \
-H "x-api-key: ${API_KEY}"
Ydelsesovervejelser
Kommer snart: Vektorbutik Arkitekturdiagram
Dette tekniske arkitekturdiagram vil illustrere:
PostgreSQL + pgvector fundamentarkitektur
Indekseringsalgoritmestrukturer (IVFFLAT vs. HNSW)
Hvordan søgemetrikker fungerer i vektorrum (visuel sammenligning)
Dokumentchunking-proces med overlapvisualisering
Ydelsesovervejelser visualiseret på tværs af forskellige skalaer
Optimering for Forskellige Datavolumener
Datavolumen
Anbefalet Konfiguration
Noter
Lille (<10k dokumenter)
IVFFLAT, cosinuslighed
Enkel konfiguration giver god ydeevne
Medium (10k-100k dokumenter)
IVFFLAT, sørg for regelmæssig reindeksering
Balance mellem søgehastighed og indeksvedligeholdelse
Stor (>100k dokumenter)
HNSW, overvej at øge vektordimensioner
Højere hukommelsesforbrug, men opretholder ydeevne i stor skala
Chunk Størrelse: Rememberizer bruger en standard chunk størrelse på 1024 bytes med en overlapning på 200 bytes
Mindre Chunks (512-1024 bytes): Mere præcise matches, bedre til specifikke spørgsmål
Større Chunks (1500-2048 bytes): Mere kontekst i hvert match, bedre til bredere emner
Overlapning: Sikrer at konteksten ikke går tabt ved chunk-grænser
Forespørgselsoptimering
Kontekstvinduer: Brug prev_chunks og next_chunks til at hente omgivende indhold
Resultatantal: Start med 3-5 resultater (n parameter) og juster baseret på præcisionsbehov
Tærskel: Juster t parameteren for at filtrere resultater efter lighedsscore
Avanceret brug
Reindeksering
Rememberizer udløser automatisk reindeksering, når vektortællinger overstiger foruddefinerede tærskler, men overvej manuel reindeksering efter:
Upload af et stort antal dokumenter
Ændring af indlejringsmodellen
Modifikation af indekseringsalgoritmen
Spørgsmål Forbedring
For bedre søgeresultater:
Vær specifik i søgespørgsmål
Inkluder kontekst når det er muligt
Brug naturligt sprog frem for nøgleord
Justér parametre baseret på resultatkvalitet
Migration fra Andre Vektordatabaser
Hvis du i øjeblikket bruger andre vektordatabase-løsninger og ønsker at migrere til Rememberizer Vector Store, vil de følgende vejledninger hjælpe dig med at overføre dine data effektivt.
Migrering Oversigt
Migrering af vektordata involverer:
Eksportering af data fra din kildevektordatabase
Konvertering af data til et format, der er kompatibelt med Rememberizer
Importering af data til din Rememberizer Vektorbutik
Verificering af, at migreringen var vellykket
Fordele ved at migrere til Rememberizer
PostgreSQL Foundation: Bygget på moden databasteknologi med indbygget backup og gendannelse
Integreret Økosystem: Problemfri forbindelse med andre Rememberizer-komponenter
Forenklet Administration: Unified interface til vektoroperationer
Avanceret Sikkerhed: Sikkerhed på række-niveau og detaljerede adgangskontroller
Skalerbar Arkitektur: Ydelsesoptimering efterhånden som dine data vokser
Migrering fra Pinecone
import os
import pinecone
import requests
import json
import time
# Opsæt Pinecone-klient
pinecone.init(api_key="PINECONE_API_KEY", environment="PINECONE_ENV")
source_index = pinecone.Index("your-pinecone-index")
# Opsæt Rememberizer Vector Store-klient
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123" # Dit Rememberizer vector store ID
BASE_URL = "https://api.rememberizer.ai/api/v1"
# 1. Opsæt batchstørrelse til migration (juster baseret på din datastørrelse)
BATCH_SIZE = 100
# 2. Funktion til at hente vektorer fra Pinecone
def fetch_vectors_from_pinecone(index_name, batch_size, cursor=None):
# Brug listeoperationen, hvis den er tilgængelig i din Pinecone-version
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:
# For ældre Pinecone-versioner uden listeoperation
# Dette er en forenklet tilgang; den faktiske implementering afhænger af dit dataadgangsmønster
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. Funktion til at uploade vektorer til 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():
# Konverter Pinecone vektordata til Rememberizer format
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"Springer {vector_id} over - ingen tekstindhold fundet i metadata")
continue
data = {
"name": document_name,
"content": content,
# Valgfrit: inkluder yderligere metadata
"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"Dokument '{document_name}' uploadet med succes!")
else:
print(f"Fejl ved upload af dokument {document_name}: {response.text}")
# Tilføj en lille forsinkelse for at forhindre rate limiting
time.sleep(0.1)
# 4. Hoved migrationsfunktion
def migrate_pinecone_to_rememberizer():
cursor = None
total_migrated = 0
print("Starter migration fra Pinecone til Rememberizer...")
while True:
vectors, cursor = fetch_vectors_from_pinecone("your-pinecone-index", BATCH_SIZE, cursor)
if not vectors:
break
print(f"Hentet {len(vectors)} vektorer fra Pinecone")
upload_to_rememberizer(vectors)
total_migrated += len(vectors)
print(f"Fremdrift: {total_migrated} vektorer migreret")
if not cursor:
break
print(f"Migrering fuldført! {total_migrated} samlede vektorer migreret til Rememberizer")
# Kør migrationen
# migrate_pinecone_to_rememberizer()
const { PineconeClient } = require('@pinecone-database/pinecone');
const axios = require('axios');
// Pinecone konfiguration
const pineconeApiKey = 'PINECONE_API_KEY';
const pineconeEnvironment = 'PINECONE_ENVIRONMENT';
const pineconeIndexName = 'YOUR_PINECONE_INDEX';
// Rememberizer konfiguration
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Batch størrelse konfiguration
const BATCH_SIZE = 100;
// Initialiser Pinecone klient
async function initPinecone() {
const pinecone = new PineconeClient();
await pinecone.init({
apiKey: pineconeApiKey,
environment: pineconeEnvironment,
});
return pinecone;
}
// Hent vektorer fra Pinecone
async function fetchVectorsFromPinecone(pinecone, batchSize, paginationToken = null) {
const index = pinecone.Index(pineconeIndexName);
try {
// For nyere Pinecone versioner
const listResponse = await index.list({
limit: batchSize,
paginationToken: paginationToken
});
return {
vectors: listResponse.vectors || {},
nextToken: listResponse.paginationToken
};
} catch (error) {
// Fallback for ældre Pinecone versioner
// Dette er forenklet; den faktiske implementering afhænger af dit dataadgangsmønster
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 };
}
}
// Upload vektorer til 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(`Springer over ${vectorId} - ingen tekstindhold fundet i metadata`);
continue;
}
const data = {
name: documentName,
content: content,
// Valgfri: inkluder yderligere metadata
metadata: vectorData.metadata || {}
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Dokument '${documentName}' uploadet med succes!`);
results.push({ id: vectorId, success: true });
} else {
console.error(`Fejl ved upload af dokument ${documentName}: ${response.statusText}`);
results.push({ id: vectorId, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Fejl ved upload af dokument ${documentName}: ${error.message}`);
results.push({ id: vectorId, success: false, error: error.message });
}
// Tilføj en lille forsinkelse for at forhindre rate limiting
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Hoved migrationsfunktion
async function migratePineconeToRememberizer() {
try {
console.log('Starter migration fra Pinecone til 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(`Hentede ${Object.keys(vectors).length} vektorer fra Pinecone`);
const results = await uploadToRememberizer(vectors);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Fremskridt: ${totalMigrated} vektorer migreret med succes`);
} while (nextToken);
console.log(`Migration fuldført! ${totalMigrated} samlede vektorer migreret til Rememberizer`);
} catch (error) {
console.error('Migration mislykkedes:', error);
}
}
// Kør migrationen
// migratePineconeToRememberizer();
Migrering fra Qdrant
import requests
import json
import time
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
# Opsæt Qdrant-klient
QDRANT_URL = "http://localhost:6333" # eller din Qdrant cloud URL
QDRANT_API_KEY = "your_qdrant_api_key" # hvis du bruger Qdrant Cloud
QDRANT_COLLECTION_NAME = "your_collection"
qdrant_client = QdrantClient(
url=QDRANT_URL,
api_key=QDRANT_API_KEY # Kun for Qdrant Cloud
)
# Opsæt Rememberizer Vector Store-klient
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123" # Dit Rememberizer vector store ID
BASE_URL = "https://api.rememberizer.ai/api/v1"
# Batch størrelse til behandling
BATCH_SIZE = 100
# Funktion til at hente punkter fra Qdrant
def fetch_points_from_qdrant(collection_name, batch_size, offset=0):
try:
# Hent kollektionsinfo for at bestemme vektordimension
collection_info = qdrant_client.get_collection(collection_name=collection_name)
# Rul gennem punkter
scroll_result = qdrant_client.scroll(
collection_name=collection_name,
limit=batch_size,
offset=offset,
with_payload=True,
with_vectors=True
)
points = scroll_result[0] # Tuple af (punkter, næste_offset)
next_offset = scroll_result[1]
return points, next_offset
except Exception as e:
print(f"Fejl ved hentning af punkter fra Qdrant: {e}")
return [], None
# Funktion til at uploade vektorer til Rememberizer
def upload_to_rememberizer(points):
headers = {
"x-api-key": REMEMBERIZER_API_KEY,
"Content-Type": "application/json"
}
results = []
for point in points:
# Uddrag data fra Qdrant punkt
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"Springer over {point_id} - ingen tekstindhold fundet i payload")
continue
data = {
"name": document_name,
"content": text_content,
# Valgfrit: inkluder yderligere metadata
"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"Dokument '{document_name}' uploadet med succes!")
results.append({"id": point_id, "success": True})
else:
print(f"Fejl ved upload af dokument {document_name}: {response.text}")
results.append({"id": point_id, "success": False, "error": response.text})
except Exception as e:
print(f"Undtagelse ved upload af dokument {document_name}: {str(e)}")
results.append({"id": point_id, "success": False, "error": str(e)})
# Tilføj en lille forsinkelse for at forhindre rate limiting
time.sleep(0.1)
return results
# Hoved migrationsfunktion
def migrate_qdrant_to_rememberizer():
offset = None
total_migrated = 0
print("Starter migration fra Qdrant til Rememberizer...")
while True:
points, next_offset = fetch_points_from_qdrant(
QDRANT_COLLECTION_NAME,
BATCH_SIZE,
offset
)
if not points:
break
print(f"Hentet {len(points)} punkter fra 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"Fremdrift: {total_migrated} punkter migreret med succes")
if next_offset is None:
break
offset = next_offset
print(f"Migrering fuldført! {total_migrated} samlede punkter migreret til Rememberizer")
# Kør migrationen
# migrate_qdrant_to_rememberizer()
const { QdrantClient } = require('@qdrant/js-client-rest');
const axios = require('axios');
// Qdrant konfiguration
const qdrantUrl = 'http://localhost:6333'; // eller din Qdrant cloud URL
const qdrantApiKey = 'your_qdrant_api_key'; // hvis du bruger Qdrant Cloud
const qdrantCollectionName = 'your_collection';
// Rememberizer konfiguration
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Batch størrelse konfiguration
const BATCH_SIZE = 100;
// Initialiser Qdrant klient
const qdrantClient = new QdrantClient({
url: qdrantUrl,
apiKey: qdrantApiKey // Kun for Qdrant Cloud
});
// Hent punkter fra Qdrant
async function fetchPointsFromQdrant(collectionName, batchSize, offset = 0) {
try {
// Få kollektionsinfo
const collectionInfo = await qdrantClient.getCollection(collectionName);
// Scroll gennem punkter
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(`Fejl ved hentning af punkter fra Qdrant: ${error.message}`);
return { points: [], nextOffset: null };
}
}
// Upload vektorer til Rememberizer
async function uploadToRememberizer(points) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const point of points) {
// Uddrag data fra Qdrant punkt
const pointId = point.id;
const metadata = point.payload || {};
const textContent = metadata.text || '';
const documentName = metadata.filename || `qdrant_doc_${pointId}`;
if (!textContent) {
console.log(`Springer over ${pointId} - ingen tekstindhold fundet i payload`);
continue;
}
const data = {
name: documentName,
content: textContent,
// Valgfrit: inkluder yderligere metadata
metadata: metadata
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Dokument '${documentName}' uploadet med succes!`);
results.push({ id: pointId, success: true });
} else {
console.error(`Fejl ved upload af dokument ${documentName}: ${response.statusText}`);
results.push({ id: pointId, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Fejl ved upload af dokument ${documentName}: ${error.message}`);
results.push({ id: pointId, success: false, error: error.message });
}
// Tilføj en lille forsinkelse for at forhindre rate limiting
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Hoved migrationsfunktion
async function migrateQdrantToRememberizer() {
try {
console.log('Starter migration fra Qdrant til 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(`Hentede ${points.length} punkter fra Qdrant`);
const results = await uploadToRememberizer(points);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Fremdrift: ${totalMigrated} punkter migreret med succes`);
} while (offset !== null);
console.log(`Migration fuldført! ${totalMigrated} samlede punkter migreret til Rememberizer`);
} catch (error) {
console.error('Migration mislykkedes:', error);
}
}
// Kør migrationen
// migrateQdrantToRememberizer();
Migration fra Supabase pgvector
Hvis du allerede bruger Supabase med pgvector, er migrationen til Rememberizer særligt ligetil, da begge bruger PostgreSQL med pgvector-udvidelsen.
import psycopg2
import requests
import json
import time
import os
from dotenv import load_dotenv
# Indlæs miljøvariabler
load_dotenv()
# Supabase PostgreSQL konfiguration
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")
# Rememberizer konfiguration
REMEMBERIZER_API_KEY = os.getenv("REMEMBERIZER_API_KEY")
VECTOR_STORE_ID = os.getenv("VECTOR_STORE_ID") # f.eks. "vs_abc123"
BASE_URL = "https://api.rememberizer.ai/api/v1"
# Batch størrelse til behandling
BATCH_SIZE = 100
# Forbind til 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"Fejl ved forbindelse til Supabase PostgreSQL: {e}")
return None
# Hent dokumenter fra Supabase pgvector
def fetch_documents_from_supabase(conn, batch_size, offset=0):
try:
cursor = conn.cursor()
# Juster denne forespørgsel baseret på din tabelstruktur
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"Fejl ved hentning af dokumenter fra Supabase: {e}")
return []
# Upload dokumenter til Rememberizer
def upload_to_rememberizer(dokumenter):
headers = {
"x-api-key": REMEMBERIZER_API_KEY,
"Content-Type": "application/json"
}
resultater = []
for doc in dokumenter:
doc_id, indhold, metadata, embedding = doc
# Parse metadata hvis det er gemt som JSON-streng
if isinstance(metadata, str):
try:
metadata = json.loads(metadata)
except:
metadata = {}
elif metadata is None:
metadata = {}
dokument_navn = metadata.get("filename", f"supabase_doc_{doc_id}")
if not indhold:
print(f"Springer {doc_id} over - ingen indhold fundet")
continue
data = {
"name": dokument_navn,
"content": indhold,
"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"Dokument '{dokument_navn}' uploadet med succes!")
resultater.append({"id": doc_id, "success": True})
else:
print(f"Fejl ved upload af dokument {dokument_navn}: {response.text}")
resultater.append({"id": doc_id, "success": False, "error": response.text})
except Exception as e:
print(f"Undtagelse ved upload af dokument {dokument_navn}: {str(e)}")
resultater.append({"id": doc_id, "success": False, "error": str(e)})
# Tilføj en lille forsinkelse for at forhindre rate limiting
time.sleep(0.1)
return resultater
# Hoved migrationsfunktion
def migrate_supabase_to_rememberizer():
conn = connect_to_supabase()
if not conn:
print("Mislykkedes at oprette forbindelse til Supabase. Afbryder migration.")
return
offset = 0
total_migrated = 0
print("Starter migration fra Supabase pgvector til Rememberizer...")
try:
while True:
documents = fetch_documents_from_supabase(conn, BATCH_SIZE, offset)
if not documents:
break
print(f"Hentede {len(documents)} dokumenter fra 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"Fremdrift: {total_migrated} dokumenter migreret med succes")
offset += BATCH_SIZE
finally:
conn.close()
print(f"Migrering fuldført! {total_migrated} samlede dokumenter migreret til Rememberizer")
# Kør migrationen
# migrate_supabase_to_rememberizer()
const { Pool } = require('pg');
const axios = require('axios');
require('dotenv').config();
// Supabase PostgreSQL konfiguration
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';
// Rememberizer konfiguration
const rememberizerApiKey = process.env.REMEMBERIZER_API_KEY;
const vectorStoreId = process.env.VECTOR_STORE_ID; // f.eks. "vs_abc123"
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Batch størrelse konfiguration
const BATCH_SIZE = 100;
// Hent dokumenter fra Supabase pgvector
async function fetchDocumentsFromSupabase(batchSize, offset = 0) {
try {
// Juster denne forespørgsel baseret på din tabelstruktur
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(`Fejl ved hentning af dokumenter fra Supabase: ${error.message}`);
return [];
}
}
// Upload dokumenter til Rememberizer
async function uploadToRememberizer(documents) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const doc of documents) {
// Parse metadata hvis det er gemt som JSON-streng
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(`Springer over ${doc.id} - ingen indhold fundet`);
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(`Dokument '${documentName}' uploadet med succes!`);
results.push({ id: doc.id, success: true });
} else {
console.error(`Fejl ved upload af dokument ${documentName}: ${response.statusText}`);
results.push({ id: doc.id, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Fejl ved upload af dokument ${documentName}: ${error.message}`);
results.push({ id: doc.id, success: false, error: error.message });
}
// Tilføj en lille forsinkelse for at forhindre rate limiting
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Hoved migrationsfunktion
async function migrateSupabaseToRememberizer() {
try {
console.log('Starter migration fra Supabase pgvector til Rememberizer...');
let offset = 0;
let totalMigrated = 0;
while (true) {
const documents = await fetchDocumentsFromSupabase(BATCH_SIZE, offset);
if (documents.length === 0) {
break;
}
console.log(`Hentede ${documents.length} dokumenter fra Supabase`);
const results = await uploadToRememberizer(documents);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Fremdrift: ${totalMigrated} dokumenter migreret med succes`);
offset += BATCH_SIZE;
}
console.log(`Migration fuldført! ${totalMigrated} samlede dokumenter migreret til Rememberizer`);
} catch (error) {
console.error('Migration mislykkedes:', error);
} finally {
await supabasePool.end();
}
}
// Kør migrationen
// migrateSupabaseToRememberizer();
Migrerings bedste praksis
Følg disse anbefalinger for en vellykket migrering:
Planlæg på forhånd:
Estimér datamængden og den tid, der kræves til migrering
Planlæg migrering i perioder med lav trafik
Øg diskpladsen før du starter store migreringer
Test først:
Opret et testvektorlager i Rememberizer
Migrer et lille udsnit af data (100-1000 vektorer)
Bekræft søgefunktionaliteten med nøglespørgsmål
Datavalidering:
Sammenlign dokumenttællinger før og efter migrering
Kør benchmark-spørgsmål for at sikre lignende resultater
Valider at metadata er korrekt bevaret
Optimer for ydeevne:
Brug batchoperationer for effektivitet
Overvej geografisk kolokation af kilde- og mål-databaser
Overvåg API-hastighedsgrænser og juster batchstørrelserne derefter
Post-migrerings trin:
Bekræft indeksoprettelse i Rememberizer
Opdater applikationskonfigurationer til at pege på det nye vektorlager
Behold kilde-databasen som backup, indtil migreringen er bekræftet