Postgres: baza i tabela dla pgvektor – powiązanie z cakePHP 5

# Dodaj repozytorium PGDG (oficjalne repo PostgreSQL)

# sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
# wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -

# apt update

# apt install postgresql-18-pgvector

Klient posgres

# su - postgres
# psql

Sprawdź czy pgvector jest zainstalowany na Twoim serwerze:

> SELECT * FROM pg_available_extensions WHERE name = 'vector';

 name | default_version | installed_version | comment
--------+-----------------+-------------------+------------------------------
vector | 0.8.2 | 0.8.2 | vector data type and ivfflat and hnsw access methods

Utworzenie usera i bazy danych

> CREATE USER rag_user WITH PASSWORD 'silne_haslo_tutaj';

> CREATE DATABASE rag_db OWNER rag_user;

-- Połącz się z nową bazą
> \c rag_db

-- Zainstaluj rozszerzenie pgvector
> CREATE EXTENSION IF NOT EXISTS vector;

-- Nadaj uprawnienia
> GRANT ALL PRIVILEGES ON DATABASE rag_db TO rag_user; 
> GRANT ALL PRIVILEGES ON SCHEMA public   TO rag_user;

Tabela chunk-ów dokumentów

> CREATE TABLE document_chunks (
    id          BIGSERIAL PRIMARY KEY,
    brand_id    INTEGER       NOT NULL,
    source_type VARCHAR(50)   NOT NULL, -- 'invoice', 'project', 'faq', itp.
    source_id   INTEGER       NOT NULL, -- id rekordu w MariaDB
    chunk_index INTEGER       NOT NULL, -- numer fragmentu w dokumencie
    content     TEXT          NOT NULL, -- surowy tekst fragmentu
    embedding   vector(1536),           -- OpenAI text-embedding-3-small = 1536 wymiarów
    meta        JSONB,                  -- dowolne dodatkowe dane (numer faktury, data, itp.)
    created_at  TIMESTAMP     NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMP     NOT NULL DEFAULT NOW()
);

Indeksy

-- Indeks do szybkiego wyszukiwania wektorowego (cosine similarity)
> CREATE INDEX ON document_chunks USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

NOTICE: ivfflat index created with little data
DETAIL: This will cause low recall.
HINT: Drop the index until the table has more data.

-- Indeksy pomocnicze
> CREATE INDEX ON document_chunks (brand_id); 
> CREATE INDEX ON document_chunks (source_type, source_id);

Integracja PostgreSQL z CakePHP 5

// Ubuntu/Debian
# apt install php-pgsql

// sprawdź że jest aktywny
# php -m | grep pgsql

  pdo_pgsql
  pgsql

// Restart Apache
# systemctl restart apache2

Połączenie w config/app.php:

return [
    
    'Datasources' => [
        'default' => [
            'className' => Connection::class,
            'driver' => Mysql::class,
            'persistent' => false,
            'timezone' => 'UTC',
            ....
        ],
        'vector' => [
            'className' => Connection::class,
            'driver' => Postgres::class, 
            'persistent' => false,
            'encoding' => 'utf8', 
            'timezone' => 'UTC', 
        ],
    ],
];

Połączenie w config/app_local.php:

return [
    'Encryption' => [
        'key' => 'twój_klucz_base64',
    ],

    'Datasources' => [
        'default' => [
            'host'     => 'localhost',
            'username' => 'mariadb_user',
            'password' => 'mariadb_pass',
            'database' => 'twoja_aplikacja',
        ],
        'vector' => [
            'host'     => '127.0.0.1',
            'port'     => '5432',
            'username' => 'rag_user',
            'password' => 'silne_haslo_tutaj',
            'database' => 'rag_db',
        ],
    ],
];

Model DocumentChunksTable wskazujący na PostgreSQL:

namespace App\Model\Table;

use Cake\ORM\Table;

class DocumentChunksTable extends Table
{
    public static function defaultConnectionName(): string
    {
        return 'vector';
    }

    public function initialize(array $config): void
    {
        parent::initialize($config);

        $this->setTable('document_chunks');
        $this->setPrimaryKey('id');
        $this->addBehavior('Timestamp', [
            'events' => [
                'Model.beforeSave' => [
                    'created_at' => 'new',
                    'updated_at' => 'always',
                ],
            ],
        ]);
    }
}

Test połączenia — dodaj tymczasowo w dowolnym kontrolerze w akcji:

$conn   = \Cake\Datasource\ConnectionManager::get('vector');
$result = $conn->execute('SELECT version()')->fetch();
debug($result);
exit;