# Almacenes de Vectores

El Almacén de Vectores de Rememberizer simplifica el proceso de manejo de datos vectoriales, permitiéndote concentrarte en la entrada de texto y aprovechando el poder de los vectores para diversas aplicaciones como la búsqueda y el análisis de datos.

## Introducción

El Almacén de Vectores Rememberizer proporciona una interfaz fácil de usar para manejar datos vectoriales mientras abstrae la complejidad de las incrustaciones vectoriales. Impulsado por PostgreSQL con la extensión pgvector, el Almacén de Vectores Rememberizer te permite trabajar directamente con texto. El servicio se encarga de dividir, vectorizar y almacenar los datos de texto, facilitándote el enfoque en la lógica central de tu aplicación.

Para una comprensión más profunda de los conceptos teóricos detrás de las incrustaciones vectoriales y las bases de datos vectoriales, consulta [¿Qué son las Incrustaciones Vectoriales y las Bases de Datos Vectoriales?](https://docs.rememberizer.ai/es/background/what-are-vector-embeddings-and-vector-databases).

## Visión Técnica

### Cómo Funcionan los Almacenes de Vectores

Los Almacenes de Vectores de Rememberizer convierten texto en representaciones vectoriales de alta dimensión (embeddings) que capturan el significado semántico. Esto permite:

1. **Búsqueda Semántica**: Encontrar documentos basados en el significado en lugar de solo palabras clave
2. **Coincidencia de Similitud**: Identificar contenido conceptualmente relacionado
3. **Recuperación Eficiente**: Localizar rápidamente información relevante de grandes conjuntos de datos

### Componentes Clave

* **Procesamiento de Documentos**: El texto se divide en fragmentos de tamaño óptimo con límites superpuestos para la preservación del contexto
* **Vectorización**: Los fragmentos se convierten en incrustaciones utilizando modelos de última generación
* **Indexación**: Algoritmos especializados organizan vectores para una búsqueda de similitud eficiente
* **Procesamiento de Consultas**: Las consultas de búsqueda se vectorizan y se comparan con las incrustaciones almacenadas

### Arquitectura

Rememberizer implementa almacenes de vectores utilizando:

* **PostgreSQL con la extensión pgvector**: Para almacenamiento y búsqueda de vectores eficientes
* **Organización basada en colecciones**: Cada almacén de vectores tiene su propia colección aislada
* **Acceso impulsado por API**: Puntos finales RESTful simples para todas las operaciones

## Empezando

### Creando un Almacén de Vectores

1. Navega a la Sección de Almacenes de Vectores en tu panel de control
2. Haz clic en "Crear nuevo Almacén de Vectores":
   * Aparecerá un formulario que te pedirá que ingreses detalles.
3. Completa los Detalles:
   * **Nombre**: Proporciona un nombre único para tu almacén de vectores.
   * **Descripción**: Escribe una breve descripción del almacén de vectores.
   * **Modelo de Embedding**: Selecciona el modelo que convierte texto en vectores.
   * **Algoritmo de Indexación**: Elige cómo se organizarán los vectores para la búsqueda.
   * **Métrica de Búsqueda**: Define cómo se calcula la similitud entre vectores.
   * **Dimensión del Vector**: El tamaño de las incrustaciones de vectores (típicamente 768-1536).
4. Envía el Formulario:
   * Haz clic en el botón "Crear". Recibirás una notificación de éxito, y el nuevo almacén aparecerá en tu lista de almacenes de vectores.

<figure><img src="https://983989491-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeFTiuIsKOMpUEE73g7bP%2Fuploads%2Fgit-blob-72ea151df769d4ea4796d74ab2d2b335a2445a6f%2Fcreate_vector_DB_store.png?alt=media" alt="Crear un Nuevo Almacén de Vectores"><figcaption><p>Crear un Nuevo Almacén de Vectores</p></figcaption></figure>

### Opciones de Configuración

#### Modelos de Embedding

| Modelo                        | Dimensiones | Descripción                                        | Mejor Para                                                   |
| ----------------------------- | ----------- | -------------------------------------------------- | ------------------------------------------------------------ |
| openai/text-embedding-3-large | 1536        | Modelo de embedding de alta precisión de OpenAI    | Aplicaciones de producción que requieren la máxima precisión |
| openai/text-embedding-3-small | 1536        | Modelo de embedding más pequeño y rápido de OpenAI | Aplicaciones con mayores requisitos de rendimiento           |

#### Algoritmos de Indexación

| Algoritmo                | Descripción                            | Compensaciones                                                                                       |
| ------------------------ | -------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| IVFFLAT (predeterminado) | Archivo invertido con compresión plana | Buen equilibrio entre velocidad y precisión; funciona bien para la mayoría de los conjuntos de datos |
| HNSW                     | Mundo Pequeño Navegable Jerárquico     | Mejor precisión para conjuntos de datos grandes; mayores requisitos de memoria                       |

#### Métricas de Búsqueda

| Métrica                 | Descripción                             | Mejor Para                                       |
| ----------------------- | --------------------------------------- | ------------------------------------------------ |
| coseno (predeterminado) | Mide el ángulo entre vectores           | Coincidencia de similitud de propósito general   |
| producto interno (ip)   | Producto punto entre vectores           | Cuando la magnitud del vector es importante      |
| L2 (Euclidiana)         | Distancia en línea recta entre vectores | Cuando las relaciones espaciales son importantes |

### Gestión de Almacenes de Vectores

1. Ver y Editar Almacenes de Vectores:
   * Accede al panel de gestión para ver, editar o eliminar almacenes de vectores.
2. Visualización de Documentos:
   * Navega por documentos individuales y su metadatos asociados dentro de un almacén de vectores específico.
3. Estadísticas:
   * Visualiza estadísticas detalladas como el número de vectores almacenados, el rendimiento de las consultas y métricas operativas.

<figure><img src="https://983989491-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeFTiuIsKOMpUEE73g7bP%2Fuploads%2Fgit-blob-302b722a14296aab8a6021b660e14861024f454b%2Fvector_store_management.png?alt=media" alt="Ver Detalles de un Almacén de Vectores"><figcaption><p>Ver Detalles de un Almacén de Vectores</p></figcaption></figure>

## Gestión de Claves API

Las claves API se utilizan para autenticar y autorizar el acceso a los puntos finales de la API del Almacén de Vectores de Rememberizer. La gestión adecuada de las claves API es esencial para mantener la seguridad y la integridad de sus almacenes de vectores.

### Creando Claves API

1. Dirígete a la página de detalles de tu Almacén de Vectores
2. Navega a la Sección de Gestión de Claves API:
   * Se puede encontrar dentro de la pestaña "Configuración"
3. Haz clic en **"Agregar Clave API"**:
   * Aparecerá un formulario que te pedirá que ingreses los detalles.
4. Completa los Detalles:
   * **Nombre**: Proporciona un nombre para la clave API que te ayude a identificar su caso de uso.
5. Envía el Formulario:
   * Haz clic en el botón "Crear". La nueva clave API será generada y mostrada. Asegúrate de copiarla y almacenarla de forma segura. Esta clave se utiliza para autenticar solicitudes a ese almacén de vectores específico.

<figure><img src="https://983989491-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeFTiuIsKOMpUEE73g7bP%2Fuploads%2Fgit-blob-bff80d6c4bcf1467cd515d0c9848e7fce600765f%2Fvector_store_api_key.png?alt=media" alt="Crear una Nueva Clave API"><figcaption><p>Crear una Nueva Clave API</p></figcaption></figure>

### Revocación de Claves API

Si una clave API ya no es necesaria, puedes eliminarla para prevenir cualquier posible uso indebido.

Por razones de seguridad, es posible que desees rotar tus claves API periódicamente. Esto implica generar una nueva clave y revocar la antigua.

## Uso de la API de Vector Store

Después de crear un Vector Store y generar una clave API, puedes interactuar con él utilizando la API REST.

### Ejemplos de Código

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

API_KEY = "your_api_key_here"
VECTOR_STORE_ID = "vs_abc123"  # Reemplaza con tu ID de almacén de vectores
BASE_URL = "https://api.rememberizer.a

# Cargar un documento en el almacén de vectores
def upload_document(file_path, document_name=None):
    if document_name is None:
        document_name = file_path.split("/")[-1]
    
    with open(file_path, "rb") as f:
        files = {"file": (document_name, f)}
        headers = {"x-api-key": API_KEY}
        
        response = requests.post(
            f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents",
            headers=headers,
            files=files
        )
        
        if response.status_code == 201:
            print(f"¡Documento '{document_name}' cargado con éxito!")
            return response.json()
        else:
            print(f"Error al cargar el documento: {response.text}")
            return None

# Cargar contenido de texto en el almacén de vectores
def upload_text(content, document_name):
    headers = {
        "x-api-key": API_KEY,
        "Content-Type": "application/json"
    }
    
    data = {
        "name": document_name,
        "content": content
    }
    
    response = requests.post(
        f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
        headers=headers,
        json=data
    )
    
    if response.status_code == 201:
        print(f"¡Documento de texto '{document_name}' cargado con éxito!")
        return response.json()
    else:
        print(f"Error al cargar el texto: {response.text}")
        return None

# Buscar en el almacén de vectores
def search_vector_store(query, num_results=5, prev_chunks=1, next_chunks=1):
    headers = {"x-api-key": API_KEY}
    
    params = {
        "q": query,
        "n": num_results,
        "prev_chunks": prev_chunks,
        "next_chunks": next_chunks
    }
    
    response = requests.get(
        f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/search",
        headers=headers,
        params=params
    )
    
    if response.status_code == 200:
        results = response.json()
        print(f"Encontrados {len(results['matched_chunks'])} coincidencias para '{query}'")
        
        # Imprimir el resultado principal
        if results['matched_chunks']:
            top_match = results['matched_chunks'][0]
            print(f"Coincidencia principal (distancia: {top_match['distance']}):")
            print(f"Documento: {top_match['document']['name']}")
            print(f"Contenido: {top_match['matched_content']}")
        
        return results
    else:
        print(f"Error al buscar: {response.text}")
        return None

# Ejemplo de uso
# subir_documento("ruta/al/documento.pdf")
# upload_text("Este es un texto de muestra para ser vectorizado", "sample-document.txt")
# search_vector_store("¿Cómo funciona la similitud de vectores?")
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// Cliente de API de Almacén de Vectores
class VectorStoreClient {
  constructor(apiKey, vectorStoreId) {
    this.apiKey = apiKey;
    this.vectorStoreId = vectorStoreId;
    this.baseUrl = 'https://api.rememberizer.ai/api/v1';
  }

  // Obtener información del almacén de vectores
  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(`Error al obtener información del almacén de vectores: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Subir un documento de texto
  async uploadTextDocument(name, content) {
    const response = await fetch(`${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/text`, {
      method: 'POST',
      headers: {
        'x-api-key': this.apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name,
        content
      })
    });
    
    if (!response.ok) {
      throw new Error(`Error al subir el documento de texto: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Subir un archivo
  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(`Error al subir el archivo: ${xhr.statusText}`));
        }
      };
      
      xhr.onerror = () => {
        reject(new Error('Error de red durante la subida del archivo'));
      };
      
      xhr.send(formData);
    });
  }

  // Buscar documentos en el almacén de vectores
  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(`Error de búsqueda: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Listar todos los documentos en el almacén de vectores
  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(`Error al listar documentos: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Eliminar un documento
  async deleteDocument(documentId) {
    const response = await fetch(
      `${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/${documentId}`,
      {
        method: 'DELETE',
        headers: {
          'x-api-key': this.apiKey
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`Error al eliminar el documento: ${response.statusText}`);
    }
    
    return true;
  }
}

// Ejemplo de uso
/*
const client = new VectorStoreClient('your_api_key', 'vs_abc123');

// Buscar documentos
client.searchDocuments('¿Cómo funciona la búsqueda semántica?')
  .then(results => {
    console.log(`Se encontraron ${results.matched_chunks.length} coincidencias`);
    results.matched_chunks.forEach(match => {
      console.log(`Documento: ${match.document.name}`);
      console.log(`Puntuación: ${match.distance}`);
      console.log(`Contenido: ${match.matched_content}`);
      console.log('---');
    });
  })
  .catch(error => console.error(error));
*/
```

{% endtab %}

{% tab title="Ruby" %}

```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

  # Obtener detalles del almacén de vectores
  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

  # Subir contenido de texto
  def upload_text(name, content)
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents/text")
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request['x-api-key'] = @api_key
    
    request.body = {
      name: name,
      content: content
    }.to_json
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # Buscar documentos
  def search(query, num_results: 5, prev_chunks: 1, next_chunks: 1, threshold: nil)
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents/search")
    params = {
      q: query,
      n: num_results,
      prev_chunks: prev_chunks,
      next_chunks: next_chunks
    }
    
    params[:t] = threshold if threshold
    
    uri.query = URI.encode_www_form(params)
    request = Net::HTTP::Get.new(uri)
    request['x-api-key'] = @api_key
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # Listar documentos
  def list_documents
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents")
    request = Net::HTTP::Get.new(uri)
    request['x-api-key'] = @api_key
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # Subir archivo (formulario 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 "Error en la solicitud a la API: #{response.code} #{response.message}\n#{response.body}"
    end
    
    response
  end
end
```

## Ejemplo de uso

\=begin client = VectorStoreClient.new('your\_api\_key', 'vs\_abc123')

## Buscar documentos

results = client.search('¿Cuáles son las mejores prácticas para la seguridad de datos?') puts "Encontrados #{results\['matched\_chunks'].length} resultados"

## Mostrar el mejor resultado

if results\['matched\_chunks'].any? top\_match = results\['matched\_chunks'].first puts "Mejor coincidencia (distancia: #{top\_match\['distance']}):" puts "Documento: #{top\_match\['document']\['name']}" puts "Contenido: #{top\_match\['matched\_content']}" end =end

````
{% endtab %}

{% tab title="cURL" %}
```bash
# Establece tu clave API y el ID de la tienda de vectores
API_KEY="your_api_key_here"
VECTOR_STORE_ID="vs_abc123"
BASE_URL="https://api.rememberizer.ai/api/v1"

# Obtener información del almacén de vectores
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}" \
  -H "x-api-key: ${API_KEY}"

# Subir un documento de texto
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/text" \
  -H "x-api-key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "example-document.txt",
    "content": "Este es un documento de muestra que será vectorizado y almacenado en la base de datos vectorial para búsqueda semántica."
  }'

# Subir un archivo
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
  -H "x-api-key: ${API_KEY}" \
  -F "file=@/ruta/a/tu/documento.pdf"

# Buscar documentos
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/search?q=semantic%20search&n=5&prev_chunks=1&next_chunks=1" \
  -H "x-api-key: ${API_KEY}"

# Listar todos los documentos
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
  -H "x-api-key: ${API_KEY}"

# Eliminar un documento
curl -X DELETE "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/123" \
  -H "x-api-key: ${API_KEY}"
````

{% endtab %} {% endtabs %}

### Consideraciones de Rendimiento

Próximamente: Diagrama de Arquitectura de Almacenamiento de Vectores

Este diagrama de arquitectura técnica ilustrará:

* La arquitectura de base de PostgreSQL + pgvector
* Estructuras de algoritmos de indexación (IVFFLAT vs. HNSW)
* Cómo funcionan las métricas de búsqueda en el espacio vectorial (comparación visual)
* Proceso de fragmentación de documentos con visualización de superposición
* Consideraciones de rendimiento visualizadas a través de diferentes escalas

#### Optimización para Diferentes Volúmenes de Datos

| Volumen de Datos            | Configuración Recomendada                            | Notas                                                             |
| --------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------- |
| Pequeño (<10k documentos)   | IVFFLAT, similitud coseno                            | La configuración simple proporciona un buen rendimiento           |
| Medio (10k-100k documentos) | IVFFLAT, asegurar reindexación regular               | Equilibrio entre velocidad de búsqueda y mantenimiento del índice |
| Grande (>100k documentos)   | HNSW, considerar aumentar las dimensiones del vector | Mayor uso de memoria pero mantiene el rendimiento a gran escala   |

#### Estrategias de Fragmentación

El proceso de fragmentación impacta significativamente la calidad de búsqueda:

* **Tamaño del Fragmento**: Rememberizer utiliza un tamaño de fragmento predeterminado de 1024 bytes con una superposición de 200 bytes
* **Fragmentos Más Pequeños** (512-1024 bytes): Coincidencias más precisas, mejor para preguntas específicas
* **Fragmentos Más Grandes** (1500-2048 bytes): Más contexto en cada coincidencia, mejor para temas más amplios
* **Superposición**: Asegura que el contexto no se pierda en los límites de los fragmentos

#### Optimización de Consultas

* **Ventanas de Contexto**: Utiliza `prev_chunks` y `next_chunks` para recuperar contenido circundante
* **Cantidad de Resultados**: Comienza con 3-5 resultados (`n` parameter) y ajusta según las necesidades de precisión
* **Umbral**: Ajusta el parámetro `t` para filtrar resultados por puntuación de similitud

### Uso Avanzado

#### Reindexación

Rememberizer activa automáticamente la reindexación cuando los recuentos de vectores superan los umbrales predefinidos, pero considere la reindexación manual después de:

* Subir una gran cantidad de documentos
* Cambiar el modelo de incrustación
* Modificar el algoritmo de indexación

#### Mejora de Consultas

Para obtener mejores resultados de búsqueda:

1. **Sé específico** en las consultas de búsqueda
2. **Incluye contexto** cuando sea posible
3. **Usa lenguaje natural** en lugar de palabras clave
4. **Ajusta los parámetros** según la calidad del resultado

### Migrando desde Otras Bases de Datos Vectoriales

Si actualmente estás utilizando otras soluciones de bases de datos vectoriales y deseas migrar a Rememberizer Vector Store, las siguientes guías te ayudarán a transferir tus datos de manera eficiente.

#### Visión general de la migración

Migrar datos vectoriales implica:

1. Exportar datos de su base de datos vectorial de origen
2. Convertir los datos a un formato compatible con Rememberizer
3. Importar los datos en su Almacén Vectorial de Rememberizer
4. Verificar que la migración fue exitosa

#### Beneficios de Migrar a Rememberizer

* **Fundación PostgreSQL**: Construido sobre tecnología de base de datos madura con copias de seguridad y recuperación integradas
* **Ecosistema Integrado**: Conexión fluida con otros componentes de Rememberizer
* **Gestión Simplificada**: Interfaz unificada para operaciones vectoriales
* **Seguridad Avanzada**: Seguridad a nivel de fila y controles de acceso granulares
* **Arquitectura Escalable**: Optimización del rendimiento a medida que crece su datos

#### Migrando de Pinecone

{% tabs %} {% tab title="Python" %}

```python
import os
import pinecone
import requests
import json
import time

# Configurar el cliente de Pinecone
pinecone.init(api_key="PINECONE_API_KEY", environment="PINECONE_ENV")
source_index = pinecone.Index("your-pinecone-index")

# Configurar el cliente de Rememberizer Vector Store
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123"  # Tu ID de tienda de vectores de Rememberizer
BASE_URL = "https://api.rememberizer.ai/api/v1"

# 1. Configurar el tamaño del lote para la migración (ajustar según el tamaño de sus datos)
BATCH_SIZE = 100

# 2. Función para obtener vectores de Pinecone
def fetch_vectors_from_pinecone(index_name, batch_size, cursor=None):
    # Utiliza la operación de lista si está disponible en tu versión 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:
        # Para versiones más antiguas de Pinecone sin operación de lista
        # Este es un enfoque simplificado; la implementación real depende de tu patrón de acceso a datos
        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. Función para subir vectores a 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 datos de vectores de Pinecone al formato de 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"Omitiendo {vector_id} - no se encontró contenido de texto en los metadatos")
            continue
            
        data = {
            "name": document_name,
            "content": content,
            # Opcional: incluir metadatos adicionales
            "metadata": vector_data.get("metadata", {})
        }
        
        response = requests.post(
            f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
            headers=headers,
            json=data
        )
        
        if response.status_code == 201:
            print(f"¡Documento '{document_name}' subido con éxito!")
        else:
            print(f"Error al subir el documento {document_name}: {response.text}")
        
        # Agregar un pequeño retraso para prevenir limitaciones de tasa
        time.sleep(0.1)

# 4. Función principal de migración
def migrate_pinecone_to_rememberizer():
    cursor = None
    total_migrated = 0
    
    print("Iniciando la migración de Pinecone a Rememberizer...")
    
    while True:
        vectors, cursor = fetch_vectors_from_pinecone("your-pinecone-index", BATCH_SIZE, cursor)
        
        if not vectors:
            break
            
        print(f"Se obtuvieron {len(vectors)} vectores de Pinecone")
        upload_to_rememberizer(vectors)
        
        total_migrated += len(vectors)
        print(f"Progreso: {total_migrated} vectores migrados")
        
        if not cursor:
            break
    
    print(f"¡Migración completa! {total_migrated} vectores migrados en total a Rememberizer")

# Ejecutar la migración
# migrate_pinecone_to_rememberizer()
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { PineconeClient } = require('@pinecone-database/pinecone');
const axios = require('axios');

// Configuración de Pinecone
const pineconeApiKey = 'PINECONE_API_KEY';
const pineconeEnvironment = 'PINECONE_ENVIRONMENT';
const pineconeIndexName = 'YOUR_PINECONE_INDEX';

// Configuración de Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// Configuración del tamaño del lote
const BATCH_SIZE = 100;

// Inicializar el cliente de Pinecone
async function initPinecone() {
  const pinecone = new PineconeClient();
  await pinecone.init({
    apiKey: pineconeApiKey,
    environment: pineconeEnvironment,
  });
  return pinecone;
}

// Obtener vectores de Pinecone
async function fetchVectorsFromPinecone(pinecone, batchSize, paginationToken = null) {
  const index = pinecone.Index(pineconeIndexName);
  
  try {
    // Para versiones más nuevas de Pinecone
    const listResponse = await index.list({
      limit: batchSize,
      paginationToken: paginationToken
    });
    
    return {
      vectors: listResponse.vectors || {},
      nextToken: listResponse.paginationToken
    };
  } catch (error) {
    // Respaldo para versiones más antiguas de Pinecone
    // Esto está simplificado; la implementación real depende de tu patrón de acceso a datos
    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 };
  }
}

// Subir vectores a 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(`Saltando ${vectorId} - no se encontró contenido de texto en los metadatos`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: content,
      // Opcional: incluir metadatos adicionales
      metadata: vectorData.metadata || {}
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`¡Documento '${documentName}' subido con éxito!`);
        results.push({ id: vectorId, success: true });
      } else {
        console.error(`Error al subir el documento ${documentName}: ${response.statusText}`);
        results.push({ id: vectorId, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`Error al subir el documento ${documentName}: ${error.message}`);
      results.push({ id: vectorId, success: false, error: error.message });
    }
    
    // Agregar un pequeño retraso para prevenir limitaciones de tasa
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// Función principal de migración
async function migratePineconeToRememberizer() {
  try {
    console.log('Iniciando la migración de Pinecone a 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(`Se obtuvieron ${Object.keys(vectors).length} vectores de Pinecone`);
      
      const results = await uploadToRememberizer(vectors);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`Progreso: ${totalMigrated} vectores migrados con éxito`);
      
    } while (nextToken);
    
    console.log(`¡Migración completa! ${totalMigrated} vectores migrados en total a Rememberizer`);
    
  } catch (error) {
    console.error('La migración falló:', error);
  }
}

// Ejecutar la migración
// migratePineconeToRememberizer();
```

{% endtab %} {% endtabs %}

#### Migrando desde Qdrant

{% tabs %} {% tab title="Python" %}

```python
import requests
import json
import time
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest

# Configurar cliente Qdrant
QDRANT_URL = "http://localhost:6333"  # o tu URL de Qdrant en la nube
QDRANT_API_KEY = "your_qdrant_api_key"  # si usas Qdrant Cloud
QDRANT_COLLECTION_NAME = "your_collection"

qdrant_client = QdrantClient(
    url=QDRANT_URL,
    api_key=QDRANT_API_KEY  # Solo para Qdrant Cloud
)

# Configurar el cliente de Rememberizer Vector Store
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123"  # Tu ID de tienda de vectores de Rememberizer
BASE_URL = "https://api.rememberizer.ai/api/v1"

# Tamaño del lote para el procesamiento
BATCH_SIZE = 100

# Función para obtener puntos de Qdrant
def fetch_points_from_qdrant(collection_name, batch_size, offset=0):
    try:
        # Obtener información de la colección para determinar la dimensión del vector
        collection_info = qdrant_client.get_collection(collection_name=collection_name)
        
        # Desplazarse a través de los puntos
        scroll_result = qdrant_client.scroll(
            collection_name=collection_name,
            limit=batch_size,
            offset=offset,
            with_payload=True,
            with_vectors=True
        )
        
        points = scroll_result[0]  # Tupla de (puntos, siguiente_offset)
        next_offset = scroll_result[1]
        
        return points, next_offset
    except Exception as e:
        print(f"Error al obtener puntos de Qdrant: {e}")
        return [], None

# Función para subir vectores a Rememberizer
def upload_to_rememberizer(points):
    headers = {
        "x-api-key": REMEMBERIZER_API_KEY,
        "Content-Type": "application/json"
    }
    
    results = []
    
    for point in points:
        # Extraer datos del punto de 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"Omitiendo {point_id} - no se encontró contenido de texto en la carga")
            continue
            
        data = {
            "name": document_name,
            "content": text_content,
            # Opcional: incluir metadatos adicionales
            "metadata": metadata
        }
        
        try:
            response = requests.post(
                f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
                headers=headers,
                json=data
            )
            
            if response.status_code == 201:
                print(f"¡Documento '{document_name}' subido con éxito!")
                results.append({"id": point_id, "success": True})
            else:
                print(f"Error al subir el documento {document_name}: {response.text}")
                results.append({"id": point_id, "success": False, "error": response.text})
        except Exception as e:
            print(f"Excepción al subir el documento {document_name}: {str(e)}")
            results.append({"id": point_id, "success": False, "error": str(e)})
        
        # Agregar un pequeño retraso para prevenir limitaciones de tasa
        time.sleep(0.1)
    
    return results

# Función principal de migración
def migrate_qdrant_to_rememberizer():
    offset = None
    total_migrated = 0
    
    print("Iniciando la migración de Qdrant a Rememberizer...")
    
    while True:
        points, next_offset = fetch_points_from_qdrant(
            QDRANT_COLLECTION_NAME, 
            BATCH_SIZE,
            offset
        )
        
        if not points:
            break
            
        print(f"Se obtuvieron {len(points)} puntos 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"Progreso: {total_migrated} puntos migrados con éxito")
        
        if next_offset is None:
            break
            
        offset = next_offset
    
    print(f"¡Migración completa! {total_migrated} puntos migrados en total a Rememberizer")

# Ejecutar la migración
# migrate_qdrant_to_rememberizer()
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { QdrantClient } = require('@qdrant/js-client-rest');
const axios = require('axios');

// Configuración de Qdrant
const qdrantUrl = 'http://localhost:6333'; // o tu URL de Qdrant en la nube
const qdrantApiKey = 'your_qdrant_api_key'; // si usas Qdrant Cloud
const qdrantCollectionName = 'your_collection';

// Configuración de Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// Configuración del tamaño del lote
const BATCH_SIZE = 100;

// Inicializar cliente de Qdrant
const qdrantClient = new QdrantClient({ 
  url: qdrantUrl,
  apiKey: qdrantApiKey // Solo para Qdrant Cloud
});

// Obtener puntos de Qdrant
async function fetchPointsFromQdrant(collectionName, batchSize, offset = 0) {
  try {
    // Obtener información de la colección
    const collectionInfo = await qdrantClient.getCollection(collectionName);
    
    // Desplazarse a través de los puntos
    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(`Error al obtener puntos de Qdrant: ${error.message}`);
    return { points: [], nextOffset: null };
  }
}

// Subir vectores a Rememberizer
async function uploadToRememberizer(points) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const point of points) {
    // Extraer datos del punto de Qdrant
    const pointId = point.id;
    const metadata = point.payload || {};
    const textContent = metadata.text || '';
    const documentName = metadata.filename || `qdrant_doc_${pointId}`;
    
    if (!textContent) {
      console.log(`Saltando ${pointId} - no se encontró contenido de texto en la carga útil`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: textContent,
      // Opcional: incluir metadatos adicionales
      metadata: metadata
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`¡Documento '${documentName}' subido con éxito!`);
        results.push({ id: pointId, success: true });
      } else {
        console.error(`Error al subir el documento ${documentName}: ${response.statusText}`);
        results.push({ id: pointId, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`Error al subir el documento ${documentName}: ${error.message}`);
      results.push({ id: pointId, success: false, error: error.message });
    }
    
    // Agregar un pequeño retraso para evitar limitaciones de tasa
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// Función principal de migración
async function migrateQdrantToRememberizer() {
  try {
    console.log('Iniciando la migración de Qdrant a 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(`Se obtuvieron ${points.length} puntos de Qdrant`);
      
      const results = await uploadToRememberizer(points);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`Progreso: ${totalMigrated} puntos migrados con éxito`);
      
    } while (offset !== null);
    
    console.log(`¡Migración completa! ${totalMigrated} puntos migrados en total a Rememberizer`);
    
  } catch (error) {
    console.error('La migración falló:', error);
  }
}

// Ejecutar la migración
// migrateQdrantToRememberizer();
```

{% endtab %} {% endtabs %}

#### Migrando de Supabase pgvector

Si ya estás utilizando Supabase con pgvector, la migración a Rememberizer es particularmente sencilla ya que ambos utilizan PostgreSQL con la extensión pgvector.

{% tabs %} {% tab title="Python" %}

```python
import psycopg2
import requests
import json
import time
import os
from dotenv import load_dotenv

# Cargar variables de entorno
load_dotenv()

# Configuración de 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")

# Configuración de Rememberizer
REMEMBERIZER_API_KEY = os.getenv("REMEMBERIZER_API_KEY")
VECTOR_STORE_ID = os.getenv("VECTOR_STORE_ID")  # p. ej., "vs_abc123"
BASE_URL = "https://api.rememberizer.ai/api/v1"

# Tamaño del lote para el procesamiento
BATCH_SIZE = 100

# Conectar a 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"Error al conectar a Supabase PostgreSQL: {e}")
        return None

# Obtener documentos de Supabase pgvector
def fetch_documents_from_supabase(conn, batch_size, offset=0):
    try:
        cursor = conn.cursor()
        
        # Ajusta esta consulta según la estructura de tu tabla
        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"Error al obtener documentos de Supabase: {e}")
        return []

# Cargar documentos a 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
        
        # Analizar metadatos si se almacenan como cadena 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"Omitiendo {doc_id} - no se encontró contenido")
            continue
            
        data = {
            "name": document_name,
            "content": content,
            "metadata": metadata
        }
        
        try:
            response = requests.post(
                f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
                headers=headers,
                json=data
            )
            
            if response.status_code == 201:
                print(f"¡Documento '{document_name}' cargado con éxito!")
                results.append({"id": doc_id, "success": True})
            else:
                print(f"Error al cargar el documento {document_name}: {response.text}")
                results.append({"id": doc_id, "success": False, "error": response.text})
        except Exception as e:
            print(f"Excepción al cargar el documento {document_name}: {str(e)}")
            results.append({"id": doc_id, "success": False, "error": str(e)})
        
        # Agregar un pequeño retraso para prevenir limitaciones de tasa
        time.sleep(0.1)
    
    return results

# Función principal de migración
def migrate_supabase_to_rememberizer():
    conn = connect_to_supabase()
    if not conn:
        print("Error al conectar a Supabase. Abortando la migración.")
        return
    
    offset = 0
    total_migrated = 0
    
    print("Iniciando la migración de Supabase pgvector a Rememberizer...")
    
    try:
        while True:
            documents = fetch_documents_from_supabase(conn, BATCH_SIZE, offset)
            
            if not documents:
                break
                
            print(f"Se obtuvieron {len(documents)} documentos 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"Progreso: {total_migrated} documentos migrados con éxito")
            
            offset += BATCH_SIZE
            
    finally:
        conn.close()
    
    print(f"¡Migración completa! {total_migrated} documentos migrados en total a Rememberizer")

# Ejecutar la migración
# migrate_supabase_to_rememberizer()
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const { Pool } = require('pg');
const axios = require('axios');
require('dotenv').config();

// Configuración de PostgreSQL de 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';

// Configuración de Rememberizer
const rememberizerApiKey = process.env.REMEMBERIZER_API_KEY;
const vectorStoreId = process.env.VECTOR_STORE_ID; // por ejemplo, "vs_abc123"
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// Configuración del tamaño del lote
const BATCH_SIZE = 100;

// Obtener documentos de Supabase pgvector
async function fetchDocumentsFromSupabase(batchSize, offset = 0) {
  try {
    // Ajusta esta consulta según la estructura de tu tabla
    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(`Error al obtener documentos de Supabase: ${error.message}`);
    return [];
  }
}

// Subir documentos a Rememberizer
async function uploadToRememberizer(documents) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const doc of documents) {
    // Analizar metadata si está almacenada como cadena 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(`Saltando ${doc.id} - no se encontró contenido`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: doc.content,
      metadata: metadata
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`¡Documento '${documentName}' subido exitosamente!`);
        results.push({ id: doc.id, success: true });
      } else {
        console.error(`Error al subir el documento ${documentName}: ${response.statusText}`);
        results.push({ id: doc.id, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`Error al subir el documento ${documentName}: ${error.message}`);
      results.push({ id: doc.id, success: false, error: error.message });
    }
    
    // Agregar un pequeño retraso para evitar limitaciones de tasa
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// Función principal de migración
async function migrateSupabaseToRememberizer() {
  try {
    console.log('Iniciando la migración de Supabase pgvector a Rememberizer...');
    
    let offset = 0;
    let totalMigrated = 0;
    
    while (true) {
      const documents = await fetchDocumentsFromSupabase(BATCH_SIZE, offset);
      
      if (documents.length === 0) {
        break;
      }
      
      console.log(`Se obtuvieron ${documents.length} documentos de Supabase`);
      
      const results = await uploadToRememberizer(documents);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`Progreso: ${totalMigrated} documentos migrados exitosamente`);
      
      offset += BATCH_SIZE;
    }
    
    console.log(`¡Migración completa! ${totalMigrated} documentos migrados en total a Rememberizer`);
    
  } catch (error) {
    console.error('La migración falló:', error);
  } finally {
    await supabasePool.end();
  }
}

// Ejecutar la migración
// migrateSupabaseToRememberizer();
```

{% endtab %}
{% endtabs %}

### Mejores Prácticas de Migración

Sigue estas recomendaciones para una migración exitosa:

1. **Planifica con Anticipación**:
   * Estima el volumen de datos y el tiempo requerido para la migración
   * Programa la migración durante períodos de baja actividad
   * Aumenta el espacio en disco antes de comenzar migraciones grandes
2. **Prueba Primero**:
   * Crea un almacén de vectores de prueba en Rememberizer
   * Migra un pequeño subconjunto de datos (100-1000 vectores)
   * Verifica la funcionalidad de búsqueda con consultas clave
3. **Validación de Datos**:
   * Compara el conteo de documentos antes y después de la migración
   * Ejecuta consultas de referencia para asegurar resultados similares
   * Valida que los metadatos se conserven correctamente
4. **Optimiza para el Rendimiento**:
   * Utiliza operaciones por lotes para mayor eficiencia
   * Considera la colocación geográfica de las bases de datos de origen y destino
   * Monitorea los límites de tasa de la API y ajusta los tamaños de los lotes en consecuencia
5. **Pasos Post-Migración**:
   * Verifica la creación del índice en Rememberizer
   * Actualiza las configuraciones de la aplicación para apuntar al nuevo almacén de vectores
   * Mantén la base de datos de origen como respaldo hasta que la migración sea verificada

Para referencia detallada de la API y documentación de puntos finales, visita la página de [vector-store](https://docs.rememberizer.ai/es/recursos-para-desarrolladores/api-docs/vector-store).

***

Asegúrate de manejar las claves de API de manera segura y seguir las mejores prácticas para la gestión de claves de API.
