luplo.core.search.pipeline ========================== .. py:module:: luplo.core.search.pipeline .. autoapi-nested-parse:: Full search pipeline: parse → glossary expand → tsquery → optional rerank. Vector is **ranking only, never primary search**. tsquery does retrieval; vectors reorder the candidates by semantic similarity. If the embedding backend is null (default), reranking is skipped entirely. The query dialect (phrases, OR, negation) is parsed by :func:`luplo.core.search.tsquery.parse_user_query`. Glossary expansion is applied only to required and OR-group terms — phrases and negated terms pass through literally. Functions --------- .. autoapisummary:: luplo.core.search.pipeline.search Module Contents --------------- .. py:function:: search(conn: psycopg.AsyncConnection[Any], query: str, project_id: str, *, embedding_backend: luplo.core.embedding.EmbeddingBackend | None = None, item_types: list[str] | None = None, system_ids: list[str] | None = None, limit: int = 10, tsquery: str | None = None) -> list[luplo.core.models.SearchResult] :async: Run the full search pipeline. 1. **Glossary expand** — ``"vendor"`` → ``"(vendor | shop | NPC벤더)"``. 2. **tsquery retrieval** — GIN index scan, ``ts_rank`` scoring. Over-fetches ``limit * 3`` candidates for reranking headroom. 3. **Vector rerank** (optional) — if *embedding_backend* is provided and is not ``NullEmbedding``, rerank candidates by cosine similarity. Otherwise return tsquery results as-is. :param conn: Async psycopg connection. :param query: Raw user query string (simple-dialect: word, "phrase", OR, -negation). Glossary expanded. Ignored when *tsquery* is set. :param project_id: Project scope. :param embedding_backend: Embedding backend for reranking (default null). :param item_types: Filter by item types (e.g. ``["decision", "knowledge"]``). :param system_ids: Filter by system membership. :param limit: Maximum results to return. :param tsquery: Optional escape hatch — a raw PostgreSQL ``to_tsquery`` expression (e.g. ``"(inventory | 인벤토리) & slot & !deprecated"``). When set, *query* and glossary expansion are bypassed and the string is passed directly to ``to_tsquery('simple', …)``. Caller is responsible for synonym coverage and valid syntax. A malformed expression raises ``InvalidTsquery``. :returns: Ranked list of ``SearchResult`` objects.