From 5d9abe4dc9b9b9724099abc4ba40b13e88e8e41d Mon Sep 17 00:00:00 2001 From: Sebastian Frank Date: Tue, 20 Oct 2026 01:44:30 +0000 Subject: [PATCH] Facetten zur Suche dokumentieren (tibi-server #38) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - abfragen-lesen: Abschnitt "Suchbewusste Facetten" (q/qName/qLimit, search-Block, Default-Fenster rrf.topK, 20000er-Deckel) - suche: topK-Default 500, q gilt auch für _count/_facet, zwei Fehlerbild-Zeilen - mcp-nutzen: documents_facet mit q/qName/qLimit - doku-ausbau: Vollständigkeitszeile ergänzt - Stempel auf tibi-server d0d699d --- plans/audit-report.json | 2 +- plans/doku-ausbau.md | 1 + src/content/docs/projekt/abfragen-lesen.mdx | 26 ++++++++++++++++++++- src/content/docs/projekt/mcp-nutzen.mdx | 6 +++-- src/content/docs/projekt/suche.mdx | 9 ++++--- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/plans/audit-report.json b/plans/audit-report.json index 08ed64d..1b1018e 100644 --- a/plans/audit-report.json +++ b/plans/audit-report.json @@ -1,5 +1,5 @@ { - "generatedAt": "2026-10-20T00:51:22.849Z", + "generatedAt": "2026-10-20T01:44:24.935Z", "stats": { "files": 70, "byDir": { diff --git a/plans/doku-ausbau.md b/plans/doku-ausbau.md index 204bd00..2dc9e6c 100644 --- a/plans/doku-ausbau.md +++ b/plans/doku-ausbau.md @@ -58,6 +58,7 @@ Jede Fähigkeit von tibi-server / tibi-admin braucht genau eine Dokustelle. Die | search (Textindex, RRF-Hybrid, ngram.stopwords, Regenerate) | projekt/suche (+ projekt/sammlungen-anlegen für Index-YAML) | ✅ | | embedding + vectorindex (inkl. Failover-Gruppen, Startprüfung/Quarantäne/Rückkehr, `goldenPath`, Status-Endpunkte) | server/konfiguration (Gruppen im Detail), server/betrieb (Status/Störungen), projekt/suche (Kurzüberblick) | ✅ | | rankfusion (RRF-Formel) | projekt/suche | ✅ | +| suchbewusste Facetten (`_facet` mit `q`/`qName`/`qLimit`, `search`-Block, `rrf.topK`-Default 500) | projekt/abfragen-lesen (+ projekt/suche) | ✅ | | permissions (public/user/token, Orgs/Teams-Matrix) | projekt/rechte-tokens | ✅ | | filecleanup (automatisch, keine Config-Fläche) | kein eigener Artikel — Einzeiler in server/betrieb prüfen (T-FINISH) | ⏳ | | cache (Hook-lokal) | projekt/hooks-schreiben (Kontext-Tabelle) | ✅ | diff --git a/src/content/docs/projekt/abfragen-lesen.mdx b/src/content/docs/projekt/abfragen-lesen.mdx index 6541c0a..6252e1b 100644 --- a/src/content/docs/projekt/abfragen-lesen.mdx +++ b/src/content/docs/projekt/abfragen-lesen.mdx @@ -104,9 +104,33 @@ Ein `lookup` löst nur auf, wenn der Zieldatensatz für dich lesbar ist — dazu | `GET …//_facet?facet=` | Werte zählen je Feld | `GET …/comment/_facet?facet=contentId` | | `…/_facet?facet=&limit=10` | Nur Top N | `GET …/comment/_facet?facet=contentId&limit=10` | | `…/_facet?facet=&includeEmpty=1` | Leere Werte mitzählen | `GET …/comment/_facet?facet=tags&includeEmpty=1` | +| `…/_facet?facet=&q=&qName=` | Werte **der Treffer** zählen | `GET …/productVariant/_facet?facet=brand&q=warme jacke&qName=combined` | Die Kommentar-Anzahl je Seite (`commentCount`) kommt aus so einer Abfrage über `contentId`. +### Suchbewusste Facetten + +`q` und `qName` gelten auch für `_facet`: Die Zählung bezieht sich dann auf die Trefferliste, nicht auf die ganze Sammlung. +Damit passt sich eine Filterseitenleiste der Suche an. + +| Parameter | Bedeutung | +|---|---| +| `q`, `qName` | Suchtext und Suchblock; gezählt werden nur noch die Treffer | +| `qLimit` | Zahl, `0` oder `all`: wie viele Treffer die Zählung abdeckt | + +```text title="Facetten zur Suche" +GET …/productVariant/_facet?facet=catalogProjection.brand&q=warme jacke&qName=combined +GET …/productVariant/_facet?facet=catalogProjection.brand&q=warme jacke&qName=combined&qLimit=all +``` + +- Ohne `qLimit` ist das Fenster so groß wie `rrf.topK` des Suchblocks (ohne Angabe 500, siehe [Suche](/projekt/suche/)) — also genau die Menge, die die Liste zeigt. +- `qLimit=all` (oder `qLimit=0`) zählt alle Treffer; der Server deckelt bei 20 000 IDs. `qLimit=` setzt das Fenster selbst. +- Ein größeres Fenster als `rrf.topK` liefert bewusst mehr Treffer als die Liste zeigt: die Summe der Facettenwerte ist dann größer als die Trefferzahl der Liste. +- Bei den filterbasierten Modi (`text`, `regex`, `ngram`, `eval`, `filter`) wird `qLimit` ignoriert — dort zählt der Filter ohnehin exakt. +- Nur bei den Modi `vector` und `combined` ergänzt die Antwort einen Block `search`, z. B. `{"mode":"combined","resolved":500,"limit":500,"truncated":true}`. `truncated: true` heißt: Fenster voll, weitere Treffer sind möglich — auch wenn es exakt aufgeht, denn der Server holt kein Extra-Dokument. +- Die Modi `text`, `regex`, `ngram`, `eval` und `filter` setzen `q` als MongoDB-Filter um. Dort ist die Zählung exakt und es gibt keinen `search`-Block. +- Ohne Treffer kommt eine leere Facetten-Antwort ohne Datenbankzugriff. + ## Aggregate: Rückwärts zählen und rechnen (Listen-Route!) `aggregate` hängt an der normalen `GET`-Liste — **kein** eigener Endpunkt wie `_count`/`_facet`. @@ -162,4 +186,4 @@ GET …/tag?q=hero | Leere Liste trotz Daten | `filter_public`-Hook filtert `active:true` + Zeitraum ([Rechte und Tokens](/projekt/rechte-tokens/)) | `active:true` setzen, `publication`-Fenster prüfen | | `_lookup` leer | Zieldatensatz nicht lesbar (meist `active:true` fehlt, siehe [Rechte und Tokens](/projekt/rechte-tokens/)) | Zieldatensatz prüfen, nicht die Abfrage | -Verifiziert am e3f92eb 2026-10-17 (tibi-svelte-starter), am 68b4278 2026-10-17 (tibi-server, collection_get/select/sort/facet/count/lookup), am 68b4278 2026-10-17 (tibi-server, aggregate: dbapi/aggregate.go, controller/collection_aggregate.go) +Verifiziert am e3f92eb 2026-10-17 (tibi-svelte-starter), am 68b4278 2026-10-17 (tibi-server, collection_get/select/sort/facet/count/lookup), am 68b4278 2026-10-17 (tibi-server, aggregate: dbapi/aggregate.go, controller/collection_aggregate.go), am d0d699d 2026-10-20 (tibi-server: collection_facet.go, collection_facet_search.go, rrf.topK-Default) diff --git a/src/content/docs/projekt/mcp-nutzen.mdx b/src/content/docs/projekt/mcp-nutzen.mdx index 4b88c65..d4b01cc 100644 --- a/src/content/docs/projekt/mcp-nutzen.mdx +++ b/src/content/docs/projekt/mcp-nutzen.mdx @@ -137,9 +137,11 @@ Fehler: ohne Leserecht am Ziel → 403 (`permission denied` bzw. Scope-Fehler). ### documents_facet — Werte je Feld zählen -Signatur: `namespace*`, `collection*`, `fields*`, optional `filter`, `extra`. Scope: `namespace...read`. Methode: `GET`. +Signatur: `namespace*`, `collection*`, `fields*`, optional `filter`, `q`, `qName`, `qLimit`, `extra`. Scope: `namespace...read`. Methode: `GET`. -`tools/call`: `{"name":"documents_facet","arguments":{"namespace": "", "collection": "content", "fields": "status"}}` +`tools/call`: `{"name":"documents_facet","arguments":{"namespace": "", "collection": "content", "fields": "status", "q": "kontakt", "qName": "combined"}}` + +Mit `q`/`qName` zählen die Werte nur über den Treffern der Suche; `qLimit` (Zahl oder `all`) weitet das Fenster über `rrf.topK` hinaus ([Lesen und suchen](/projekt/abfragen-lesen/)). Fehler: ohne `fields` → 400 (`missing required parameter: facet` auf Controller-Ebene). diff --git a/src/content/docs/projekt/suche.mdx b/src/content/docs/projekt/suche.mdx index f0b3706..27b4819 100644 --- a/src/content/docs/projekt/suche.mdx +++ b/src/content/docs/projekt/suche.mdx @@ -59,6 +59,7 @@ GET …/content?q=kontakt&qName=combined&qExplain=1 ``` - `q` ist der Suchtext, `qName` wählt den Block (ohne `qName` greift der Standard). +- `q` und `qName` gelten auch für `_count` und `_facet` — Facetten zählen dann nur die Treffer ([Lesen und suchen](/projekt/abfragen-lesen/)). - `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. @@ -70,7 +71,8 @@ GET …/content?q=kontakt&qName=combined&qExplain=1 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`). +- `topK: 100` begrenzt die Kandidaten je Quelle **und** kappt das Fusionsergebnis (`MergeRRF`). Ohne Angabe im `rrf`-Block gilt `topK: 500`. +- Das gekappte Fusionsergebnis ist die Treffermenge der Liste **und** das Standardfenster der Facetten (`_facet?q=…`). - 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. @@ -240,8 +242,9 @@ Zwei Dense-Speicherformen sind im Umlauf: BSON-Binary (aktuell) und ein Legacy-B | `X-Search-Memory: mongo(lookup)` / `mongo(aggregate)` / `mongo(hook-pipeline)` / `mongo(hook-filter)` | Anfrage nutzt Schritte oder einen Hook-Filter, die in der MongoDB-Pipeline laufen | Erwartetes Verhalten; ohne diese 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 | +| `?facet=` an der Liste wirkungslos | Facetten sind eine eigene Route (`…/_facet`) | `q`/`filter` dort mitgeben — [Lesen und suchen](/projekt/abfragen-lesen/) | +| Facettenzahlen kleiner als erwartet | Fenster ist `rrf.topK` (Default 500), nicht die ganze Sammlung | `?qLimit=all` an `_facet` setzen oder `topK` im `rrf`-Block erhöhen | 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 92c3ad74 2026-10-20 (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) +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 92c3ad74 2026-10-20 (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), am d0d699d 2026-10-20 (tibi-server: collection_facet_search.go, rrf.topK-Default 500, qLimit)