Le Magasin de Vecteurs Rememberizer simplifie le processus de gestion des données vectorielles, vous permettant de vous concentrer sur l'entrée de texte et de tirer parti de la puissance des vecteurs pour diverses applications telles que la recherche et l'analyse de données.
Introduction
Le magasin de vecteurs Rememberizer fournit une interface facile à utiliser pour gérer les données vectorielles tout en abstraisant la complexité des embeddings vectoriels. Alimenté par PostgreSQL avec l'extension pgvector, le magasin de vecteurs Rememberizer vous permet de travailler directement avec du texte. Le service gère le découpage, la vectorisation et le stockage des données textuelles, vous permettant de vous concentrer sur la logique principale de votre application.
Pour une compréhension plus approfondie des concepts théoriques derrière les embeddings vectoriels et les bases de données vectorielles, consultez .
Vue d'ensemble technique
Comment fonctionnent les magasins de vecteurs
Les magasins de vecteurs Rememberizer convertissent le texte en représentations vectorielles de haute dimension (embeddings) qui capturent le sens sémantique. Cela permet :
Recherche sémantique : Trouver des documents en fonction du sens plutôt que des mots-clés
Correspondance de similarité : Identifier du contenu conceptuellement lié
Récupération efficace : Localiser rapidement des informations pertinentes à partir de grands ensembles de données
Composants Clés
Traitement de Document : Le texte est divisé en morceaux de taille optimale avec des frontières qui se chevauchent pour préserver le contexte
Vectorisation : Les morceaux sont convertis en embeddings à l'aide de modèles à la pointe de la technologie
Indexation : Des algorithmes spécialisés organisent les vecteurs pour une recherche de similarité efficace
Traitement de Requête : Les requêtes de recherche sont vectorisées et comparées aux embeddings stockés
Architecture
Rememberizer implémente des magasins de vecteurs en utilisant :
PostgreSQL avec l'extension pgvector : Pour un stockage et une recherche de vecteurs efficaces
Organisation basée sur des collections : Chaque magasin de vecteurs a sa propre collection isolée
Accès piloté par API : Points de terminaison RESTful simples pour toutes les opérations
Commencer
Création d'un Magasin de Vecteurs
Accédez à la section Magasins de Vecteurs dans votre tableau de bord
Cliquez sur "Créer un nouveau Magasin de Vecteurs" :
Un formulaire apparaîtra vous demandant d'entrer des détails.
Remplissez les Détails :
Nom : Fournissez un nom unique pour votre magasin de vecteurs.
Description : Écrivez une brève description du magasin de vecteurs.
Modèle d'Incorporation : Sélectionnez le modèle qui convertit le texte en vecteurs.
Algorithme d'Indexation : Choisissez comment les vecteurs seront organisés pour la recherche.
Métrique de Recherche : Définissez comment la similarité entre les vecteurs est calculée.
Dimension du Vecteur : La taille des incorporations de vecteurs (généralement 768-1536).
Soumettez le Formulaire :
Cliquez sur le bouton "Créer". Vous recevrez une notification de succès, et le nouveau magasin apparaîtra dans votre liste de magasins de vecteurs.
Options de configuration
Modèles d'Intégration
Modèle
Dimensions
Description
Meilleur Pour
openai/text-embedding-3-large
1536
Modèle d'intégration à haute précision d'OpenAI
Applications de production nécessitant une précision maximale
openai/text-embedding-3-small
1536
Modèle d'intégration plus petit et plus rapide d'OpenAI
Applications avec des exigences de débit plus élevées
Algorithmes d'indexation
Algorithme
Description
Compromis
IVFFLAT (par défaut)
Fichier inversé avec compression plate
Bon équilibre entre vitesse et précision ; fonctionne bien pour la plupart des ensembles de données
HNSW
Petit monde navigable hiérarchique
Meilleure précision pour les grands ensembles de données ; exigences de mémoire plus élevées
Métriques de recherche
Métrique
Description
Meilleur pour
cosinus (par défaut)
Mesure l'angle entre les vecteurs
Correspondance de similarité à usage général
produit scalaire (ip)
Produit scalaire entre les vecteurs
Lorsque la magnitude du vecteur est importante
L2 (Euclidien)
Distance en ligne droite entre les vecteurs
Lorsque les relations spatiales sont importantes
Gestion des Magasins de Vecteurs
Voir et Éditer les Magasins de Vecteurs :
Accédez au tableau de bord de gestion pour voir, éditer ou supprimer des magasins de vecteurs.
Visualisation des Documents :
Parcourez les documents individuels et leurs métadonnées associées au sein d'un magasin de vecteurs spécifique.
Statistiques :
Consultez des statistiques détaillées telles que le nombre de vecteurs stockés, les performances des requêtes et les métriques opérationnelles.
Gestion des clés API
Les clés API sont utilisées pour authentifier et autoriser l'accès aux points de terminaison de l'API du magasin de vecteurs Rememberizer. Une gestion appropriée des clés API est essentielle pour maintenir la sécurité et l'intégrité de vos magasins de vecteurs.
Création de Clés API
Rendez-vous sur la page de détails de votre Vector Store
Naviguez vers la section de Gestion des Clés API :
Elle se trouve dans l'onglet "Configuration"
Cliquez sur "Ajouter une Clé API" :
Un formulaire apparaîtra vous demandant d'entrer des détails.
Remplissez les Détails :
Nom : Fournissez un nom pour la clé API afin de vous aider à identifier son cas d'utilisation.
Soumettez le Formulaire :
Cliquez sur le bouton "Créer". La nouvelle clé API sera générée et affichée. Assurez-vous de la copier et de la stocker en toute sécurité. Cette clé est utilisée pour authentifier les demandes à ce vector store spécifique.
Révocation des clés API
Si une clé API n'est plus nécessaire, vous pouvez la supprimer pour éviter tout usage abusif potentiel.
Pour des raisons de sécurité, vous voudrez peut-être faire tourner vos clés API périodiquement. Cela implique de générer une nouvelle clé et de révoquer l'ancienne.
Utilisation de l'API Vector Store
Après avoir créé un Vector Store et généré une clé API, vous pouvez interagir avec lui en utilisant l'API REST.
Exemples de Code
import requests
import json
API_KEY = "your_api_key_here"
VECTOR_STORE_ID = "vs_abc123" # Remplacez par l'ID de votre magasin de vecteurs
BASE_URL = "https://api.rememberizer.ai/api/v1"
Télécharger un document dans le magasin de vecteurs
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"Document '{document_name}' téléchargé avec succès !")
return response.json()
else:
print(f"Erreur lors du téléchargement du document : {response.text}")
return None
Télécharger le contenu textuel vers le magasin de vecteurs
results = client.search('Quelles sont les meilleures pratiques en matière de sécurité des données ?')
puts "Trouvé #{results['matched_chunks'].length} résultats"
Afficher le meilleur résultat
if results['matched_chunks'].any?
top_match = results['matched_chunks'].first
puts "Meilleur match (distance : #{top_match['distance']}):"
puts "Document : #{top_match['document']['name']}"
puts "Contenu : #{top_match['matched_content']}"
end
=end
</div>
<div data-gb-custom-block data-tag="tab" data-title='cURL'>
```bash
# Définissez votre clé API et l'ID du magasin de vecteurs
API_KEY="your_api_key_here"
VECTOR_STORE_ID="vs_abc123"
BASE_URL="https://api.rememberizer.ai/api/v1"
# Obtenir des informations sur le magasin de vecteurs
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}" \
-H "x-api-key: ${API_KEY}"
# Télécharger un document texte
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": "Ceci est un document d'exemple qui sera vectorisé et stocké dans la base de données vectorielle pour la recherche sémantique."
}'
# Télécharger un fichier
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
-H "x-api-key: ${API_KEY}" \
-F "file=@/path/to/your/document.pdf"
# Rechercher des documents
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}"
# Lister tous les documents
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
-H "x-api-key: ${API_KEY}"
# Supprimer un document
curl -X DELETE "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/123" \
-H "x-api-key: ${API_KEY}"
Considérations de Performance
À venir : Diagramme d'Architecture du Vector Store
Ce diagramme d'architecture technique illustrera :
L'architecture de base PostgreSQL + pgvector
Structures des algorithmes d'indexation (IVFFLAT vs. HNSW)
Comment fonctionnent les métriques de recherche dans l'espace vectoriel (comparaison visuelle)
Processus de découpage de documents avec visualisation de chevauchement
Considérations de performance visualisées à différentes échelles
Optimisation pour Différents Volumes de Données
Volume de Données
Configuration Recommandée
Remarques
Petit (<10k documents)
IVFFLAT, similarité cosinus
Configuration simple offrant de bonnes performances
Moyen (10k-100k documents)
IVFFLAT, assurer un réindexage régulier
Équilibre entre la vitesse de recherche et la maintenance de l'index
Grand (>100k documents)
HNSW, envisager d'augmenter les dimensions des vecteurs
Utilisation de mémoire plus élevée mais maintient les performances à grande échelle
Stratégies de découpage
Le processus de découpage impacte significativement la qualité de recherche :
Taille de Chunk : Rememberizer utilise une taille de chunk par défaut de 1024 octets avec un chevauchement de 200 octets
Chunks Plus Petits (512-1024 octets) : Correspondances plus précises, mieux pour des questions spécifiques
Chunks Plus Grands (1500-2048 octets) : Plus de contexte dans chaque correspondance, mieux pour des sujets plus larges
Chevauchement : Assure que le contexte n'est pas perdu aux limites des chunks
Optimisation des Requêtes
Fenêtres de Contexte : Utilisez prev_chunks et next_chunks pour récupérer le contenu environnant
Nombre de Résultats : Commencez avec 3-5 résultats (paramètre n) et ajustez en fonction des besoins de précision
Seuil : Ajustez le paramètre t pour filtrer les résultats par score de similarité
Utilisation Avancée
Réindexation
Rememberizer déclenche automatiquement la réindexation lorsque le nombre de vecteurs dépasse des seuils prédéfinis, mais envisagez une réindexation manuelle après :
Avoir téléchargé un grand nombre de documents
Avoir changé le modèle d'incorporation
Avoir modifié l'algorithme d'indexation
Amélioration des requêtes
Pour de meilleurs résultats de recherche :
Soyez spécifique dans les requêtes de recherche
Incluez le contexte lorsque c'est possible
Utilisez un langage naturel plutôt que des mots-clés
Ajustez les paramètres en fonction de la qualité des résultats
Migration depuis d'autres bases de données vectorielles
Si vous utilisez actuellement d'autres solutions de bases de données vectorielles et souhaitez migrer vers Rememberizer Vector Store, les guides suivants vous aideront à transférer vos données efficacement.
Vue d'ensemble de la migration
La migration des données vectorielles implique :
L'exportation des données de votre base de données vectorielle source
La conversion des données dans un format compatible avec Rememberizer
L'importation des données dans votre magasin de vecteurs Rememberizer
La vérification que la migration a réussi
Avantages de la migration vers Rememberizer
Fondation PostgreSQL : Construit sur une technologie de base de données mature avec sauvegarde et récupération intégrées
Écosystème intégré : Connexion transparente avec d'autres composants de Rememberizer
Gestion simplifiée : Interface unifiée pour les opérations vectorielles
Sécurité avancée : Sécurité au niveau des lignes et contrôles d'accès granulaires
Architecture évolutive : Optimisation des performances à mesure que vos données croissent
Migration de Pinecone
import os
import pinecone
import requests
import json
import time
# Configurer le client Pinecone
pinecone.init(api_key="PINECONE_API_KEY", environment="PINECONE_ENV")
source_index = pinecone.Index("your-pinecone-index")
# Configurer le client de la boutique de vecteurs Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123" # Votre ID de boutique de vecteurs Rememberizer
BASE_URL = "https://api.rememberizer.ai/api/v1"
# 1. Configurer la taille du lot pour la migration (ajuster en fonction de la taille de vos données)
BATCH_SIZE = 100
# 2. Fonction pour obtenir des vecteurs de Pinecone
def fetch_vectors_from_pinecone(index_name, batch_size, cursor=None):
# Utilisez l'opération de liste si disponible dans votre version de 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:
# Pour les anciennes versions de Pinecone sans opération de liste
# Il s'agit d'une approche simplifiée ; l'implémentation réelle dépend de votre modèle d'accès aux données
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. Fonction pour télécharger des vecteurs vers 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():
# Convertir les données de vecteur Pinecone au format 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"Passage de {vector_id} - aucun contenu textuel trouvé dans les métadonnées")
continue
data = {
"name": document_name,
"content": content,
# Optionnel : inclure des métadonnées supplémentaires
"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"Document '{document_name}' téléchargé avec succès !")
else:
print(f"Erreur lors du téléchargement du document {document_name} : {response.text}")
# Ajouter un petit délai pour éviter la limitation de débit
time.sleep(0.1)
# 4. Fonction principale de migration
def migrate_pinecone_to_rememberizer():
cursor = None
total_migrated = 0
print("Démarrage de la migration de Pinecone vers Rememberizer...")
while True:
vectors, cursor = fetch_vectors_from_pinecone("your-pinecone-index", BATCH_SIZE, cursor)
if not vectors:
break
print(f"Récupéré {len(vectors)} vecteurs de Pinecone")
upload_to_rememberizer(vectors)
total_migrated += len(vectors)
print(f"Progression : {total_migrated} vecteurs migrés")
if not cursor:
break
print(f"Migration terminée ! {total_migrated} vecteurs au total migrés vers Rememberizer")
# Exécutez la migration
# migrer_pinecone_vers_rememberizer()
const { PineconeClient } = require('@pinecone-database/pinecone');
const axios = require('axios');
// Configuration de Pinecone
const pineconeApiKey = 'PINECONE_API_KEY';
const pineconeEnvironment = 'PINECONE_ENVIRONMENT';
const pineconeIndexName = 'YOUR_PINECONE_INDEX';
// Configuration de Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Configuration de la taille du lot
const BATCH_SIZE = 100;
// Initialiser le client Pinecone
async function initPinecone() {
const pinecone = new PineconeClient();
await pinecone.init({
apiKey: pineconeApiKey,
environment: pineconeEnvironment,
});
return pinecone;
}
// Récupérer les vecteurs depuis Pinecone
async function fetchVectorsFromPinecone(pinecone, batchSize, paginationToken = null) {
const index = pinecone.Index(pineconeIndexName);
try {
// Pour les versions plus récentes de Pinecone
const listResponse = await index.list({
limit: batchSize,
paginationToken: paginationToken
});
return {
vectors: listResponse.vectors || {},
nextToken: listResponse.paginationToken
};
} catch (error) {
// Solution de secours pour les versions plus anciennes de Pinecone
// Ceci est simplifié ; l'implémentation réelle dépend de votre modèle d'accès aux données
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 };
}
}
// Télécharger les vecteurs vers 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(`Ignorer ${vectorId} - aucun contenu textuel trouvé dans les métadonnées`);
continue;
}
const data = {
name: documentName,
content: content,
// Optionnel : inclure des métadonnées supplémentaires
metadata: vectorData.metadata || {}
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Document '${documentName}' téléchargé avec succès !`);
results.push({ id: vectorId, success: true });
} else {
console.error(`Erreur lors du téléchargement du document ${documentName} : ${response.statusText}`);
results.push({ id: vectorId, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Erreur lors du téléchargement du document ${documentName} : ${error.message}`);
results.push({ id: vectorId, success: false, error: error.message });
}
// Ajouter un petit délai pour éviter la limitation de débit
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Fonction principale de migration
async function migratePineconeToRememberizer() {
try {
console.log('Démarrage de la migration de Pinecone vers 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(`Récupéré ${Object.keys(vectors).length} vecteurs depuis Pinecone`);
const results = await uploadToRememberizer(vectors);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Progression : ${totalMigrated} vecteurs migrés avec succès`);
} while (nextToken);
console.log(`Migration terminée ! ${totalMigrated} vecteurs au total migrés vers Rememberizer`);
} catch (error) {
console.error('Échec de la migration :', error);
}
}
// Exécuter la migration
// migratePineconeToRememberizer();
Migration de Qdrant
import requests
import json
import time
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest
# Configurer le client Qdrant
QDRANT_URL = "http://localhost:6333" # ou votre URL Qdrant cloud
QDRANT_API_KEY = "your_qdrant_api_key" # si vous utilisez Qdrant Cloud
QDRANT_COLLECTION_NAME = "your_collection"
qdrant_client = QdrantClient(
url=QDRANT_URL,
api_key=QDRANT_API_KEY # Seulement pour Qdrant Cloud
)
# Configurer le client de la boutique de vecteurs Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123" # Votre ID de boutique de vecteurs Rememberizer
BASE_URL = "https://api.rememberizer.ai/api/v1"
# Taille du lot pour le traitement
BATCH_SIZE = 100
# Fonction pour récupérer des points depuis Qdrant
def fetch_points_from_qdrant(collection_name, batch_size, offset=0):
try:
# Obtenir des informations sur la collection pour déterminer la dimension du vecteur
collection_info = qdrant_client.get_collection(collection_name=collection_name)
# Faire défiler les points
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 de (points, next_offset)
next_offset = scroll_result[1]
return points, next_offset
except Exception as e:
print(f"Erreur lors de la récupération des points depuis Qdrant : {e}")
return [], None
# Fonction pour télécharger des vecteurs vers Rememberizer
def upload_to_rememberizer(points):
headers = {
"x-api-key": REMEMBERIZER_API_KEY,
"Content-Type": "application/json"
}
results = []
for point in points:
# Extraire les données du point 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"Saut de {point_id} - aucun contenu textuel trouvé dans la charge utile")
continue
data = {
"name": document_name,
"content": text_content,
# Optionnel : inclure des métadonnées supplémentaires
"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"Document '{document_name}' téléchargé avec succès !")
results.append({"id": point_id, "success": True})
else:
print(f"Erreur lors du téléchargement du document {document_name} : {response.text}")
results.append({"id": point_id, "success": False, "error": response.text})
except Exception as e:
print(f"Exception lors du téléchargement du document {document_name} : {str(e)}")
results.append({"id": point_id, "success": False, "error": str(e)})
# Ajouter un petit délai pour éviter la limitation de débit
time.sleep(0.1)
return results
# Fonction principale de migration
def migrate_qdrant_to_rememberizer():
offset = None
total_migrated = 0
print("Démarrage de la migration de Qdrant vers Rememberizer...")
while True:
points, next_offset = fetch_points_from_qdrant(
QDRANT_COLLECTION_NAME,
BATCH_SIZE,
offset
)
if not points:
break
print(f"Récupéré {len(points)} points de 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"Progression : {total_migrated} points migrés avec succès")
if next_offset is None:
break
offset = next_offset
print(f"Migrazione terminée ! {total_migrated} points au total migrés vers Rememberizer")
# Exécutez la migration
# migrate_qdrant_to_rememberizer()
const { QdrantClient } = require('@qdrant/js-client-rest');
const axios = require('axios');
// Configuration de Qdrant
const qdrantUrl = 'http://localhost:6333'; // ou votre URL cloud Qdrant
const qdrantApiKey = 'your_qdrant_api_key'; // si vous utilisez Qdrant Cloud
const qdrantCollectionName = 'your_collection';
// Configuration de Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';
// Configuration de la taille du lot
const BATCH_SIZE = 100;
// Initialiser le client Qdrant
const qdrantClient = new QdrantClient({
url: qdrantUrl,
apiKey: qdrantApiKey // Seulement pour Qdrant Cloud
});
// Récupérer des points depuis Qdrant
async function fetchPointsFromQdrant(collectionName, batchSize, offset = 0) {
try {
// Obtenir les informations de la collection
const collectionInfo = await qdrantClient.getCollection(collectionName);
// Faire défiler les points
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(`Erreur lors de la récupération des points depuis Qdrant : ${error.message}`);
return { points: [], nextOffset: null };
}
}
// Télécharger des vecteurs vers Rememberizer
async function uploadToRememberizer(points) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const point of points) {
// Extraire les données du point Qdrant
const pointId = point.id;
const metadata = point.payload || {};
const textContent = metadata.text || '';
const documentName = metadata.filename || `qdrant_doc_${pointId}`;
if (!textContent) {
console.log(`Ignorer ${pointId} - aucun contenu texte trouvé dans la charge utile`);
continue;
}
const data = {
name: documentName,
content: textContent,
// Optionnel : inclure des métadonnées supplémentaires
metadata: metadata
};
try {
const response = await axios.post(
`${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
data,
{ headers }
);
if (response.status === 201) {
console.log(`Document '${documentName}' téléchargé avec succès !`);
results.push({ id: pointId, success: true });
} else {
console.error(`Erreur lors du téléchargement du document ${documentName} : ${response.statusText}`);
results.push({ id: pointId, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Erreur lors du téléchargement du document ${documentName} : ${error.message}`);
results.push({ id: pointId, success: false, error: error.message });
}
// Ajouter un petit délai pour éviter la limitation de débit
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Fonction principale de migration
async function migrateQdrantToRememberizer() {
try {
console.log('Démarrage de la migration de Qdrant vers 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(`Récupéré ${points.length} points depuis Qdrant`);
const results = await uploadToRememberizer(points);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Progression : ${totalMigrated} points migrés avec succès`);
} while (offset !== null);
console.log(`Migration terminée ! ${totalMigrated} points au total migrés vers Rememberizer`);
} catch (error) {
console.error('Échec de la migration :', error);
}
}
// Exécuter la migration
// migrateQdrantToRememberizer();
Migration de Supabase pgvector
Si vous utilisez déjà Supabase avec pgvector, la migration vers Rememberizer est particulièrement simple puisque les deux utilisent PostgreSQL avec l'extension pgvector.
import psycopg2
import requests
import json
import time
import os
from dotenv import load_dotenv
# Charger les variables d'environnement
load_dotenv()
# Configuration PostgreSQL de 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")
# Configuration de Rememberizer
REMEMBERIZER_API_KEY = os.getenv("REMEMBERIZER_API_KEY")
VECTOR_STORE_ID = os.getenv("VECTOR_STORE_ID") # par exemple, "vs_abc123"
BASE_URL = "https://api.rememberizer.ai/api/v1"
# Taille du lot pour le traitement
BATCH_SIZE = 100
# Se connecter à 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"Erreur de connexion à Supabase PostgreSQL : {e}")
return None
# Récupérer des documents depuis Supabase pgvector
def fetch_documents_from_supabase(conn, batch_size, offset=0):
try:
cursor = conn.cursor()
# Ajustez cette requête en fonction de la structure de votre table
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"Erreur lors de la récupération des documents depuis Supabase : {e}")
return []
# Télécharger des documents sur 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
# Analyser les métadonnées si elles sont stockées sous forme de chaîne 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"Passer {doc_id} - aucun contenu trouvé")
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"Document '{document_name}' téléchargé avec succès !")
results.append({"id": doc_id, "success": True})
else:
print(f"Erreur lors du téléchargement du document {document_name} : {response.text}")
results.append({"id": doc_id, "success": False, "error": response.text})
except Exception as e:
print(f"Exception lors du téléchargement du document {document_name} : {str(e)}")
results.append({"id": doc_id, "success": False, "error": str(e)})
# Ajouter un petit délai pour éviter la limitation de débit
time.sleep(0.1)
return results
# Fonction principale de migration
def migrate_supabase_to_rememberizer():
conn = connect_to_supabase()
if not conn:
print("Échec de la connexion à Supabase. Abandon de la migration.")
return
offset = 0
total_migrated = 0
print("Démarrage de la migration de Supabase pgvector vers Rememberizer...")
try:
while True:
documents = fetch_documents_from_supabase(conn, BATCH_SIZE, offset)
if not documents:
break
print(f"Récupéré {len(documents)} documents de 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"Progression : {total_migrated} documents migrés avec succès")
offset += BATCH_SIZE
finally:
conn.close()
print(f"Migration terminée ! {total_migrated} documents au total migrés vers Rememberizer")
# Exécutez la migration
# migrate_supabase_to_rememberizer()
const { Pool } = require('pg');
const axios = require('axios');
require('dotenv').config();
// Configuration PostgreSQL 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';
// Configuration 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';
// Configuration de la taille du lot
const BATCH_SIZE = 100;
// Récupérer des documents depuis Supabase pgvector
async function fetchDocumentsFromSupabase(batchSize, offset = 0) {
try {
// Ajustez cette requête en fonction de la structure de votre table
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(`Erreur lors de la récupération des documents depuis Supabase : ${error.message}`);
return [];
}
}
// Télécharger des documents vers Rememberizer
async function uploadToRememberizer(documents) {
const headers = {
'x-api-key': rememberizerApiKey,
'Content-Type': 'application/json'
};
const results = [];
for (const doc of documents) {
// Analyser les métadonnées si elles sont stockées sous forme de chaîne 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(`Ignorer ${doc.id} - aucun contenu trouvé`);
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(`Document '${documentName}' téléchargé avec succès !`);
results.push({ id: doc.id, success: true });
} else {
console.error(`Erreur lors du téléchargement du document ${documentName} : ${response.statusText}`);
results.push({ id: doc.id, success: false, error: response.statusText });
}
} catch (error) {
console.error(`Erreur lors du téléchargement du document ${documentName} : ${error.message}`);
results.push({ id: doc.id, success: false, error: error.message });
}
// Ajouter un petit délai pour éviter la limitation de débit
await new Promise(resolve => setTimeout(resolve, 100));
}
return results;
}
// Fonction principale de migration
async function migrateSupabaseToRememberizer() {
try {
console.log('Démarrage de la migration de Supabase pgvector vers Rememberizer...');
let offset = 0;
let totalMigrated = 0;
while (true) {
const documents = await fetchDocumentsFromSupabase(BATCH_SIZE, offset);
if (documents.length === 0) {
break;
}
console.log(`Récupéré ${documents.length} documents depuis Supabase`);
const results = await uploadToRememberizer(documents);
const successCount = results.filter(r => r.success).length;
totalMigrated += successCount;
console.log(`Progression : ${totalMigrated} documents migrés avec succès`);
offset += BATCH_SIZE;
}
console.log(`Migration terminée ! ${totalMigrated} documents au total migrés vers Rememberizer`);
} catch (error) {
console.error('La migration a échoué :', error);
} finally {
await supabasePool.end();
}
}
// Exécuter la migration
// migrateSupabaseToRememberizer();
Meilleures Pratiques de Migration
Suivez ces recommandations pour une migration réussie :
Planifiez à l'avance :
Estimez le volume de données et le temps requis pour la migration
Planifiez la migration pendant les périodes de faible trafic
Augmentez l'espace disque avant de commencer de grandes migrations
Testez d'abord :
Créez un magasin de vecteurs de test dans Rememberizer
Migrez un petit sous-ensemble de données (100-1000 vecteurs)
Vérifiez la fonctionnalité de recherche avec des requêtes clés
Validation des Données :
Comparez les comptes de documents avant et après la migration
Exécutez des requêtes de référence pour garantir des résultats similaires
Validez que les métadonnées sont correctement préservées
Optimisez pour la Performance :
Utilisez des opérations par lots pour plus d'efficacité
Envisagez la colocation géographique des bases de données source et cible
Surveillez les limites de taux d'API et ajustez les tailles de lot en conséquence
Étapes Post-Migration :
Vérifiez la création de l'index dans Rememberizer
Mettez à jour les configurations de l'application pour pointer vers le nouveau magasin de vecteurs
Gardez la base de données source en tant que sauvegarde jusqu'à ce que la migration soit vérifiée