|
6 | 6 | from functools import lru_cache
|
7 | 7 | from hashlib import sha256
|
8 | 8 | from pathlib import Path
|
9 |
| -from typing import Any |
| 9 | +from typing import Any, cast |
10 | 10 | from xml.sax.saxutils import escape
|
11 | 11 |
|
12 | 12 | import numpy as np
|
13 | 13 | from markdown_it import MarkdownIt
|
| 14 | +from packaging import version |
| 15 | +from packaging.version import Version |
14 | 16 | from pydantic import ConfigDict
|
15 | 17 | from sqlalchemy.engine import Engine, make_url
|
16 | 18 | from sqlmodel import JSON, Column, Field, Relationship, Session, SQLModel, create_engine, text
|
@@ -310,6 +312,18 @@ def from_chunks(
|
310 | 312 | )
|
311 | 313 |
|
312 | 314 |
|
| 315 | +def _pgvector_version(session: Session) -> Version: |
| 316 | + try: |
| 317 | + result = session.execute( |
| 318 | + text("SELECT extversion FROM pg_extension WHERE extname = 'vector'") |
| 319 | + ) |
| 320 | + pgvector_version = version.parse(cast(str, result.scalar_one())) |
| 321 | + except Exception as e: |
| 322 | + error_message = "Unable to parse pgvector version, is pgvector installed?" |
| 323 | + raise ValueError(error_message) from e |
| 324 | + return pgvector_version |
| 325 | + |
| 326 | + |
313 | 327 | @lru_cache(maxsize=1)
|
314 | 328 | def create_database_engine(config: RAGLiteConfig | None = None) -> Engine:
|
315 | 329 | """Create a database engine and initialize it."""
|
@@ -358,17 +372,19 @@ def create_database_engine(config: RAGLiteConfig | None = None) -> Engine:
|
358 | 372 | CREATE INDEX IF NOT EXISTS keyword_search_chunk_index ON chunk USING GIN (to_tsvector('simple', body));
|
359 | 373 | """)
|
360 | 374 | )
|
361 |
| - session.execute( |
362 |
| - text(f""" |
| 375 | + create_vector_index_sql = f""" |
363 | 376 | CREATE INDEX IF NOT EXISTS vector_search_chunk_index ON chunk_embedding
|
364 | 377 | USING hnsw (
|
365 | 378 | (embedding::halfvec({embedding_dim}))
|
366 | 379 | halfvec_{metrics[config.vector_search_index_metric]}_ops
|
367 | 380 | );
|
368 | 381 | SET hnsw.ef_search = {20 * 4 * 8};
|
369 |
| - SET hnsw.iterative_scan = {'relaxed_order' if config.reranker else 'strict_order'}; |
370 |
| - """) |
371 |
| - ) |
| 382 | + """ |
| 383 | + # Enable iterative scan for pgvector v0.8.0 and up. |
| 384 | + pgvector_version = _pgvector_version(session) |
| 385 | + if pgvector_version and pgvector_version >= version.parse("0.8.0"): |
| 386 | + create_vector_index_sql += f"\nSET hnsw.iterative_scan = {'relaxed_order' if config.reranker else 'strict_order'};" |
| 387 | + session.execute(text(create_vector_index_sql)) |
372 | 388 | session.commit()
|
373 | 389 | elif db_backend == "sqlite":
|
374 | 390 | # Create a virtual table for keyword search on the chunk table.
|
|
0 commit comments