Meilisearch Dokumentenstruktur

jb_alvarado

Lieutenant
Registriert
Sep. 2015
Beiträge
617
Guten Morgen an Alle!

Ich wollte eure Meinung zu folgendem Sachverhalt wissen:

Hintergrund
ich arbeite für einen gemeinnützigen Verein und wir betreiben ein Internet TV, sowie eine Mediathek. Inhalt sind hauptsächlich christliche Vorträge.

Wir würden uns gerne in Sachen Barrierefreiheit verbessern und Untertitel anbieten. Da wir nicht die Manpower haben, alles selbst zu betiteln, machen wir das mit faster_whisper, ist nicht ganz fehlerfrei aber funktioniert erstaunlich gut. Zu den Untertiteln möchte ich die Texte auch in eine Datenbank schreiben, um so nach Inhalten suchen zu können.

Sachverhalt
Bei Tests habe ich von ca. 1500 Videos (ist ca. 1/5 von der Gesamtmenge) die Untertitel in eine Postgresql Datenbank geschrieben, im Format:

Code:
id | media_id | start | end | text

Dabei hatte meine Tabelle am Ende ~120MB. Eine Volltextsuche ohne Index hat daraufhin ~8 Sekunden gedauert. Mit Index 4 Sekunden.

Mein Gedanke war nun, dass ich die Volltextsuche nach Meilisearch verlagere, weil ich damit in der Vergangenheit gute Erfahrung gemacht habe. Auch bietet es experimentell AI-Search an, was für die Zukunft sicher noch interessant werden könnte. (Elastic Search ist mir zu groß und würde ich gerne drauf verzichten.)

Ich frage mich nun, wie ich die Dokumente aufbauen soll. Soll ich weiterhin pro Zeitstempel und Textzeile ein Dokument anlegen, oder soll ich pro Untertiteldatei ein Dokument anlegen, in diesem Format:

JSON:
{
  "id": 1,
  "media_id": 12,
  "filename": "subtitle_file.vtt",
  "hash": "abc123hash",
  "language": "de",
  "subtitles": [
    {
      "start": "00:00:10,000",
      "end": "00:00:12,000",
      "text": "Hello, world!"
    },
    {
      "start": "00:00:13,000",
      "end": "00:00:15,000",
      "text": "This is a test."
    }
  ]
}

Man sagt ja, dass kleinere Dokumente effizienter zu verarbeiten sind, allerdings bin ich mir nicht ganz sicher von welcher Größe bei "kleinen Dokumenten" gesprochen wird. Ein Vortrag von einer Stunden und 50 Minuten hat um die 3000 Zeilen Text und 180kb Dateigröße. Ist das noch klein?

Wenn ich nur ein Dokument pro Video anlegen würde, wäre es von meinem Verständnis her auch einfacher, später per AI-Search nach sinnhaften Ergebnissen zu suchen, weil man dann ja den ganzen Zusammenhang hat. Ob so die Möglichkeit bestehen bleibt, dass man die genaue zeitliche Position bestimmen kann, weiß ich leider noch nicht, schön wäre es.

Wie würdet ihr hier vorgehen? Macht es Sinn pro Untertiteldatei ein Dokument anzulegen, oder lieber doch pro Untertitelzeile?
 
Disclaimer: Ich bin kein Experte für Volltextsuche oder Meilisearch.

Ich halte eine Datei pro Zeitsegment für viel zu kleinteilig. Mir bekannte Dokumentendatenbanken kommen mit 200 kB für ein Dokument locker klar. Das entspricht auch meinem Verständnis vom einem Dokument - der bisherige Ansatz müsste ja auch erst wieder zusammengeführt werden.

Das was du als Datenbank einsetzen willst ist tendenziell eher ArangoDB / MongoDB oder ähnliches.
 
Hast Du PostgreSQLs Volltextsuche verwendet, oder einfache Queries?

Bezüglich Dokumentgröße: ich denke, man wird vor allem Suchergebnisse haben wollen, bei denen die Worte im selben Satz oder zumindest nah beieinander auftreten. Keine Ahnung, ob Meilisearch das liefern kann, wenn das komplette Video ein Dokument ist. Umgekehrt könnte natürlich ein einzelner Text zu wenig sein, so dass die Begriffe in zwei aufeinanderfolgenden Texten nicht gefunden werden.
 
Zuletzt bearbeitet:
@H4110
Die Frage bzgl der Volltextsuche ist allerdings berechtigt.

Ich find die Suchperformance vom Bauchgefühl generell langsam. Ich hab in Postgres schon eine Tabelle gebaut, wo man über ein Textfeld suchen kann. Da sind etwa 100.000.000 Einträge drin und es dauert, wenn die DB ordentlich cached, vielleicht 1 Sekunde.

Es wird jedoch nicht vergleichbar sein. Die Texte sind vlt höchstens 10-20 Wörter lang, man kann es zeitlich einschränken und es gibt keine Losgröße 1 d.h. ein Index hilft sinnvoll bei der Vorfilterung.
 
Danke für euren Input!

@andy_0, ich habe Postgres eh schon in Einsatz, darüber läuft die ganze Verwaltung der Videos inklusive TV Programmplanung. Daher war mein Gedanke es dort auch mal mit der Volltextsuche zu probieren, weil ich so auch gleiche meine Tabellen miteinander in relation setzen kann. Eine zweite Datenbank kommt nur in Frage, wenn sie etwas bieten kann, was Postgres nicht kann, oder nicht für die spezielle Aufgabe optimiert ist. Wie z.B. Volltextsuche.

@H4110, ja ich habe die Postgres Volltextsuche getest, mit dieser Abfrage:

SQL:
SELECT ms.id, ms.media_id, ms.start, ms.end, ms.media_id, ms.text,
    ts_rank_cd(to_tsvector('german', unaccent(ms.text)), websearch_to_tsquery('german', 'offenbarung 13')) AS score
FROM media_subtitles ms
where to_tsvector('german', unaccent(ms.text)) @@ websearch_to_tsquery('german', 'offenbarung 13')
ORDER BY score DESC;

Ohne score Feld ist es auch nicht schneller. Aktuell sind 893599 Einträge in der Tabelle, was ja eigentlich noch nicht soviel sind, gerade wenn ich das mit der Zahl vergleiche die @andy_0 erwähnt hat.

Bezüglich Meilisearch werde ich das einfach mal mit Daten füttern und testen.

Ob jetzt pro Untertitel ein Dokument, oder pro Video, bin ich mir immer noch unschlüssig. Ich fände es schön, wenn man allgemein suchen könnte, in welchem Video über etwas gesprochen wurde, aber praktisch wäre auch speziell suchen zu können, wann in einem bestimmten Video was gesagt wurde. Wobei ersteres wichtiger ist.
 
Ich würde mal den hier beschriebenen Ansatz mit einer generierten Spalte für den TSVector probieren.

Also so:
SQL:
ALTER TABLE media_subtitles
 ADD COLUMN text_tsvector tsvector
  GENERATED ALWAYS AS (to_tsvector('german', unaccent(text))) STORED;

CREATE INDEX index_media_subtitles_text_tsvector ON media_subtitles USING gin (text_tsvector);
 
SELECT ms.id, ms.media_id, ms.start, ms.end, ms.media_id, ms.text,
    ts_rank_cd(ms.text_tsvector, websearch_to_tsquery('german', 'offenbarung 13')) AS score
FROM media_subtitles ms
WHERE ms.text_tsvector @@ websearch_to_tsquery('german', 'offenbarung 13')
ORDER BY score DESC;

Ich habe am Wochenende selbst erstmalig die Volltextsuche ausprobiert, weil ich das eh noch auf der TODO-Liste hatte. In meinem Fall erst einmal nur Suche in Titel + Kurztitel, ca. 11400 Zeilen.

Ohne Index und generierte Spalte ca. 50 ms. Mit Index auf den Ausdruck to_tsvector signifikant weniger, manchmal so schnell wie mit generierter Spalte, aber schwankend. Mit generierter Spalte immer unter 0,5 ms.

Keine Ahnung, wie PostgreSQL da intern genau funktioniert, aber vielleicht spielt die Zeit für die Ausführung von to_tsvector und unaccent im Query eine nicht unwesentliche Rolle.
 
H4110 schrieb:
Ich würde mal den hier beschriebenen Ansatz mit einer generierten Spalte für den TSVector probieren.
Krass... Habe das jetzt gemacht: 2062489 Einträge insgesamt (Tabellengröße 385MB), Suche dauert ~4ms.

Dann werde ich wohl doch bei Postgres bleiben.
 
  • Gefällt mir
Reaktionen: andy_0 und H4110
Zurück
Oben