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

5.8 KiB
Raw Permalink Blame History

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

  • Manticore läuft als Systemd-Service auf dem Server (Port 9306, nur localhost)
  • internal/index/manticore.go ersetzt xapian.go und xapian_stub.go
  • Gleiche Interface-Signatur (IndexMail, Search, Delete, Close)
  • Go-Integration via go-sql-driver/mysql (kein CGO)
  • Pro Tenant ein Manticore Real-Time-Index: emails_tenant_{id}
  • Indizierte Felder: id, subject, from_addr, to_addr, body, attachment_names, date_ts
  • Suchanfragen: Volltext, FROM:, TO:, SUBJECT:, SINCE:, BEFORE:
  • Migration-Kommando: archivmail reindex baut alle Tenant-Indizes neu auf
  • CGO_ENABLED=0 go build funktioniert nach Migration
  • Manticore-Port 9306 nur auf localhost gebunden (kein externer Zugriff)
  • 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
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