# Cửa hàng Vector

Cửa hàng Vector của Rememberizer đơn giản hóa quy trình xử lý dữ liệu vector, cho phép bạn tập trung vào đầu vào văn bản và tận dụng sức mạnh của các vector cho nhiều ứng dụng như tìm kiếm và phân tích dữ liệu.

## Giới thiệu

Rememberizer Vector Store cung cấp một giao diện dễ sử dụng để xử lý dữ liệu vector trong khi trừu tượng hóa sự phức tạp của các vector embeddings. Được hỗ trợ bởi PostgreSQL với phần mở rộng pgvector, Rememberizer Vector Store cho phép bạn làm việc trực tiếp với văn bản. Dịch vụ này xử lý việc chia nhỏ, vector hóa và lưu trữ dữ liệu văn bản, giúp bạn dễ dàng tập trung vào logic ứng dụng cốt lõi của mình.

Để hiểu sâu hơn về các khái niệm lý thuyết đằng sau vector embeddings và cơ sở dữ liệu vector, hãy xem [Vector Embeddings và Cơ sở dữ liệu Vector là gì?](https://docs.rememberizer.ai/vi/background/what-are-vector-embeddings-and-vector-databases).

## Tổng Quan Kỹ Thuật

### Cách Các Kho Vector Hoạt Động

Kho Vector Rememberizer chuyển đổi văn bản thành các đại diện vector nhiều chiều (nhúng) nắm bắt ý nghĩa ngữ nghĩa. Điều này cho phép:

1. **Tìm Kiếm Ngữ Nghĩa**: Tìm tài liệu dựa trên ý nghĩa thay vì chỉ từ khóa
2. **Khớp Tương Tự**: Xác định nội dung có liên quan về mặt khái niệm
3. **Truy Xuất Hiệu Quả**: Nhanh chóng xác định thông tin liên quan từ các tập dữ liệu lớn

### Các Thành Phần Chính

* **Xử Lý Tài Liệu**: Văn bản được chia thành các đoạn có kích thước tối ưu với các ranh giới chồng chéo để bảo tồn ngữ cảnh
* **Chuyển Đổi Thành Vector**: Các đoạn được chuyển đổi thành các nhúng bằng cách sử dụng các mô hình tiên tiến nhất
* **Lập Chỉ Mục**: Các thuật toán chuyên biệt tổ chức các vector để tìm kiếm độ tương đồng hiệu quả
* **Xử Lý Truy Vấn**: Các truy vấn tìm kiếm được chuyển đổi thành vector và so sánh với các nhúng đã lưu trữ

### Kiến trúc

Rememberizer triển khai các kho vector sử dụng:

* **PostgreSQL với phần mở rộng pgvector**: Để lưu trữ và tìm kiếm vector hiệu quả
* **Tổ chức dựa trên bộ sưu tập**: Mỗi kho vector có bộ sưu tập riêng biệt
* **Truy cập dựa trên API**: Các điểm cuối RESTful đơn giản cho tất cả các thao tác

## Bắt đầu

### Tạo một Cửa Hàng Vector

1. Điều hướng đến phần Cửa Hàng Vector trong bảng điều khiển của bạn
2. Nhấp vào "Tạo cửa hàng vector mới":
   * Một biểu mẫu sẽ xuất hiện yêu cầu bạn nhập chi tiết.
3. Điền vào các Chi tiết:
   * **Tên**: Cung cấp một tên duy nhất cho cửa hàng vector của bạn.
   * **Mô tả**: Viết một mô tả ngắn gọn về cửa hàng vector.
   * **Mô hình Nhúng**: Chọn mô hình chuyển đổi văn bản thành vector.
   * **Thuật toán Lập chỉ mục**: Chọn cách tổ chức các vector để tìm kiếm.
   * **Chỉ số Tìm kiếm**: Định nghĩa cách tính toán độ tương đồng giữa các vector.
   * **Kích thước Vector**: Kích thước của các nhúng vector (thường là 768-1536).
4. Gửi Biểu mẫu:
   * Nhấp vào nút "Tạo". Bạn sẽ nhận được thông báo thành công, và cửa hàng mới sẽ xuất hiện trong danh sách cửa hàng vector của bạn.

<figure><img src="https://4187618229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fwbxu0T4faQnPtKbPzrD5%2Fuploads%2Fgit-blob-72ea151df769d4ea4796d74ab2d2b335a2445a6f%2Fcreate_vector_DB_store.png?alt=media" alt="Tạo một Cửa Hàng Vector Mới"><figcaption><p>Tạo một Cửa Hàng Vector Mới</p></figcaption></figure>

### Tùy Chọn Cấu Hình

#### Các Mô Hình Nhúng

| Mô Hình                       | Kích Thước | Mô Tả                                      | Tốt Nhất Cho                                      |
| ----------------------------- | ---------- | ------------------------------------------ | ------------------------------------------------- |
| openai/text-embedding-3-large | 1536       | Mô hình nhúng chính xác cao từ OpenAI      | Các ứng dụng sản xuất yêu cầu độ chính xác tối đa |
| openai/text-embedding-3-small | 1536       | Mô hình nhúng nhỏ hơn, nhanh hơn từ OpenAI | Các ứng dụng có yêu cầu thông lượng cao hơn       |

#### Thuật Toán Lập Chỉ Mục

| Thuật Toán         | Mô Tả                                       | Đánh Đổi                                                                            |
| ------------------ | ------------------------------------------- | ----------------------------------------------------------------------------------- |
| IVFFLAT (mặc định) | Tệp đảo ngược với nén phẳng                 | Cân bằng tốt giữa tốc độ và độ chính xác; hoạt động tốt cho hầu hết các tập dữ liệu |
| HNSW               | Thế Giới Nhỏ Có Thể Điều Hướng Theo Cấp Bậc | Độ chính xác tốt hơn cho các tập dữ liệu lớn; yêu cầu bộ nhớ cao hơn                |

#### Các chỉ số tìm kiếm

| Chỉ số             | Mô tả                                   | Tốt nhất cho                              |
| ------------------ | --------------------------------------- | ----------------------------------------- |
| cosine (mặc định)  | Đo góc giữa các vector                  | So khớp độ tương đồng mục đích chung      |
| inner product (ip) | Tích vô hướng giữa các vector           | Khi độ lớn của vector là quan trọng       |
| L2 (Euclidean)     | Khoảng cách đường thẳng giữa các vector | Khi các mối quan hệ không gian quan trọng |

### Quản lý Cửa hàng Vector

1. Xem và Chỉnh sửa Cửa hàng Vector:
   * Truy cập bảng điều khiển quản lý để xem, chỉnh sửa hoặc xóa cửa hàng vector.
2. Xem Tài liệu:
   * Duyệt qua các tài liệu riêng lẻ và siêu dữ liệu liên quan của chúng trong một cửa hàng vector cụ thể.
3. Thống kê:
   * Xem thống kê chi tiết như số lượng vector được lưu trữ, hiệu suất truy vấn và các chỉ số hoạt động.

<figure><img src="https://4187618229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fwbxu0T4faQnPtKbPzrD5%2Fuploads%2Fgit-blob-302b722a14296aab8a6021b660e14861024f454b%2Fvector_store_management.png?alt=media" alt="Xem Chi tiết của một Cửa hàng Vector"><figcaption><p>Xem Chi tiết của một Cửa hàng Vector</p></figcaption></figure>

## Quản lý Khóa API

Các khóa API được sử dụng để xác thực và ủy quyền truy cập vào các điểm cuối API của Rememberizer Vector Store. Quản lý đúng cách các khóa API là rất quan trọng để duy trì sự an toàn và toàn vẹn của các kho vector của bạn.

### Tạo Khóa API

1. Truy cập trang chi tiết Vector Store của bạn
2. Điều hướng đến Phần Quản lý Khóa API:
   * Nó có thể được tìm thấy trong tab "Cấu hình"
3. Nhấp vào **"Thêm Khóa API"**:
   * Một biểu mẫu sẽ xuất hiện yêu cầu bạn nhập chi tiết.
4. Điền Thông Tin:
   * **Tên**: Cung cấp một tên cho khóa API để giúp bạn xác định trường hợp sử dụng của nó.
5. Gửi Biểu Mẫu:
   * Nhấp vào nút "Tạo". Khóa API mới sẽ được tạo ra và hiển thị. Hãy chắc chắn sao chép và lưu trữ nó một cách an toàn. Khóa này được sử dụng để xác thực các yêu cầu đến cửa hàng vector cụ thể đó.

<figure><img src="https://4187618229-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fwbxu0T4faQnPtKbPzrD5%2Fuploads%2Fgit-blob-bff80d6c4bcf1467cd515d0c9848e7fce600765f%2Fvector_store_api_key.png?alt=media" alt="Tạo Khóa API Mới"><figcaption><p>Tạo Khóa API Mới</p></figcaption></figure>

### Thu hồi khóa API

Nếu một khóa API không còn cần thiết, bạn có thể xóa nó để ngăn chặn bất kỳ sự lạm dụng tiềm ẩn nào.

Vì lý do bảo mật, bạn có thể muốn thay đổi khóa API của mình định kỳ. Điều này bao gồm việc tạo một khóa mới và thu hồi khóa cũ.

## Sử dụng API Vector Store

Sau khi tạo một Vector Store và tạo một khóa API, bạn có thể tương tác với nó bằng cách sử dụng REST API.

### Ví dụ Mã

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

```python
import requests
import json

API_KEY = "your_api_key_here"
VECTOR_STORE_ID = "vs_abc123"  # Thay thế bằng ID kho vector của bạn
BASE_URL = "https://api.rememberizer.a

# Tải lên một tài liệu vào kho vector
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"Tài liệu '{document_name}' đã được tải lên thành công!")
            return response.json()
        else:
            print(f"Lỗi khi tải lên tài liệu: {response.text}")
            return None

# Tải nội dung văn bản lên kho vector
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"Tài liệu văn bản '{document_name}' đã được tải lên thành công!")
        return response.json()
    else:
        print(f"Lỗi khi tải lên văn bản: {response.text}")
        return None

# Tìm kiếm kho vector
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"Đã tìm thấy {len(results['matched_chunks'])} kết quả cho '{query}'")
        
        # In kết quả hàng đầu
        if results['matched_chunks']:
            top_match = results['matched_chunks'][0]
            print(f"Kết quả hàng đầu (khoảng cách: {top_match['distance']}):")
            print(f"Tài liệu: {top_match['document']['name']}")
            print(f"Nội dung: {top_match['matched_content']}")
        
        return results
    else:
        print(f"Lỗi khi tìm kiếm: {response.text}")
        return None

# Ví dụ sử dụng
# tải_tài_liệu("đường/dẫn/đến/tài_liệu.pdf")
# upload_text("Đây là một đoạn văn bản mẫu để được vector hóa", "sample-document.txt")
# search_vector_store("Cách hoạt động của độ tương đồng vector?")
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// Khách hàng API Vector Store
class VectorStoreClient {
  constructor(apiKey, vectorStoreId) {
    this.apiKey = apiKey;
    this.vectorStoreId = vectorStoreId;
    this.baseUrl = 'https://api.rememberizer.ai/api/v1';
  }

  // Lấy thông tin cửa hàng vector
  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(`Không thể lấy thông tin cửa hàng vector: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Tải lên tài liệu văn bản
  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(`Không thể tải lên tài liệu văn bản: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Tải lên một tệp
  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(`Không thể tải lên tệp: ${xhr.statusText}`));
        }
      };
      
      xhr.onerror = () => {
        reject(new Error('Lỗi mạng trong quá trình tải lên tệp'));
      };
      
      xhr.send(formData);
    });
  }

  // Tìm kiếm tài liệu trong cửa hàng vector
  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(`Tìm kiếm không thành công: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Liệt kê tất cả tài liệu trong cửa hàng vector
  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(`Không thể liệt kê tài liệu: ${response.statusText}`);
    }
    
    return response.json();
  }

  // Xóa một tài liệu
  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(`Không thể xóa tài liệu: ${response.statusText}`);
    }
    
    return true;
  }
}

// Ví dụ sử dụng
/*
const client = new VectorStoreClient('your_api_key', 'vs_abc123');

// Tìm kiếm tài liệu
client.searchDocuments('Cách hoạt động của tìm kiếm ngữ nghĩa?')
  .then(results => {
    console.log(`Tìm thấy ${results.matched_chunks.length} kết quả`);
    results.matched_chunks.forEach(match => {
      console.log(`Tài liệu: ${match.document.name}`);
      console.log(`Điểm: ${match.distance}`);
      console.log(`Nội dung: ${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

  # Lấy chi tiết cửa hàng vector
  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ải lên nội dung văn bản
  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

  # Tìm kiếm tài liệu
  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

  # Liệt kê tài liệu
  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ải lên tệp (hình thức đa phần)
  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 "Yêu cầu API không thành công: #{response.code} #{response.message}\n#{response.body}"
    end
    
    response
  end
end
```

## Ví dụ sử dụng

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

## Tìm kiếm tài liệu

results = client.search('Những thực hành tốt nhất cho an ninh dữ liệu là gì?') puts "Tìm thấy #{results\['matched\_chunks'].length} kết quả"

## Hiển thị kết quả hàng đầu

if results\['matched\_chunks'].any? top\_match = results\['matched\_chunks'].first puts "Kết quả hàng đầu (khoảng cách: #{top\_match\['distance']}):" puts "Tài liệu: #{top\_match\['document']\['name']}" puts "Nội dung: #{top\_match\['matched\_content']}" end =end

````
{% endtab %}

{% tab title="cURL" %}
```bash
# Đặt khóa API và ID Vector Store
API_KEY="your_api_key_here"
VECTOR_STORE_ID="vs_abc123"
BASE_URL="https://api.rememberizer.ai/api/v1"

# Lấy thông tin cửa hàng vector
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}" \
  -H "x-api-key: ${API_KEY}"

# Tải lên một tài liệu văn bản
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": "Đây là một tài liệu mẫu sẽ được vector hóa và lưu trữ trong cơ sở dữ liệu vector để tìm kiếm ngữ nghĩa."
  }'

# Tải lên một tệp
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
  -H "x-api-key: ${API_KEY}" \
  -F "file=@/path/to/your/document.pdf"

# Tìm kiếm tài liệu
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}"

# Liệt kê tất cả tài liệu
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
  -H "x-api-key: ${API_KEY}"

# Xóa một tài liệu
curl -X DELETE "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/123" \
  -H "x-api-key: ${API_KEY}"
````

{% endtab %} {% endtabs %}

### Các yếu tố hiệu suất

Sắp ra mắt: Sơ đồ Kiến trúc Lưu trữ Vector

Sơ đồ kiến trúc kỹ thuật này sẽ minh họa:

* Kiến trúc nền tảng PostgreSQL + pgvector
* Cấu trúc thuật toán lập chỉ mục (IVFFLAT so với HNSW)
* Cách thức hoạt động của các chỉ số tìm kiếm trong không gian vector (so sánh trực quan)
* Quá trình chia nhỏ tài liệu với hình ảnh trực quan về sự chồng chéo
* Các yếu tố hiệu suất được hình dung qua các quy mô khác nhau

#### Tối ưu hóa cho Các Khối Lượng Dữ Liệu Khác Nhau

| Khối Lượng Dữ Liệu             | Cấu Hình Đề Xuất                              | Ghi Chú                                                     |
| ------------------------------ | --------------------------------------------- | ----------------------------------------------------------- |
| Nhỏ (<10k tài liệu)            | IVFFLAT, độ tương đồng cosine                 | Cấu hình đơn giản cung cấp hiệu suất tốt                    |
| Trung Bình (10k-100k tài liệu) | IVFFLAT, đảm bảo tái lập chỉ mục thường xuyên | Cân bằng giữa tốc độ tìm kiếm và bảo trì chỉ mục            |
| Lớn (>100k tài liệu)           | HNSW, xem xét tăng kích thước vector          | Sử dụng bộ nhớ cao hơn nhưng duy trì hiệu suất ở quy mô lớn |

#### Chiến Lược Chia Nhỏ

Quá trình chia nhỏ ảnh hưởng đáng kể đến chất lượng tìm kiếm:

* **Kích Thước Chia Nhỏ**: Rememberizer sử dụng kích thước chia nhỏ mặc định là 1024 byte với độ chồng chéo 200 byte
* **Chia Nhỏ Nhỏ Hơn** (512-1024 byte): Các kết quả khớp chính xác hơn, tốt hơn cho các câu hỏi cụ thể
* **Chia Nhỏ Lớn Hơn** (1500-2048 byte): Nhiều ngữ cảnh hơn trong mỗi kết quả khớp, tốt hơn cho các chủ đề rộng
* **Độ Chồng Chéo**: Đảm bảo ngữ cảnh không bị mất ở các ranh giới chia nhỏ

#### Tối ưu hóa truy vấn

* **Cửa sổ ngữ cảnh**: Sử dụng `prev_chunks` và `next_chunks` để lấy nội dung xung quanh
* **Số lượng kết quả**: Bắt đầu với 3-5 kết quả (`n` parameter) và điều chỉnh dựa trên nhu cầu độ chính xác
* **Ngưỡng**: Điều chỉnh tham số `t` để lọc kết quả theo điểm tương đồng

### Sử Dụng Nâng Cao

#### Tái lập chỉ mục

Rememberizer tự động kích hoạt tái lập chỉ mục khi số lượng vector vượt quá ngưỡng đã định trước, nhưng hãy xem xét việc tái lập chỉ mục thủ công sau:

* Tải lên một số lượng lớn tài liệu
* Thay đổi mô hình nhúng
* Sửa đổi thuật toán lập chỉ mục

#### Cải Thiện Truy Vấn

Để có kết quả tìm kiếm tốt hơn:

1. **Cụ thể** trong các truy vấn tìm kiếm
2. **Bao gồm ngữ cảnh** khi có thể
3. **Sử dụng ngôn ngữ tự nhiên** thay vì từ khóa
4. **Điều chỉnh tham số** dựa trên chất lượng kết quả

### Di chuyển từ các cơ sở dữ liệu vector khác

Nếu bạn hiện đang sử dụng các giải pháp cơ sở dữ liệu vector khác và muốn chuyển sang Rememberizer Vector Store, các hướng dẫn sau sẽ giúp bạn chuyển dữ liệu một cách hiệu quả.

#### Tổng Quan Về Di Chuyển

Di chuyển dữ liệu vector bao gồm:

1. Xuất dữ liệu từ cơ sở dữ liệu vector nguồn của bạn
2. Chuyển đổi dữ liệu sang định dạng tương thích với Rememberizer
3. Nhập dữ liệu vào Kho Dữ Liệu Vector Rememberizer của bạn
4. Xác minh rằng việc di chuyển đã thành công

#### Lợi ích của việc Chuyển đổi sang Rememberizer

* **Nền tảng PostgreSQL**: Xây dựng trên công nghệ cơ sở dữ liệu trưởng thành với sao lưu và phục hồi tích hợp
* **Hệ sinh thái Tích hợp**: Kết nối liền mạch với các thành phần khác của Rememberizer
* **Quản lý Đơn giản**: Giao diện thống nhất cho các thao tác vector
* **Bảo mật Nâng cao**: Bảo mật theo hàng và kiểm soát truy cập chi tiết
* **Kiến trúc Có thể mở rộng**: Tối ưu hóa hiệu suất khi dữ liệu của bạn phát triển

#### Di chuyển từ Pinecone

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

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

# Thiết lập khách hàng Pinecone
pinecone.init(api_key="PINECONE_API_KEY", environment="PINECONE_ENV")
source_index = pinecone.Index("your-pinecone-index")

# Thiết lập khách hàng Vector Store Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123"  # ID vector store Rememberizer của bạn
BASE_URL = "https://api.rememberizer.ai/api/v1"

# 1. Thiết lập kích thước lô cho việc di chuyển (điều chỉnh dựa trên kích thước dữ liệu của bạn)
BATCH_SIZE = 100

# 2. Hàm để lấy vector từ Pinecone
def fetch_vectors_from_pinecone(index_name, batch_size, cursor=None):
    # Sử dụng thao tác danh sách nếu có trong phiên bản Pinecone của bạn
    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:
        # Đối với các phiên bản Pinecone cũ hơn không có thao tác danh sách
        # Đây là một cách tiếp cận đơn giản; việc triển khai thực tế phụ thuộc vào mẫu truy cập dữ liệu của bạn
        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. Hàm để tải lên vector đến 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():
        # Chuyển đổi dữ liệu vector Pinecone sang định dạng 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"Bỏ qua {vector_id} - không tìm thấy nội dung văn bản trong metadata")
            continue
            
        data = {
            "name": document_name,
            "content": content,
            # Tùy chọn: bao gồm metadata bổ sung
            "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"Tài liệu '{document_name}' đã được tải lên thành công!")
        else:
            print(f"Lỗi khi tải lên tài liệu {document_name}: {response.text}")
        
        # Thêm một khoảng thời gian nhỏ để ngăn chặn giới hạn tốc độ
        time.sleep(0.1)

# 4. Hàm di chuyển chính
def migrate_pinecone_to_rememberizer():
    cursor = None
    total_migrated = 0
    
    print("Bắt đầu di chuyển từ Pinecone sang Rememberizer...")
    
    while True:
        vectors, cursor = fetch_vectors_from_pinecone("your-pinecone-index", BATCH_SIZE, cursor)
        
        if not vectors:
            break
            
        print(f"Đã lấy {len(vectors)} vector từ Pinecone")
        upload_to_rememberizer(vectors)
        
        total_migrated += len(vectors)
        print(f"Tiến độ: {total_migrated} vector đã di chuyển")
        
        if not cursor:
            break
    
    print(f"Di chuyển hoàn tất! {total_migrated} tổng số vector đã di chuyển sang Rememberizer")

# Chạy quá trình di chuyển
# migrate_pinecone_to_rememberizer()
```

{% endtab %}

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

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

// Cấu hình Pinecone
const pineconeApiKey = 'PINECONE_API_KEY';
const pineconeEnvironment = 'PINECONE_ENVIRONMENT';
const pineconeIndexName = 'YOUR_PINECONE_INDEX';

// Cấu hình Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// Cấu hình kích thước lô
const BATCH_SIZE = 100;

// Khởi tạo client Pinecone
async function initPinecone() {
  const pinecone = new PineconeClient();
  await pinecone.init({
    apiKey: pineconeApiKey,
    environment: pineconeEnvironment,
  });
  return pinecone;
}

// Lấy vector từ Pinecone
async function fetchVectorsFromPinecone(pinecone, batchSize, paginationToken = null) {
  const index = pinecone.Index(pineconeIndexName);
  
  try {
    // Đối với các phiên bản Pinecone mới hơn
    const listResponse = await index.list({
      limit: batchSize,
      paginationToken: paginationToken
    });
    
    return {
      vectors: listResponse.vectors || {},
      nextToken: listResponse.paginationToken
    };
  } catch (error) {
    // Phương án dự phòng cho các phiên bản Pinecone cũ hơn
    // Điều này được đơn giản hóa; việc triển khai thực tế phụ thuộc vào mẫu truy cập dữ liệu của bạn
    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ải lên vector đến 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(`Bỏ qua ${vectorId} - không tìm thấy nội dung văn bản trong metadata`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: content,
      // Tùy chọn: bao gồm metadata bổ sung
      metadata: vectorData.metadata || {}
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`Tài liệu '${documentName}' đã được tải lên thành công!`);
        results.push({ id: vectorId, success: true });
      } else {
        console.error(`Lỗi khi tải lên tài liệu ${documentName}: ${response.statusText}`);
        results.push({ id: vectorId, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`Lỗi khi tải lên tài liệu ${documentName}: ${error.message}`);
      results.push({ id: vectorId, success: false, error: error.message });
    }
    
    // Thêm một khoảng thời gian nhỏ để tránh giới hạn tần suất
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// Hàm di chuyển chính
async function migratePineconeToRememberizer() {
  try {
    console.log('Bắt đầu di chuyển từ Pinecone sang 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(`Đã lấy ${Object.keys(vectors).length} vector từ Pinecone`);
      
      const results = await uploadToRememberizer(vectors);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`Tiến độ: ${totalMigrated} vector đã được di chuyển thành công`);
      
    } while (nextToken);
    
    console.log(`Di chuyển hoàn tất! ${totalMigrated} tổng số vector đã được di chuyển đến Rememberizer`);
    
  } catch (error) {
    console.error('Di chuyển thất bại:', error);
  }
}

// Chạy quá trình di chuyển
// migratePineconeToRememberizer();
```

{% endtab %} {% endtabs %}

#### Di chuyển từ 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

# Thiết lập khách hàng Qdrant
QDRANT_URL = "http://localhost:6333"  # hoặc URL đám mây Qdrant của bạn
QDRANT_API_KEY = "your_qdrant_api_key"  # nếu sử dụng Qdrant Cloud
QDRANT_COLLECTION_NAME = "your_collection"

qdrant_client = QdrantClient(
    url=QDRANT_URL,
    api_key=QDRANT_API_KEY  # Chỉ dành cho Qdrant Cloud
)

# Thiết lập khách hàng Vector Store Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123"  # ID vector store Rememberizer của bạn
BASE_URL = "https://api.rememberizer.ai/api/v1"

# Kích thước lô để xử lý
BATCH_SIZE = 100

# Hàm để lấy điểm từ Qdrant
def fetch_points_from_qdrant(collection_name, batch_size, offset=0):
    try:
        # Lấy thông tin bộ sưu tập để xác định kích thước vector
        collection_info = qdrant_client.get_collection(collection_name=collection_name)
        
        # Cuộn qua các điểm
        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 của (điểm, next_offset)
        next_offset = scroll_result[1]
        
        return points, next_offset
    except Exception as e:
        print(f"Lỗi khi lấy điểm từ Qdrant: {e}")
        return [], None

# Hàm để tải lên vector đến Rememberizer
def upload_to_rememberizer(points):
    headers = {
        "x-api-key": REMEMBERIZER_API_KEY,
        "Content-Type": "application/json"
    }
    
    results = []
    
    for point in points:
        # Trích xuất dữ liệu từ điểm 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"Bỏ qua {point_id} - không tìm thấy nội dung văn bản trong payload")
            continue
            
        data = {
            "name": document_name,
            "content": text_content,
            # Tùy chọn: bao gồm siêu dữ liệu bổ sung
            "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"Tài liệu '{document_name}' đã được tải lên thành công!")
                results.append({"id": point_id, "success": True})
            else:
                print(f"Lỗi khi tải lên tài liệu {document_name}: {response.text}")
                results.append({"id": point_id, "success": False, "error": response.text})
        except Exception as e:
            print(f"Ngoại lệ khi tải lên tài liệu {document_name}: {str(e)}")
            results.append({"id": point_id, "success": False, "error": str(e)})
        
        # Thêm một khoảng thời gian nhỏ để ngăn chặn giới hạn tần suất
        time.sleep(0.1)
    
    return results

# Chức năng di chuyển chính
def migrate_qdrant_to_rememberizer():
    offset = None
    total_migrated = 0
    
    print("Bắt đầu di chuyển từ Qdrant sang Rememberizer...")
    
    while True:
        points, next_offset = fetch_points_from_qdrant(
            QDRANT_COLLECTION_NAME, 
            BATCH_SIZE,
            offset
        )
        
        if not points:
            break
            
        print(f"Đã lấy {len(points)} điểm từ 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"Tiến độ: {total_migrated} điểm đã di chuyển thành công")
        
        if next_offset is None:
            break
            
        offset = next_offset
    
    print(f"Di chuyển hoàn tất! {total_migrated} tổng số điểm đã di chuyển sang Rememberizer")

# Chạy quá trình di chuyển
# migrate_qdrant_to_rememberizer()
```

{% endtab %}

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

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

// Cấu hình Qdrant
const qdrantUrl = 'http://localhost:6333'; // hoặc URL đám mây Qdrant của bạn
const qdrantApiKey = 'your_qdrant_api_key'; // nếu sử dụng Qdrant Cloud
const qdrantCollectionName = 'your_collection';

// Cấu hình Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// Cấu hình kích thước lô
const BATCH_SIZE = 100;

// Khởi tạo client Qdrant
const qdrantClient = new QdrantClient({ 
  url: qdrantUrl,
  apiKey: qdrantApiKey // Chỉ dành cho Qdrant Cloud
});

// Lấy điểm từ Qdrant
async function fetchPointsFromQdrant(collectionName, batchSize, offset = 0) {
  try {
    // Lấy thông tin bộ sưu tập
    const collectionInfo = await qdrantClient.getCollection(collectionName);
    
    // Cuộn qua các điểm
    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(`Lỗi khi lấy điểm từ Qdrant: ${error.message}`);
    return { points: [], nextOffset: null };
  }
}

// Tải lên vector đến Rememberizer
async function uploadToRememberizer(points) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const point of points) {
    // Trích xuất dữ liệu từ điểm Qdrant
    const pointId = point.id;
    const metadata = point.payload || {};
    const textContent = metadata.text || '';
    const documentName = metadata.filename || `qdrant_doc_${pointId}`;
    
    if (!textContent) {
      console.log(`Bỏ qua ${pointId} - không tìm thấy nội dung văn bản trong payload`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: textContent,
      // Tùy chọn: bao gồm thêm metadata
      metadata: metadata
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`Tài liệu '${documentName}' đã được tải lên thành công!`);
        results.push({ id: pointId, success: true });
      } else {
        console.error(`Lỗi khi tải lên tài liệu ${documentName}: ${response.statusText}`);
        results.push({ id: pointId, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`Lỗi khi tải lên tài liệu ${documentName}: ${error.message}`);
      results.push({ id: pointId, success: false, error: error.message });
    }
    
    // Thêm một khoảng thời gian nhỏ để ngăn chặn giới hạn tốc độ
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// Hàm di chuyển chính
async function migrateQdrantToRememberizer() {
  try {
    console.log('Bắt đầu di chuyển từ Qdrant sang 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(`Đã lấy ${points.length} điểm từ Qdrant`);
      
      const results = await uploadToRememberizer(points);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`Tiến độ: ${totalMigrated} điểm đã được di chuyển thành công`);
      
    } while (offset !== null);
    
    console.log(`Di chuyển hoàn tất! ${totalMigrated} tổng số điểm đã được di chuyển đến Rememberizer`);
    
  } catch (error) {
    console.error('Di chuyển thất bại:', error);
  }
}

// Chạy di chuyển
// migrateQdrantToRememberizer();
```

{% endtab %} {% endtabs %}

#### Di chuyển từ Supabase pgvector

Nếu bạn đã sử dụng Supabase với pgvector, việc di chuyển sang Rememberizer đặc biệt đơn giản vì cả hai đều sử dụng PostgreSQL với phần mở rộng pgvector.

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

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

# Tải biến môi trường
load_dotenv()

# Cấu hình PostgreSQL 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")

# Cấu hình Rememberizer
REMEMBERIZER_API_KEY = os.getenv("REMEMBERIZER_API_KEY")
VECTOR_STORE_ID = os.getenv("VECTOR_STORE_ID")  # ví dụ: "vs_abc123"
BASE_URL = "https://api.rememberizer.ai/api/v1"

# Kích thước lô để xử lý
BATCH_SIZE = 100

# Kết nối đến 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"Lỗi khi kết nối đến Supabase PostgreSQL: {e}")
        return None

# Lấy tài liệu từ Supabase pgvector
def fetch_documents_from_supabase(conn, batch_size, offset=0):
    try:
        cursor = conn.cursor()
        
        # Điều chỉnh truy vấn này dựa trên cấu trúc bảng của bạn
        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"Lỗi khi lấy tài liệu từ Supabase: {e}")
        return []

# Tải tài liệu lên 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
        
        # Phân tích metadata nếu nó được lưu dưới dạng chuỗi 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"Bỏ qua {doc_id} - không tìm thấy nội dung")
            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"Tài liệu '{document_name}' đã được tải lên thành công!")
                results.append({"id": doc_id, "success": True})
            else:
                print(f"Lỗi khi tải tài liệu {document_name}: {response.text}")
                results.append({"id": doc_id, "success": False, "error": response.text})
        except Exception as e:
            print(f"Ngoại lệ khi tải tài liệu {document_name}: {str(e)}")
            results.append({"id": doc_id, "success": False, "error": str(e)})
        
        # Thêm một khoảng thời gian nhỏ để ngăn chặn giới hạn tốc độ
        time.sleep(0.1)
    
    return results

# Chức năng di chuyển chính
def migrate_supabase_to_rememberizer():
    conn = connect_to_supabase()
    if not conn:
        print("Không thể kết nối với Supabase. Đang hủy di chuyển.")
        return
    
    offset = 0
    total_migrated = 0
    
    print("Bắt đầu di chuyển từ Supabase pgvector sang Rememberizer...")
    
    try:
        while True:
            documents = fetch_documents_from_supabase(conn, BATCH_SIZE, offset)
            
            if not documents:
                break
                
            print(f"Đã lấy {len(documents)} tài liệu từ 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"Tiến trình: {total_migrated} tài liệu đã di chuyển thành công")
            
            offset += BATCH_SIZE
            
    finally:
        conn.close()
    
    print(f"Di chuyển hoàn tất! {total_migrated} tài liệu đã được di chuyển sang Rememberizer")

# Chạy quá trình di chuyển
# migrate_supabase_to_rememberizer()
```

{% endtab %}

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

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

// Cấu hình 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';

// Cấu hình Rememberizer
const rememberizerApiKey = process.env.REMEMBERIZER_API_KEY;
const vectorStoreId = process.env.VECTOR_STORE_ID; // ví dụ: "vs_abc123"
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// Cấu hình kích thước lô
const BATCH_SIZE = 100;

// Lấy tài liệu từ pgvector Supabase
async function fetchDocumentsFromSupabase(batchSize, offset = 0) {
  try {
    // Điều chỉnh truy vấn này dựa trên cấu trúc bảng của bạn
    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(`Lỗi khi lấy tài liệu từ Supabase: ${error.message}`);
    return [];
  }
}

// Tải tài liệu lên Rememberizer
async function uploadToRememberizer(documents) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const doc of documents) {
    // Phân tích metadata nếu nó được lưu dưới dạng chuỗi 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(`Bỏ qua ${doc.id} - không tìm thấy nội dung`);
      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(`Tài liệu '${documentName}' đã được tải lên thành công!`);
        results.push({ id: doc.id, success: true });
      } else {
        console.error(`Lỗi khi tải tài liệu ${documentName}: ${response.statusText}`);
        results.push({ id: doc.id, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`Lỗi khi tải tài liệu ${documentName}: ${error.message}`);
      results.push({ id: doc.id, success: false, error: error.message });
    }
    
    // Thêm một khoảng thời gian nhỏ để tránh giới hạn tốc độ
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// Hàm di chuyển chính
async function migrateSupabaseToRememberizer() {
  try {
    console.log('Bắt đầu di chuyển từ Supabase pgvector sang Rememberizer...');
    
    let offset = 0;
    let totalMigrated = 0;
    
    while (true) {
      const documents = await fetchDocumentsFromSupabase(BATCH_SIZE, offset);
      
      if (documents.length === 0) {
        break;
      }
      
      console.log(`Đã lấy ${documents.length} tài liệu từ Supabase`);
      
      const results = await uploadToRememberizer(documents);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`Tiến độ: ${totalMigrated} tài liệu đã được di chuyển thành công`);
      
      offset += BATCH_SIZE;
    }
    
    console.log(`Di chuyển hoàn tất! ${totalMigrated} tài liệu đã được di chuyển đến Rememberizer`);
    
  } catch (error) {
    console.error('Di chuyển thất bại:', error);
  } finally {
    await supabasePool.end();
  }
}

// Chạy quá trình di chuyển
// migrateSupabaseToRememberizer();
```

{% endtab %}
{% endtabs %}

### Thực Hành Tốt Nhất Khi Di Chuyển

Hãy làm theo những khuyến nghị này để có một quá trình di chuyển thành công:

1. **Lập Kế Hoạch Trước**:
   * Ước lượng khối lượng dữ liệu và thời gian cần thiết cho việc di chuyển
   * Lên lịch di chuyển trong các khoảng thời gian có lưu lượng thấp
   * Tăng dung lượng ổ đĩa trước khi bắt đầu các cuộc di chuyển lớn
2. **Kiểm Tra Trước**:
   * Tạo một cửa hàng vector thử nghiệm trong Rememberizer
   * Di chuyển một tập hợp dữ liệu nhỏ (100-1000 vector)
   * Xác minh chức năng tìm kiếm với các truy vấn chính
3. **Xác Thực Dữ Liệu**:
   * So sánh số lượng tài liệu trước và sau khi di chuyển
   * Chạy các truy vấn chuẩn để đảm bảo kết quả tương tự
   * Xác thực rằng siêu dữ liệu được bảo tồn chính xác
4. **Tối Ưu Hiệu Suất**:
   * Sử dụng các thao tác theo lô để tăng hiệu quả
   * Cân nhắc việc đặt địa lý của cơ sở dữ liệu nguồn và đích
   * Giám sát giới hạn tỷ lệ API và điều chỉnh kích thước lô cho phù hợp
5. **Các Bước Sau Khi Di Chuyển**:
   * Xác minh việc tạo chỉ mục trong Rememberizer
   * Cập nhật cấu hình ứng dụng để trỏ đến cửa hàng vector mới
   * Giữ cơ sở dữ liệu nguồn như một bản sao lưu cho đến khi việc di chuyển được xác minh

Để tham khảo chi tiết về API và tài liệu điểm cuối, hãy truy cập trang [vector-store](https://docs.rememberizer.ai/vi/tai-nguyen-cho-nha-phat-trien/api-docs/vector-store "mention").

***

Hãy chắc chắn xử lý các khóa API một cách an toàn và tuân theo các thực hành tốt nhất cho việc quản lý khóa API.
