248 lines
20 KiB
Plaintext
248 lines
20 KiB
Plaintext
---
|
||
title: 'Suche'
|
||
description: 'Textindex, search-Blöcke, Hybrid-Suche, Neuaufbau des Index aus Projektsicht.'
|
||
---
|
||
|
||
import { Aside, Steps } from '@astrojs/starlight/components';
|
||
|
||
Die Suche läuft über `search`-Blöcke in der Sammlungs-YAML plus Abfrage per `q` und `qName`.
|
||
Suchbegriffe: Volltextsuche, Hybrid-Suche, Suchindex neu aufbauen.
|
||
|
||
## Index anlegen
|
||
|
||
`content.yml` definiert drei Indexe:
|
||
|
||
| Index | Schlüssel | Zweck |
|
||
|---|---|---|
|
||
| `content_text` | `$text:$**`, `defaultLanguage: none` | Volltext über alle Felder |
|
||
| `path_lang` | `path` + `lang`, unique | Pfad je Sprache eindeutig |
|
||
| `translation` | `translationKey` + `lang`, unique | Übersetzung je Sprache eindeutig |
|
||
|
||
`navigation.yml` und `medialib.yml` nutzen nur einen `default`-Index im Modus `regex` (kein Textindex nötig).
|
||
|
||
## search-Blöcke
|
||
|
||
```yaml title="content.yml — search-Blöcke (gekürzt)"
|
||
# content.yml — search (gekürzt)
|
||
search:
|
||
- name: combined # Hybrid aus semantic + fuzzy
|
||
mode: combined
|
||
rrf: { k: 60, topK: 100, weights: { semantic: 1.5, fuzzy: 1.0 } }
|
||
- name: fuzzy
|
||
mode: ngram
|
||
autoRegenerate: true
|
||
fields: [name, path, meta.title, meta.description, blocks.headline, blocks.subline,
|
||
blocks.text, blocks.items.title, blocks.items.text, blocks.items.question, blocks.items.answer]
|
||
- name: semantic
|
||
mode: vector
|
||
autoRegenerate: true
|
||
fields: [name, meta.title, meta.description, blocks.headline, blocks.subline,
|
||
blocks.text, blocks.items.title, blocks.items.text, blocks.items.question, blocks.items.answer]
|
||
vector: { provider: bge_m3 }
|
||
```
|
||
|
||
| `qName` | Sammlung | Modus |
|
||
|---|---|---|
|
||
| `combined` | `content` | Hybrid (RRF aus `semantic` + `fuzzy`) |
|
||
| `fuzzy` | `content` | n-gram, fehlertolerant |
|
||
| `semantic` | `content` | Vektor (`bge_m3`) |
|
||
| `default` | `tag`, `navigation`, `comment`, `medialib` | regex |
|
||
|
||
## Lesen mit q
|
||
|
||
Grundlagen (Filter, Lookup, Facetten) stehen unter [Lesen und suchen](/projekt/abfragen-lesen/). Hier nur die Suche:
|
||
|
||
```text title="Suche per q und qName"
|
||
GET …/content?q=kontakt&qName=combined
|
||
GET …/tag?q=hero
|
||
GET …/content?q=kontakt&qName=combined&qExplain=1
|
||
```
|
||
|
||
- `q` ist der Suchtext, `qName` wählt den Block (ohne `qName` greift der Standard).
|
||
- `qExplain=1` zeigt die Gewichtung — nützlich beim Debuggen.
|
||
- Suche mit und ohne `lookup` testen: `?q=…&qName=combined&lookup=blocks.heroImage.image:medialib,blocks.image:medialib` löst Treffer-Bilder gleich auf.
|
||
|
||
## Hybrid-Kurzüberblick
|
||
|
||
`combined` mischt Vektor- und n-gram-Treffer per Reciprocal Rank Fusion (`internal/rankfusion`, tibi-server):
|
||
|
||
```text title="RRF-Formel (combined)"
|
||
score(doc) += weight / (k + rank) # k = 60, weights: semantic 1.5, fuzzy 1.0
|
||
```
|
||
|
||
- `topK: 100` begrenzt die Kandidaten je Quelle **und** kappt das Fusionsergebnis (`MergeRRF`).
|
||
- Weitere Strategien (`score_rrf`, `score_sum`, `rank_score`, `hybrid`), Normierung (`minmax`, `zscore`), Gewichte (`scoreWeight`) und Quellen-Config (`sourceConfig`) existieren im Code **und** sind als `rrf`-Block in der Projekt-YAML einstellbar — aus Projektsicht reicht `combined` mit den Starter-Gewichten.
|
||
- Alte Score-Beispiele aus Erzähl-Docs nicht übernehmen — nur diese Formel gilt.
|
||
|
||
## Suchmodi im Überblick
|
||
|
||
Alle Modi aus `collection.go:314` — `fields` gilt für `regex` und `ngram`, `vector.provider` muss auf einen Server-Provider zeigen (`collection.go:377`):
|
||
|
||
| Modus | Einsatzfall | Braucht Index/Aufbau |
|
||
|---|---|---|
|
||
| `text` | MongoDB-Volltext, eine Textstelle pro Sammlung | Ja — Mongo-Textindex (`hasTextIndex`; nur **ein** Textindex je Sammlung) |
|
||
| `regex` | Einfache Teilübereinstimmung (`default`-Block in `tag`, `navigation`, `comment`, `medialib`) | Nein — läuft direkt auf den Feldern, kein Aufbau, keine Queue |
|
||
| `eval` | Eigene JS-Bewertung pro Treffer (`eval`-Ausdruck) | Nein — Ausdruck läuft zur Abfragezeit, optional `score.expr` |
|
||
| `filter` | Feste MongoDB-Filtervorlage mit `$subst` | Nein — Filter zur Abfragezeit, optional `score.expr` |
|
||
| `ngram` | Fehlertolerante Teilwortsuche (Starter-`fuzzy`) | Ja — `_search`-Anreicherung mit `autoRegenerate`, Queue bis zum Worker-Lauf |
|
||
| `vector` | Semantische Suche (Starter-`semantic`, Provider `bge_m3`) | Ja — Embeddings über Embedding-Provider, Queue bis zum Worker-Lauf |
|
||
| `combined` | Hybrid aus mehreren Blöcken (Starter-`combined` = RRF aus `semantic` + `fuzzy`) | Je beteiligtem Block (siehe oben); Fusion selbst braucht keinen eigenen Index |
|
||
|
||
<Aside type="note">
|
||
`qName` wählt den Block, `q` liefert den Suchtext. Ohne `qName` greift der erste Block der Sammlung. `text`, `eval` und `filter` kommen im Starter nicht vor — dort zählen `regex` (kein Aufbau), `ngram`/`vector` (Aufbau nötig) und `combined` (Fusion).
|
||
</Aside>
|
||
|
||
## Index aufbauen und prüfen
|
||
|
||
<Steps>
|
||
|
||
1. Bearbeite Einträge normal — `fuzzy` und `semantic` haben `autoRegenerate: true` und bauen sich selbst nach.
|
||
2. Beobachte im tibi-admin den Hinweis `SearchIndexBuildNotice`: Er erscheint im Projekt-Header (Summe offener `_queue`-Einträge aller `ngram`-/`vector`-Sammlungen) und im Sammlungs-Header der betroffenen Sammlung.
|
||
3. Warte, bis der Hinweis nach dem nächsten Polling von selbst verschwindet (`_queue` = 0). Der `regex`-Modus (`default`) hat keine Queue und keinen Hinweis.
|
||
4. Bleibt die Queue stehen oder hast du die Config geändert: `POST /_/:project/_/admin/regenerate-search` aufrufen — optional mit Body `{ collection, modes, names, ids, filter, force }` (`admin_regenerate_search.go:17-25`). Mit `?async=1` nur einreihen und sofort antworten (`{"message": "queued", …}`), ohne `filter` auch synchron möglich. Ungültige IDs ohne einzige gültige Hex-ID brechen mit `400 no valid document IDs in request` ab.
|
||
5. Status prüfen: `GET /_/:project/_/admin/search-worker/status` zeigt pro Provider Aktiv-Flag, Queue-Tiefe, laufenden Job und Fortschrittszähler (`admin_search_status.go:10-15`). Auth jeweils: Scope `project.regenerate-search` plus Token-Flag `AllowRegenerateSearch`.
|
||
|
||
</Steps>
|
||
|
||
<Aside type="note" title="Neuaufbau aus Sicht des Projekts">
|
||
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.
|
||
</Aside>
|
||
|
||
## Stoppwörter für `ngram` (`ngram.stopwords`)
|
||
|
||
Füllwörter wie „zum", „der" oder „für" treffen in einer n-gram-Suche jeden Text, in dem sie irgendwo vorkommen — auch Beschreibungen, in denen sie nichts aussagen. `ngram.stopwords` entfernt sie aus **beiden** Seiten: aus den gespeicherten N-Grammen und aus der Suchanfrage. Einseitig wäre falsch: stehen gebliebene Stoppwort-N-Gramme blähen die Ähnlichkeitswerte auf und drücken die Unterschiede zwischen relevanten und irrelevanten Treffern zusammen.
|
||
|
||
```yaml title="Projekt-YAML — Stoppwörter für fuzzy"
|
||
search:
|
||
- name: fuzzy
|
||
mode: ngram
|
||
fields: [name, meta.title, meta.description]
|
||
ngram:
|
||
sizes: [2, 3]
|
||
stopwords:
|
||
presets: [de] # de, en, fr, es, it
|
||
words: [zum, zur] # optionale Ergänzungen, werden gemerged
|
||
```
|
||
|
||
- Die Presets enthalten reine Funktionswörter: Artikel, Pronomen, Präpositionen, Konjunktionen, Hilfsverben und bedeutungsfreie Adverbien (`internal/utils/ngram_stopwords.go`). Negationswörter wie „nicht" oder „kein" bleiben bewusst draußen — „nicht wasserdicht" würde sonst zur Suche nach „wasserdicht".
|
||
- Einträge werden mit derselben Normalisiererkette gebildet wie Dokumente und Anfragen. Ohne `normalize`-Block laufen alle Zusatznormalisierer, aus „für" wird `fuer`; nur mit `normalize.use: []` bleibt es beim Standard-Normalisierer und damit bei `fur`. Einträge, die nicht genau ein Wort ergeben, erzeugen einen Projekt-Fehler (`internal/models/collection_setup.go`).
|
||
- `stopwords` gilt nur für `mode: ngram`. Ein Block mit anderem Modus und gesetzten Stoppwörtern erzeugt einen Projekt-Fehler; das Projekt lädt trotzdem, die Stoppwörter bleiben in diesem Fall aber aus.
|
||
- Ein Set gilt für den ganzen Block, nicht je Sprache: Es wirkt auf jedes Wort in den konfigurierten Feldern. Bei gemischtsprachigen Inhalten lieber `words` statt Presets nutzen oder einen Block je Sprache anlegen — sonst verschwinden Wörter der falschen Sprache (etwa `car`/`or` aus deutschen Texten, wenn `fr` aktiv ist). `words` ergänzt das Set nur; ein Preset-Wort lässt sich damit nicht wieder freistellen.
|
||
- Eine Anfrage, die nur aus Stoppwörtern besteht (oder nur aus Begriffen kürzer als jede konfigurierte Größe), liefert **null Treffer** statt der ganzen Sammlung (`internal/utils/ngram.go`).
|
||
|
||
### Nach Änderungen neu aufbauen
|
||
|
||
`ngram.stopwords` ist Teil des Anreicherungs-Hashs. Hinzufügen ist unkritisch: Die Anfrage verwirft die Wörter, die Dokumente bleiben über ihre übrigen Begriffe auffindbar. Scores können bis zum Neuaufbau abweichen, weil Kreuz-Wort-N-Gramme ohne die Stoppwort-Lücke neu entstehen. **Entfernen** braucht den Neuaufbau zuerst — sonst liefern diese Wörter null Treffer, bis jedes Dokument neu angereichert ist:
|
||
|
||
<Steps>
|
||
|
||
1. `stopwords` in der Projekt-YAML ändern und das Projekt neu laden.
|
||
2. `POST /_/:project/_/admin/regenerate-search` mit `{ collection, modes: ["ngram"] }` aufrufen — oder `autoRegenerate: true` setzen und den Reload abwarten.
|
||
3. `GET /_/:project/:collection/_queue` beobachten, bis der Zähler 0 ist. Erst danach die alten Wörter aus der Suche nehmen.
|
||
|
||
</Steps>
|
||
|
||
<Aside type="note">
|
||
Mehrere Server-Instanzen brauchen dieselbe Konfiguration: Ein Knoten ohne (oder mit anderen) Stoppwörtern schreibt einen anderen Config-Hash, markiert die Dokumente der anderen Knoten als veraltet und die `_queue` läuft nie leer.
|
||
|
||
Ein Server-Update ohne `stopwords`-Konfiguration ändert nichts: Configs ohne Stoppwörter behalten ihren bisherigen Hash und werden nicht neu aufgebaut. Während ein Neuaufbau läuft, kann ein In-Memory-Index noch N-Gramme nicht regenerierter Dokumente halten; die Treffer nähern sich mit dem Fortschritt an, ein Projekt-Reload baut den Index neu auf.
|
||
</Aside>
|
||
|
||
## 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).
|
||
- Schreibvorgänge, die einen In-Memory-Index (Vektor oder Ngram) verändern, invalidieren den Cache sofort (der Mutationszähler des Index steckt im Key); die `ttl` ist die Obergrenze für Änderungen, die noch nicht im Index stehen. Nach einem Restore wird der Cache verworfen.
|
||
- Grenzen: `ttl` kurz halten (≤30s bei mehreren Server-Instanzen, die Invalidierung ist node-lokal).
|
||
|
||
### 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 wird er für ngram-Quellen von `combined`-Suchen **und für Einzel-ngram-Suchen** — dort ersetzt er nur das Ranking, die Seitendokumente werden anschließend per `_id` geladen (Projektion, `lookup` und Aggregation bleiben also nutzbar). Bei `combined` zeigt der Debug-Header `inMemory=ram|mongo(loading)|mongo(budget)|mongo(candidates)|mongo(no-terms)`; `mongo(no-terms)` erscheint nur, wenn für die Quelle überhaupt ein In-Memory-Index existiert.
|
||
- Einzel-ngram-Suchen fallen mit `X-Search-Debug: true` im Kopf `X-Search-Memory` sichtbar auf MongoDB zurück, wenn der Index nicht bereit ist oder die Anfrage etwas braucht, das der Index nicht garantieren kann: `mongo(disabled)`, `mongo(loading)`, `mongo(budget)`, `mongo(count)` (bei `?count=1`), `mongo(sort)` (bei eigenem `?sort=`), `mongo(no-terms)` — sowie `mongo(lookup)`, `mongo(aggregate)` und `mongo(hook-pipeline)`, wenn die Anfrage Schritte braucht, die in der MongoDB-Pipeline laufen. Ein `pipelineMod` aus einem Read-Hook stört den RAM-Pfad nur, wenn er die Ergebnismenge ändern kann (`$match`, `$sort`, `$group`, `$project`, …), Stufen vor die bestehende Pipeline setzt oder `_id`/`_search` schreibt bzw. `$_search` liest. Reine angehängte Feld-Transformationen (`$addFields`, `$set`, `$unset`) laufen auf der geladenen Seite nach der Projektion und bleiben im RAM.
|
||
- 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): Die ngram-Subsearch von „blauer pullover" fällt von ~1,3 s auf wenige Millisekunden; Einzelwort-Suchen von ~1,4–4,9 s auf 85–158 ms. Das kompakte Index-Layout kostet ≈155 MB statt ≈1,15 GB und lädt in ≈2,7 s.
|
||
- Der 20000er-Kandidaten-Cap gilt nur für `combined` (dort auf Roh-Kandidaten). Einzel-ngram-Suchen prüfen nur so viele Kandidaten in Rangfolge, wie die Seite braucht (Blöcke à 500 `_id`s).
|
||
|
||
## Vektor-Index: Laden, Speicher, Altformate
|
||
|
||
Der Vektor-Index wird beim Projekt-Start im Hintergrund aufgebaut; bis dahin liefern Suchen Teilergebnisse. Für 91k Dokumente mit 1024 Dimensionen liegt der Load bei ~14 s (count-balancierte `_id`-Bereiche, parallel dekodiert) und der Speicher bei ~690 MB pro Config und Sprache. Die Sparse-Suche ist mit dem kompakten Layout von ~190 ms auf ~4 ms gefallen, Dense bleibt bei ~5 ms (parallel über die Kerne).
|
||
|
||
Zwei Dense-Speicherformen sind im Umlauf: BSON-Binary (aktuell) und ein Legacy-Byte-Array (4× größer, ~5× langsamer beim Laden). Der Server liest beide; für Altbestände gibt es im Server-Repo `tools/vectormigrate` (erst `-dry-run`, danach Projekt neu laden). Ein MongoDB-Fallback existiert nicht: fehlt der Index, bricht die Vektor-Suche mit einem klaren Fehler ab.
|
||
|
||
## 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`).
|
||
- **Gesundheit prüfen:** `GET /_/:project/_/admin/embedding/status` zeigt Gruppen-/Mitglieder-Gesundheit (an diesem Scope sind Fehlertexte redigiert, nur Zustände und Zähler; Volldetail nur am Server-Endpunkt `GET /api/v1/admin/embedding/status`, `admin_embedding_status.go:49-72`).
|
||
- **Feinheiten (optional):** `documentPrefix`/`queryPrefix`, `overflow: truncate` (Standard) oder `chunk` mit `chunkSize` (Standard 512) und `chunkOverlap` (Standard 50) — `collection.go:376-383`.
|
||
- **Debug:** Mit Header `X-Search-Debug: true` antwortet die Suche mit `X-Search-Config`, `X-Search-Timing` und `X-Search-Sources` (Treffer-/Score-Spannen je Quelle, `search_debug.go:145-159`).
|
||
|
||
## Fehlerbilder
|
||
|
||
| Symptom | Ursache | Lösung |
|
||
|---|---|---|
|
||
| Leere Scores / keine Treffer trotz Daten | Index fehlt oder `_queue` noch > 0 | Hinweis im Admin abwarten, dann erneut suchen |
|
||
| `combined` findet nichts, `fuzzy` schon | Vektor-Anteil ohne Embeddings | `semantic`-Felder und Provider (`bge_m3`) prüfen |
|
||
| `400 no valid document IDs in request` | Regenerate mit nur ungültigen `ids` | Hex-IDs prüfen oder `ids` weglassen (Vollaufbau) |
|
||
| `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 |
|
||
| Suche mit einem einzelnen Füllwort liefert nichts | `ngram.stopwords` verwirft das Wort aus der Anfrage | Inhaltliches Wort suchen; soll das Wort suchbar bleiben, das Preset weglassen und das Set nur über `words` bauen |
|
||
| Ein entferntes Stoppwort liefert weiterhin nichts | Neuaufbau nach dem Entfernen fehlt oder läuft noch | `regenerate-search` anstoßen, `_queue` auf 0 warten |
|
||
| `mongo(no-terms)` in `X-Search-Sources` | Combined-Quelle ohne verwertbare Terme (nur Stoppwörter oder zu kurze Begriffe) | Kein Fehler — Anfrage präzisieren |
|
||
| `X-Search-Memory: mongo(disabled)` bei jeder Suche | In-Memory-Index nicht aktiviert oder nicht geladen | `search.inMemory.enabled` und `ngram.inMemory.enabled` prüfen, Projekt neu laden |
|
||
| `X-Search-Memory: mongo(budget)` | Index-Load über dem Budget abgebrochen (Doc-Anzahl, Speicher oder RSS) | Budget erhöhen oder Collection kleiner halten; Loader-Log lesen |
|
||
| `X-Search-Memory: mongo(sort)` / `mongo(count)` | Eigenes `?sort=` bzw. `?count=1` — der Index kann das nicht garantieren | Erwartetes Verhalten; ohne `sort`/`count` messen |
|
||
| `X-Search-Memory: mongo(lookup)` / `mongo(aggregate)` / `mongo(hook-pipeline)` | Anfrage nutzt Schritte, die in der MongoDB-Pipeline laufen | Erwartetes Verhalten; ohne `lookup`/`aggregate`-Parameter messen |
|
||
| 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), am 63a2848 2026-10-19 (tibi-server: combinedCache, ngram.inMemory, _count-Fast-Path, Restore-Rebuild), am 76f1336 2026-10-19 (tibi-server: ngram.stopwords, Regenerate-Endpunkt, mongo(no-terms)); am 2a8922eb 2026-10-19 (tibi-server: kompakter ngramindex, collection_ngram_search.go, Hook-Pipeline-Klassifikation, X-Search-Memory), am 654b568 2026-10-19 (tibi-server: kompakter Sparse-Vektorindex, Legacy-Dense-Format, MemoryEstimate, vectormigrate, paralleler Range-Loader inkl. Retry/Semaphore), am 9e12a8e 2026-10-19 (tibi-types: ngram.stopwords/queryFilter/inMemory im Schema), am 21472bd 2026-10-19 (tibi-types: ngram.sizes 2–10, combinedCache im Schema), am cf44cd7 2026-10-19 (tibi-svelte-starter: tibi-types-Submodul auf 21472bd)
|