Zoeken (Typesense)
Full-text search is een optionele module (search/, package app.ister.search), gedreven door
Typesense. Zie het zoekflow-diagram.
Runtime-toggle, geen bean-condition
De enabled-vlag (app.ister.typesense.enabled) wordt op runtime in de handlers gecheckt — bij
disabled worden indexevents geconsumeerd en genegeerd, zoals de TMDB-key-check. Het is bewust
niet @ConditionalOnProperty: bean-conditions worden bij de GraalVM native-image build bevroren,
dus een conditionele bean zou volledig uit het productie-image gebakken worden (hoofdstuk
8). Het properties-bestand van de module wordt geïmporteerd via
spring.config.import en heeft daarom een entry nodig in
search/src/main/resources/META-INF/native-image/resource-config.json.
Index-updates
Alles loopt via SEARCH_INDEX_REQUESTED (entityType, entityId, action), afgehandeld door
HandleSearchIndexRequested, dat de entiteit laadt, naar een document mapt en dat upsert (of
verwijdert) in de collection achter de media-alias.
Verzenders:
- Creatie komt gratis mee:
ServerEventService.createXFoundEventstuurt bij creatie een indexevent voor elk doorzoekbaar entiteitstype (movie, show, episode, person, album, track). - Verrijkings-handlers sturen na hun metadata-saves:
MetadataSave(TMDB), de worker-HandlePersonFound/HandleAlbumFound(MusicBrainz),PersonLookupService(TMDB-cast),HandleNfoFileFoundenHandleAudioFileFound(audio-tags, inclusiefaction=DELETEbij track-dedup). - Deletes: elke code die een doorzoekbare entiteit verwijdert moet
serverEventService.createSearchDeleteEvent(...)aanroepen. Er zijn vangnetten — de upsert-handler verwijdert het document als de entiteit niet meer bestaat, en een reindex bouwt alles opnieuw op — maar deze regel houdt de index correct tússen reindexen in.
Volledige reindex
De GraphQL-mutation reindexSearch stuurt SEARCH_REINDEX_REQUESTED. De handler maakt een verse
collection (media_v<timestamp>), pagineert door alle entiteiten en importeert ze, en zet dan de
alias om en dropt oude collections — zoeken blijft live tijdens de rebuild.
Meertalig schema
Het collection-schema en de query_by-lijst worden gegenereerd uit LanguageProperties.tags():
elke geconfigureerde taal krijgt title_<tag>-, description_<tag>- en genre_<tag>-velden met de
bijpassende Typesense-locale. SearchDocument is een Map<String,Object> in plaats van een vast
record, precies zodat de gelokaliseerde keys dynamisch blijven.
Omdat het schema vastligt bij het aanmaken van de collection, kost een taal toevoegen twee
stappen: een re-scan/analyze (om de nieuwe MetadataEntity-rijen aan te maken, zie hoofdstuk
3) gevolgd door reindexSearch.
Query'en
De GraphQL-query search(term) bevraagt Typesense over alle gelokaliseerde velden en geeft een
SearchResult-union terug die uit PostgreSQL gehydrateerd wordt — Typesense bepaalt alleen welke
ids matchen; de gezaghebbende data komt altijd uit de database.