> ## Documentation Index
> Fetch the complete documentation index at: https://docs.conare.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Search

> Führe Vektor-ANN-, BM25-Keyword- und chronologische Ranked-Branches über eine gefilterte Zeilenmenge aus – mit typisierter Filter-DSL und Per-Branch-top_k.

`POST /v1/namespaces/{ns}/search` führt bis zu drei gerankte Zweige über einer gefilterten Zeilenmenge aus. Alle Zweige sind optional; mindestens einer ist erforderlich. `label` und `filter` gelten für jeden Zweig.

```json theme={null}
{
  "label": "chunk",
  "filter": ["And", [["project", "Eq", "conare"], ["created_at_ms", "Gte", 1720000000000]]],
  "include_props": ["text", "created_at_ms"],
  "branches": {
    "vector":        {"embedding": [0.1, "..."], "top_k": 40},
    "keyword":       {"query": "raw query text", "top_k": 40},
    "chronological": {"attribute": "created_at_ms", "order": "desc", "top_k": 40}
  }
}
```

Response – eine unabhängige gerankte Liste pro Zweig, mit In-Server-Ausführungszeit:

```json theme={null}
{
  "vector":        {"hits": [{"id": "chunk-123", "score": 0.83}], "index": "ivf-rabitq", "server_us": 412},
  "keyword":       {"hits": [{"id": "chunk-9", "score": 14.2}], "mode": "and", "server_us": 200},
  "chronological": {"hits": [{"id": "chunk-7", "value": 1720000000000}], "server_us": 90}
}
```

## Filter

Zwei Formen werden akzeptiert:

* **Einzelne Gleichheit**: `{"property": "project", "value": "conare"}` – direkt aus den Posting-Listen bedient.
* **Array-DSL**: `[property, op, value]` mit `Eq`, `NotEq`, `Gt`, `Gte`, `Lt`, `Lte`, `In` (Array-Wert), kombinierbar mit `["And", [f1, f2, ...]]` / `["Or", [...]]` bis zu 16 Ebenen tief.

Der Vergleich ist typisiert: Zahlen vergleichen numerisch, Strings lexikografisch (Byte-Reihenfolge), Bools als `false < true`. Ein Typ-Mismatch oder eine fehlende Property matcht nichts – auch bei `NotEq` – und wirft nie einen Fehler. Unbekannte Operatoren, leere `And`-/`Or`-Listen und Nicht-Array-`In`-Werte ergeben `400` und nennen den Übeltäter.

## Vektor-Zweig

Scores sind **Kosinus-Ähnlichkeit auf L2-normalisierten Vektoren und stets exakt** – der ANN-Index (IVF + RaBitQ-1-Bit-Codes) erstellt eine Shortlist der Kandidaten und rerankt sie anschließend gegen Vektoren voller Präzision. Optionen:

| Feld         | Standard        | Bedeutung                                                                                                                                        |
| ------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `mode`       | `"auto"`        | `"auto"` wählt ANN vs. exakt anhand modellierter Kosten; `"exact"` erzwingt Brute Force; `"ann"` verlangt den Index (400, falls nicht vorhanden) |
| `nprobe`     | 7 % der Cluster | Probe-Cluster – erhöhen für Recall, senken für Latenz                                                                                            |
| `oversample` | 4               | Rerank-Tiefen-Multiplikator (`top_k × oversample` Kandidaten werden exakt rerankt)                                                               |

Gefilterte Vektorsuche liefert genau die ANN-Ergebnisse der passenden Teilmenge – die Engine erweitert das Probing, um die Selektivität auszugleichen, sodass Filter dich nicht heimlich Recall kosten.

**Determinismus:** Für einen fixen Indexzustand liefern identische Query-Bytes mit identischen Knöpfen bytegleiche Trefferlisten – bei beliebiger Thread-Zahl oder Nebenläufigkeit. Im Hintergrund spielt ein kontinuierlicher Sampler \~1 % der ANN-Queries gegen die Brute-Force-Wahrheit ab und veröffentlicht den Recall; der credential-freie `GET /recall-slo`-Endpunkt meldet die Recall-Gesundheit der Flotte.

## Keyword-Zweig

BM25 (`k1=1.2`, `b=0.75`) über die `text`-Property. Tokenizer: kleinschreiben, an jedem nicht-alphanumerischen Zeichen splitten – kein Stemming, keine Stoppwörter (Wort-Tokenizer-Parität mit Turbopuffer).

`match` steuert die Token-Kombination:

* `"auto"` (Standard) – alle Tokens erforderlich; ergibt das weniger als `max(5, top_k/8)` Treffer, nochmal als Any-Token versuchen. Die Response meldet, welcher Modus lief (`"mode": "and"` / `"or"`).
* `"all"` – jedes Token erforderlich.
* `"any"` – gewöhnliches disjunktives BM25.

## Chronologischer Zweig

Ranked nach beliebiger Integer-Property, `asc` oder `desc` – der günstige „neueste zuerst"-Schenkel einer Hybrid-Query.

## Properties projizieren

`include_props` steuert, was pro Treffer mitgeschickt wird: weglassen für nur id+score (keine Zusatzkosten), ein Name-Array übergeben, um nur diese Keys zu projizieren, oder `true` für die vollständige Property-Map. Projektion bedeutet, dass ein Reranker Treffer ohne zweiten Lookup-Roundtrip verarbeiten kann.

## Turbopuffer-kompatibler Shim

`POST /v2/namespaces/{ns}/query` akzeptiert die Turbopuffer-Read-Form – `{rank_by, filters, top_k, include_attributes}` – und gibt `{"rows": [{"id", "$dist", ...}]}` zurück, wobei `$dist` die Kosinus-Distanz ist. `rank_by: ["id", "asc"]` mit `filters: ["id", "Gt", cursor]` liefert Cursor-Pagination/-Export. Nicht unterstützte Formen sind explizite `400`s, die das Feld nennen – nie eine still veränderte Query.
