diff --git a/src/content/docs/projekt/audit-backup.mdx b/src/content/docs/projekt/audit-backup.mdx index 174a942..d363992 100644 --- a/src/content/docs/projekt/audit-backup.mdx +++ b/src/content/docs/projekt/audit-backup.mdx @@ -228,7 +228,7 @@ Backups sind der Voll-Export für Umzug und Desaster-Fall — im Admin unter `/p | Fortschritt | Ja (Stream) | Ja (SSE-Stream) | diff --git a/src/content/docs/projekt/suche.mdx b/src/content/docs/projekt/suche.mdx index ba95db9..ab63a9d 100644 --- a/src/content/docs/projekt/suche.mdx +++ b/src/content/docs/projekt/suche.mdx @@ -108,6 +108,62 @@ Alle Modi aus `collection.go:314` — `fields` gilt für `regex` und `ngram`, `v Aus Projektsicht musst du nichts einrichten — lass `autoRegenerate: true` in der YAML stehen, dann pflegen sich `fuzzy`- und `semantic`-Indizes selbst. Der Regenerate-Flow im tibi-admin (Test-Plan `41-search-index-status`) nutzt genau den Endpunkt aus Schritt 4. +## Performance-Optionen (Cache und In-Memory-Index) + +Beide Optionen sind **standardmäßig aus** und ändern ohne Konfiguration nichts. + +### Ergebnis-Cache für `combined` (`combinedCache`) + +Wiederholte Combined-Queries (Katalog-Filter, Blättern durch dieselbe Treffermenge) können die gemergte Rangliste kurzzeitig wiederverwenden: + +```yaml +search: + - name: combined + mode: combined + rrf: { k: 60, topK: 100, weights: { semantic: 1.5, fuzzy: 1.0 } } + combinedCache: + enabled: true # Default: false + ttl: 45s # Default: 45s + maxEntries: 1000 # LRU-Cap, Default: 1000 +``` + +- Gecacht werden nur die gemergten **IDs + Scores**; die Dokumente der Seite werden immer frisch geladen. +- Der Key enthält Query, Config, den effektiven Filter (inkl. Rollen-`preFilter` und Hook-Filter) und alle Fusionsparameter — Ergebnisse können nicht zwischen Rollen oder Sammlungen wandern. +- Aktiv: `X-Cache: HIT|MISS` im Response-Header. Bei `HIT` bleiben `X-Search-Sources`/`X-Search-Config` leer (es lief keine Subsearch). +- Grenzen: `ttl` kurz halten (≤30s bei mehreren Server-Instanzen, die Invalidierung ist node-lokal); nach einem Restore wird der Cache verworfen. + +### In-Memory-Index für `ngram` (`ngram.inMemory`) + +Für große Sammlungen kann der ngram-Anteil einer Combined-Suche aus dem RAM beantwortet werden statt aus MongoDB: + +```yaml +# Server-config.yml — globaler Schalter, ohne ihn passiert nichts +search: + inMemory: + enabled: true + maxMemoryMB: 1024 + +# Projekt-YAML +search: + - name: fuzzy + mode: ngram + fields: [title, context] + ngram: + sizes: [3] + queryFilter: { minMatchRatio: 0.4 } + inMemory: + enabled: true # Default: false + maxDocs: 150000 # mehr Dokumente → MongoDB + maxMemoryMB: 512 # Budget pro Index +``` + +- Gebaut wird der Index beim Projekt-(Re-)Load aus den **gespeicherten** `_search`-Ngrammen (nie aus den Quellfeldern), damit er nicht vom MongoDB-Pfad abweichen kann. +- Genutzt nur für ngram-Quellen von `combined`-Suchen, und nur wenn er fertig geladen und im Budget ist. Sonst — und immer bei Einzel-ngram-Suchen sowie `_count` — läuft die Suche über MongoDB. Der Debug-Header zeigt `inMemory=ram|mongo(loading)|mongo(budget)|mongo(candidates)`. +- Rollen-`preFilter`, `?filter=` und Hook-Filter gelten weiter: der Index liefert Kandidaten-IDs, die danach gegen den effektiven Filter geprüft werden. +- Schreibvorgänge (Anlegen/Ändern/Löschen/Bulk/Worker/Regenerate) halten den Index aktuell; **Snapshot- und Backup-Restore bauen alle In-Memory-Zustände neu auf** (Indizes + Cache) — alte Treffer können einen Restore nicht überleben. Während des Neuaufbaus laufen Suchen auf MongoDB. +- Budget-Abbruch (zu viele Dokumente, Speicher- oder RSS-Grenze) lässt den Index leer und dauerhaft auf MongoDB; ein Reload startet einen neuen Versuch. +- Gemessen (91k Dokumente, ~197 KB/Doc): Die ngram-Subsearch von „blauer pullover" fällt von ~1,3 s auf wenige Millisekunden, Einzelwort-Suchen von ~1,7 s auf 30–80 ms (jeweils vor dem Rollen-/Katalogfilter). + ## Was der Vektor-Pfad zusätzlich braucht - **Provider-Name:** `vector.provider` (z. B. `bge_m3`) muss mit einem Servernamen aus der Embedding-Registry übereinstimmen (`collection.go:377`) — sonst löst die Config nicht auf. Unbekannte Provider-Typen brechen ab, defekte einzelne Provider werden übersprungen (`registry.go:58-70`). @@ -125,8 +181,11 @@ Aus Projektsicht musst du nichts einrichten — lass `autoRegenerate: true` in d | `404 collection "…" not found` | Regenerate mit falschem `collection`-Namen | Namen gegen `api/collections/*.yml` prüfen | | Worker-Queue steht | Provider defekt oder überlastet | `search-worker/status` und `embedding/status` lesen, dann Regenerate mit `force: true` | | Suche über `tag`/`navigation` unscharf | `default` ist `regex`, kein Fuzzy | Erwartung anpassen oder `content`-Indexe nutzen | +| `inMemory=ram` erscheint nie im Debug-Header | Globaler Schalter aus, Config ohne `inMemory`, Index noch nicht fertig oder Budget-Abbruch | `search.inMemory.enabled`, `ngram.inMemory.enabled` prüfen, Reload, Budget-Logs lesen | +| Nach Restore kurz alte Treffer | Restore erfolgt, Index-Neuaufbau läuft noch | Warten bis `inMemory=ram` wieder erscheint (bis dahin MongoDB-Fallback) | +| Combined-Suche liefert kurz eine ältere Reihenfolge | `combinedCache` aktiv, TTL noch nicht abgelaufen | TTL senken oder Cache für kritische Daten abschalten | | `?facet=` an der Suche wirkungslos | Facetten sind eigene Route (`…/_facet`) | [Lesen und suchen](/projekt/abfragen-lesen/) beachten | Weiter: [Lesen und suchen](/projekt/abfragen-lesen/), [Sammlungen anlegen](/projekt/sammlungen-anlegen/), [Felder und Widgets](/projekt/felder-widgets/). -Verifiziert am e3f92eb 2026-10-14 (tibi-svelte-starter), am 68b4278 2026-10-15 (tibi-server, rankfusion), am 2b091d8 2026-10-13 (tibi-admin-nova, Test-Plan 41-search-index-status) +Verifiziert am e3f92eb 2026-10-14 (tibi-svelte-starter), am 68b4278 2026-10-15 (tibi-server, rankfusion), am 2b091d8 2026-10-13 (tibi-admin-nova, Test-Plan 41-search-index-status), am 63a2848c 2026-10-19 (tibi-server: combinedCache, ngram.inMemory, _count-Fast-Path, Restore-Rebuild) diff --git a/src/content/docs/server/konfiguration.mdx b/src/content/docs/server/konfiguration.mdx index 55fc17c..068a633 100644 --- a/src/content/docs/server/konfiguration.mdx +++ b/src/content/docs/server/konfiguration.mdx @@ -36,6 +36,7 @@ config.yml (Datei) < Umgebungsvariable (gewinnt immer) | `mcp` | `enabled`, `route`, `maxResultItems`, `allowAdminActions` | `MCP_ENABLED`, `MCP_ROUTE`, `MCP_MAX_RESULT_ITEMS`, `MCP_ALLOW_ADMIN_ACTIONS` | | `sentry` | `dsn`, `environment`, `serverName`, `enableTracing`, `debug` | keine — nur Datei | | `cors` | `allowOrigins`, `allowCredentials`, … | keine — wirksam ist die Projekt-/Collection-Ebene (siehe [Sicherheit](/server/sicherheit/)) | +| `search.inMemory` | `enabled`, `maxMemoryMB` (Kill-Switch + Budget für In-Memory-N-Gram-Indizes) | keine — nur Datei | | `llm` / `embedding` | Provider-Listen | dynamisch, siehe unten |