Spaces:
Running
Running
| -- 1. Enable Extension | |
| create extension if not exists vector; | |
| -- 2. Users Table | |
| create table if not exists users ( | |
| id uuid primary key default gen_random_uuid(), | |
| username text unique not null, | |
| password_hash text not null, | |
| created_at timestamp with time zone default timezone('utc'::text, now()) | |
| ); | |
| -- 3. Documents Table (Owner metadata) | |
| create table if not exists documents ( | |
| id uuid primary key default gen_random_uuid(), | |
| user_id uuid references users(id) on delete cascade, | |
| filename text not null, | |
| file_type text not null, | |
| chunk_strategy text default 'fixed', | |
| chunk_size int default 512, | |
| overlap int default 64, | |
| chunk_count int default 0, | |
| technique text default 'hybrid', | |
| status text default 'pending', -- pending, running, done, failed | |
| created_at timestamp with time zone default timezone('utc'::text, now()) | |
| ); | |
| -- 4. Chunks Table (Text + Metadata) | |
| create table if not exists chunks ( | |
| id uuid primary key default gen_random_uuid(), | |
| document_id uuid references documents(id) on delete cascade, | |
| user_id uuid references users(id) on delete cascade, | |
| text text not null, | |
| token_count int, | |
| page int, | |
| section text, | |
| chunk_index int, | |
| parent_chunk_id uuid, -- For parent-child technique | |
| text_hash text, -- For incremental ingestion | |
| metadata jsonb, -- For generic filtering | |
| created_at timestamp with time zone default timezone('utc'::text, now()) | |
| ); | |
| -- 5. Vectors Table | |
| create table if not exists chunk_vectors ( | |
| id uuid primary key default gen_random_uuid(), | |
| chunk_id uuid references chunks(id) on delete cascade, | |
| document_id uuid references documents(id) on delete cascade, | |
| user_id uuid references users(id) on delete cascade, | |
| embedding vector(1024), -- bge-m3 dimension | |
| created_at timestamp with time zone default timezone('utc'::text, now()) | |
| ); | |
| -- 6. ColBERT Token Vectors Table | |
| create table if not exists colbert_tokens ( | |
| id uuid primary key default gen_random_uuid(), | |
| chunk_id uuid references chunks(id) on delete cascade, | |
| document_id uuid references documents(id) on delete cascade, | |
| token_text text, | |
| token_index int, | |
| embedding vector(1024), | |
| created_at timestamp with time zone default timezone('utc'::text, now()) | |
| ); | |
| -- 7. Hybrid Search / Vector Similarity Function | |
| create or replace function match_chunks ( | |
| query_embedding vector(1024), | |
| match_document_id uuid, | |
| match_user_id uuid, | |
| match_count int, | |
| filter_chunk_ids uuid[] default null | |
| ) | |
| returns table ( | |
| id uuid, | |
| text text, | |
| source text, | |
| page int, | |
| section text, | |
| metadata jsonb, | |
| similarity float | |
| ) | |
| language plpgsql | |
| as $$ | |
| begin | |
| return query | |
| select | |
| c.id, | |
| c.text, | |
| d.filename as source, | |
| c.page, | |
| c.section, | |
| c.metadata, | |
| 1 - (cv.embedding <=> query_embedding) as similarity | |
| from chunk_vectors cv | |
| join chunks c on cv.chunk_id = c.id | |
| join documents d on c.document_id = d.id | |
| where c.document_id = match_document_id | |
| and c.user_id = match_user_id | |
| and (filter_chunk_ids is null or c.id = any(filter_chunk_ids)) | |
| order by cv.embedding <=> query_embedding | |
| limit match_count; | |
| end; | |
| $$; | |
| -- 8. Indexes for Metadata Filtering | |
| create index if not exists idx_chunks_metadata on chunks using gin (metadata); | |
| create index if not exists idx_chunks_user_doc on chunks (user_id, document_id); | |
| create index if not exists idx_vectors_doc on chunk_vectors (document_id); | |