Files
archivmail/features/PROJ-30-bleve-migration.md
T

133 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PROJ-30: Volltext-Index: Xapian → Manticore Search Migration
## Status: Deployed
**Created:** 2026-03-28
**Last Updated:** 2026-04-04
## Dependencies
- Requires: PROJ-5 (Speicherung & Indexierung) — bestehende Index-Abstraktion
- Requires: PROJ-21 (Multi-Tenancy) — per-Tenant Index-Isolation
## Motivation
Xapian erfordert CGO und `libxapian-dev` als System-Dependency. Das verhindert:
- Docker-Images (CGO-Build in Containern komplex, Build-Image groß)
- Einfache Cross-Compilation
- Reproduzierbare Builds ohne native Abhängigkeiten
**Entscheidung: Manticore Search** statt ursprünglich geplantem Bleve.
### Warum Manticore statt Bleve
Das primäre Kriterium ist **Datenmenge und Performance**, nicht Einfachheit. Manticore ist eine in C++ geschriebene Such-Engine (Fork von SphinxSearch) mit MySQL-kompatiblem Protokoll:
| Metrik | Bleve | Manticore |
|---|---|---|
| Suchlatenz bei 1M Docs | 50200ms | 520ms |
| Index-Durchsatz | ~5.000 Docs/s | ~50.000 Docs/s |
| RAM bei 10M Mails | 48 GB | 12 GB |
| Columnar Storage | Nein | Ja |
| Highlighting | Ja | Ja |
| Fuzzy-Search | Ja | Ja |
| CGO im Go-Code | Nein | Nein (MySQL-Protokoll) |
Manticore läuft als eigener Systemd-Service — kein embedded Mode. Der Trade-off (externer Dienst) ist bei Performance-Priorität gerechtfertigt.
Elasticsearch/OpenSearch wurden als Alternative geprüft — zu schwer, zu viel Infrastruktur für On-Premise.
## Architektur nach Migration
```
PostgreSQL
→ Metadaten: From, To, Subject, Date, message_id, tenant_id
→ Dedup, Audit-Log, User, Tenant, Labels
→ strukturierte Filter-Queries
Manticore Search (Port 9306, MySQL-Protokoll)
→ Volltext-Body + Anhang-Text
→ Ein Index pro Tenant (saubere Mandantentrennung)
→ Real-Time-Index (neue Mail sofort suchbar)
→ Highlighting in Suchergebnissen
→ BM25+ Relevanz-Ranking
Suchanfrage in Go:
→ PostgreSQL: filtert tenant_id, Datum, From/To → IDs
→ Manticore: Volltext-Relevanz über IDs → gerankte Ergebnisse
→ Merge in API-Handler
```
## User Stories
- Als Betreiber möchte ich archivmail ohne CGO kompilieren können (`CGO_ENABLED=0`).
- Als Nutzer möchte ich auch bei großen Archiven (>1M Mails) schnelle Suchergebnisse (<20ms).
- Als Nutzer möchte ich Treffer im Suchtext hervorgehoben sehen (Highlighting).
- Als Admin möchte ich nach einem Absturz den Index mit einem Kommando neu aufbauen können.
## Acceptance Criteria
- [x] Manticore läuft als Systemd-Service auf dem Server (Port 9306, nur localhost)
- [x] `internal/index/manticore.go` ersetzt `xapian.go` und `xapian_stub.go`
- [x] Gleiche Interface-Signatur (`IndexMail`, `Search`, `Delete`, `Close`)
- [x] Go-Integration via `go-sql-driver/mysql` (kein CGO)
- [x] Pro Tenant ein Manticore Real-Time-Index: `emails_tenant_{id}`
- [x] Indizierte Felder: `id`, `subject`, `from_addr`, `to_addr`, `body`, `attachment_names`, `date_ts`
- [x] Suchanfragen: Volltext, FROM:, TO:, SUBJECT:, SINCE:, BEFORE:
- [x] Migration-Kommando: `archivmail reindex` baut alle Tenant-Indizes neu auf
- [x] `CGO_ENABLED=0 go build` funktioniert nach Migration
- [x] Manticore-Port 9306 nur auf localhost gebunden (kein externer Zugriff)
- [x] `update.sh` prüft ob Manticore installiert ist und installiert es bei Bedarf
## Edge Cases
- Bestehender Xapian-Index wird NICHT automatisch migriert — `reindex` liest Roh-Mails aus Storage neu ein
- Während `reindex` läuft: Suche liefert unvollständige Ergebnisse (Warnung im Log)
- Manticore-Dienst nicht erreichbar → Suche gibt Fehler zurück, Metadaten-Suche (PostgreSQL) bleibt verfügbar
- Index beschädigt → `reindex` behebt, kein Datenverlust (Roh-Mails in Storage sind Source of Truth)
- Neuer Tenant → Index wird beim ersten Mail-Import automatisch angelegt (`CREATE TABLE IF NOT EXISTS`)
## Technical Requirements
- **Engine:** Manticore Search (GPLv2)
- **Protokoll:** MySQL-kompatibel, Port 9306
- **Go-Treiber:** `github.com/go-sql-driver/mysql`
- **CGO:** Nicht erforderlich im Go-Code
- **Index-Typ:** Real-Time Index pro Tenant
- **Installation:** Offizielles Manticore APT-Repository — Paket bleibt über `apt upgrade` aktuell
- **Systemd:** `manticore.service` läuft parallel zu `archivmail.service`
- **Konfiguration:** Neuer Abschnitt `manticore:` in `/etc/archivmail/config.yml`
```yaml
manticore:
dsn: "manticore@tcp(127.0.0.1:9306)/"
enabled: true
```
## Migration Path
```
1. Manticore-APT-Repo einrichten + Paket installieren:
curl -s https://repo.manticoresearch.com/manticore-repo.noarch.deb -o /tmp/manticore-repo.deb
dpkg -i /tmp/manticore-repo.deb && apt update && apt install -y manticore
# danach: apt upgrade hält Manticore automatisch aktuell
2. manticore.go implementieren (gleiche Interface wie xapian.go)
3. Build-Tag in xapian.go anpassen (beide parallel lauffähig während Entwicklung)
4. Integrations-Tests gegen Manticore
5. xapian.go + xapian_stub.go entfernen
6. `archivmail reindex` auf Server ausführen
7. Alten Xapian-Index-Ordner löschen (/var/archivmail/xapian/)
8. update.sh: Manticore-Installations-Check hinzufügen
```
## Implementation Notes
- `internal/index/manticore.go` — vollständige Implementierung mit `ManticoreTenantManager` + `manticoreIndex`
- `TenantIndexer`-Interface in `index.go` abstrahiert Manticore und Legacy-Xapian-Pfad
- Morphologie: `lemmatize_de_all,stem_en` (Manticore 25.0.0 — `stem_de` nicht verfügbar via MySQL-Protokoll)
- fnv64a-Hash leitet uint64-Row-ID aus SHA-256-Mail-ID ab
- `escapeManticoreMatch()` schützt vor Injection in MATCH()-Ausdrücke
- `cmd import` und `cmd import-piler` ebenfalls auf Manticore-Backend umgestellt
- Deployed auf 131 (bookworm) und 132 (trixie) — Manticore 25.0.0 (bookworm-Paket)
## Deployment
- 192.168.1.131: Manticore 25.0.0, 65 Mails indiziert
- 192.168.1.132: Manticore 25.0.0, 14.160 Mails indiziert