Magasins de Vecteurs¶
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 Qu'est-ce que les embeddings vectoriels et les bases de données vectorielles ?.
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.

Créer un Nouveau Magasin 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.

Voir les Détails d'un Magasin de Vecteurs
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.

Créer une Nouvelle Clé API
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¶
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¶
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"Document texte '{document_name}' téléchargé avec succès !")
return response.json()
else:
print(f"Erreur lors du téléchargement du texte : {response.text}")
return None
Rechercher dans le magasin de vecteurs¶
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"Trouvé {len(results['matched_chunks'])} correspondances pour '{query}'")
# Imprimer le meilleur résultat
if results['matched_chunks']:
top_match = results['matched_chunks'][0]
print(f"Meilleure correspondance (distance : {top_match['distance']}):")
print(f"Document : {top_match['document']['name']}")
print(f"Contenu : {top_match['matched_content']}")
return results
else:
print(f"Erreur lors de la recherche : {response.text}")
return None
Exemple d'utilisation¶
télécharger_document("path/to/document.pdf")¶
upload_text("Ceci est un texte d'exemple à vectoriser", "sample-document.txt")¶
search_vector_store("Comment fonctionne la similarité vectorielle ?")¶
```
```javascript // Client API de Vector Store class VectorStoreClient { constructor(apiKey, vectorStoreId) { this.apiKey = apiKey; this.vectorStoreId = vectorStoreId; this.baseUrl = 'https://api.rememberizer.ai/api/v1'; }
// Obtenir des informations sur le magasin de vecteurs
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(`Échec de l'obtention des informations sur le magasin de vecteurs : ${response.statusText}`);
}
return response.json();
}
// Télécharger un document texte
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(`Échec du téléchargement du document texte : ${response.statusText}`);
}
return response.json();
}
// Télécharger un fichier 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(`Échec du téléchargement du fichier : ${xhr.statusText}`));
}
};
xhr.onerror = () => {
reject(new Error('Erreur réseau lors du téléchargement du fichier'));
};
xhr.send(formData);
});
}
// Rechercher des documents dans le magasin de vecteurs 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(`Échec de la recherche : ${response.statusText}`);
}
return response.json();
}
// Lister tous les documents dans le magasin de vecteurs
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(`Échec de la liste des documents : ${response.statusText}`);
}
return response.json();
}
// Supprimer un document
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(`Échec de la suppression du document : ${response.statusText}`);
}
return true;
} }
// Exemple d'utilisation /* const client = new VectorStoreClient('your_api_key', 'vs_abc123');
// Rechercher des documents
client.searchDocuments('Comment fonctionne la recherche sémantique ?')
.then(results => {
console.log(Trouvé ${results.matched_chunks.length} correspondances);
results.matched_chunks.forEach(match => {
console.log(Document : ${match.document.name});
console.log(Score : ${match.distance});
console.log(Contenu : ${match.matched_content});
console.log('---');
});
})
.catch(error => console.error(error));
*/
```
```ruby 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
# Obtenir les détails du magasin de vecteurs 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
# Télécharger du contenu texte 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
# Rechercher des documents 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
# Lister les documents 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
# Télécharger un fichier (formulaire 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 "La demande API a échoué : #{response.code} #{response.message}\n#{response.body}"
end
response
end end ```
Exemple d'utilisation¶
=begin client = VectorStoreClient.new('your_api_key', 'vs_abc123')
Rechercher des documents¶
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 ```
```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_chunksetnext_chunkspour 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
tpour 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 : 1. L'exportation des données de votre base de données vectorielle source 2. La conversion des données dans un format compatible avec Rememberizer 3. L'importation des données dans votre magasin de vecteurs Rememberizer 4. 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¶
```python 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()¶
```
```javascript 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¶
```python 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()¶
```
```javascript 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.
```python 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()¶
```
```javascript 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
Pour une référence API détaillée et la documentation des points de terminaison, visitez la page vector-store.
Assurez-vous de gérer les clés API de manière sécurisée et de suivre les meilleures pratiques pour la gestion des clés API.