Darstellung: Inline-Code-Chips fuer Dark Mode, 58 Seiten auf .mdx (Komponenten rendern jetzt)
Befund 1 (Nutzer): Inline-Code war im Dark Mode kaum lesbar.
- src/styles/custom.css: eigene Chip-Farben (--tibi-inline-*), Rahmen, nowrap in der ersten Tabellenspalte
- gemessen: Text/Chip 10,2:1 dunkel, 12,4:1 hell
Befund 2 (beim Nachmessen gefunden): 58 Seiten waren .md - Starlight-Komponenten wurden NICHT gerendert
(rohe <Aside>/<Steps>-Tags, import-Zeile als sichtbarer Text auf 57 Seiten).
- alle 58 Seiten auf .mdx umgestellt und MDX-konform gemacht (Imports, Block-Tags in eigenen Zeilen,
HTML-Kommentare -> {/* */}, geschweifte Klammern escaped)
- nachher: 428 Asides, 87 Steps, 158 Tab-Gruppen gerendert, 0 geleakte Imports
- fehlender Import in reference/hooks-daten ergaenzt
Regressionsschutz: audit-docs.mjs prueft jetzt Komponente-ohne-Import, .md-mit-Komponente,
geleakte Imports und rohe Tags im gebauten dist/. AGENTS.md 3 dokumentiert die .mdx-Regel.
Nebenfund: de.json mit ASCII-Umschreibungen -> Issue tibi-admin-nova #6
Build: 71 Seiten gruen, Audit 7 legitime Platzhalter-Marker
This commit is contained in:
1 parent
06c5f0d8ea
commit
dcdb6ee637
64 files changed
+246
-104
No files matched your search
@@ -0,0 +1,132 @@
|
||||
---
|
||||
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>
|
||||
|
||||
## 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 |
|
||||
| `?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)
|
||||
Reference in new issue
Block a user