Suchindex mit GoHugo für Meilisearch erstellen

Meilisearch bietet neben ElasticSearch und Solr eine schlanke Alternative zur Suche. Die Konfiguration und Einbindung werde ich ggf. in weiteren Beiträgen erläutern.

Für die Suche können mehrere Suchindexe definiert werden. Diese basieren auf Dokumenten. Ich habe ausprobiert diesen Index direkt beim Generieren der Seite mit GoHugo zu erzeugen.

Format Konfigurieren link

In der Konfiguration von GoHugo können outputs und outputFormats definiert werden. Wenn diese nicht gesetzt sind, werden HTML und RSS als Standard verwendet. Eine Liste aller verfügbaren Typen und Standardformate ist in der [Hugo Dokumentation] (https://gohugo.io/templates/output-formats/) zu finden.

Zuerst definiere ich ein eigenes Format als outputFormat. Dieses wird jeweils in einem Unterordner /search ausgegeben. Bei Verwendung des Languages-Moduls ist der Pfad z.B. /de/search.

# config.yaml
outputFormats:
  Meilisearch:
    name: meilisearch
    baseName: all
    isPlainText: true
    mediaType: application/json
    notAlternative: true
    path: search

Als nächstes muss definiert werden, welche Seitentypen wie gerendert werden sollen. Die Idee meines Ansatzes ist es, nur die Startseite als Suchindex zu rendern. GoHugo stellt den gesamten Inhalt zur Verfügung. Es wäre auch möglich, Seiten, Artikel, Begriffe und Taxonomien einzeln zu rendern, aber diese müssten alle einzeln an Meilisearch zurückgeschickt werden.

Die anderen Seiten werden weiterhin in den Standardformaten (HTML, RSS) generiert, sofern in der Liste nicht anders angegeben.

# config.yaml
outputs:
  home:
    - HTML
    - Meilisearch

Layout Templates link

Für das eigene Ausgabeformat habe ich ein eigenes Template erstellt. Die Config-Einstellungen name: meilisearch und der mediaType: application/json erwarten eine Template-Datei layouts/_default/home.meilisearch.json. Mit home steuere ich, dass nur die Startseite in einer einzelnen Datei gerendert wird.

Um ein korrektes JSON-Dokument zu erzeugen, darf hinter dem letzten Eintrag kein Komma stehen. Dies wird mit einem Trick erreicht.

[{{ range $pageIndex, $page := (where .Site.Pages "Type" "in" (slice "article" "glossar")) -}}
{{- if $pageIndex }},{{ end }}
  {
    "_kind": "{{ $page.Kind }}",
    "_type": "{{ $page.Type }}",
    "url": "{{ $page.Permalink }}",
    "id": "{{ $page.File.UniqueID }}",
    "language": "{{ $page.Language }}",
    "content": {{ (strings.Replace $page.Plain "\n" " ") | htmlUnescape | jsonify }}
  }
  {{- end }}
]

Mit dem Slice (slice "Artikel" "Glossar") kann definiert werden, welche Artikeltypen eingebunden werden sollen. Der Typ kann im FontMatter der Markdown-Dateien mit type festgelegt werden.

Für den Content wird .Plain verwendet. Diese Variable enthält den Inhalt ohne HTML oder Markup für Überschriften. Sonderzeichen sind HTML escaped. Mit htmlUnescape werden sie wieder in normale Zeichen umgewandelt. Mit jsonify wird aus dem String ein JSON-String, inklusive Escape von JSON-Befehlszeichen wie ".

Wenn dem Dokument übergeordnete Rubriken zugeordnet werden sollen, ist dies ebenfalls sehr einfach möglich.

[{{ range $pageIndex, $page := (where .Site.Pages "Type" "in" (slice "article" "glossar")) -}}
{{- if $pageIndex }},{{ end }}
  {
    ...
    "id": "{{ $page.File.UniqueID }}",
    "sections": [
      {{- range $i, $e := after 1 $page.Ancestors.Reverse -}}
      {{- if $i }},{{ end }}
      {
        "title": "{{ $e.LinkTitle }}",
        "url": "{{ $e.Permalink }}"
      }
      {{- end }}
    ],
    "language": "{{ $page.Language }}",
    ...
  }
  {{- end }}
]

Für jede Seite sind die übergeordneten Rubriken in der Variable .Ancestors enthalten. Mit after 1 wird der erste Eintrag übersprungen, da dies die Startseite ist.

Tags link

Tags, Kategorien oder andere Parameter aus dem FontMatter können wie Rubriken hinzugefügt werden.

[{{ range $pageIndex, $page := (where .Site.Pages "Type" "in" (slice "article" "glossar")) -}}
{{- if $pageIndex }},{{ end }}
  {
    ...
    "id": "{{ $page.File.UniqueID }}",
    "tags": [
      {{- range $i, $e := $page.Params.Tags -}}
        {{- if $i -}}, {{ end -}}
        "{{$e}}"
      {{- end -}}
    ],
    "language": "{{ $page.Language }}",
    ...
  }
  {{- end }}
]