iPhoneで Grafanaの グラフを 参照できる アプリ Grafanizer 作ってます。 詳しくは こちらへ

全記事入りのJSONが必要なわけ

Hugoには「全文検索機能」や「似ている記事」の機能がついてないのだが、いろいろ調べてみるとなんとか実装出来そうなので試してみた。

参考:

全記事の内容を分かち書きして単語リストを作れば全文検索ができるし、単語リストから記事の特徴を表す単語を抽出して各文章を比較すれば似たような記事をリストアップ出来るだろうという考え。

で、それを行うには

  1. GitLabのビルド時に何らかの方法でデータを作っておく
  2. 全記事が入ったJSONを元にしてJSで機能を実装する

の二つが考えられる。

どちらにしてもJSが必要になるということでとりあえずは2の方で実装してみることに。記事が増えてきてどうしようも無くなったら1を実装すれば良いかなと。

ということで、とりあえずはHugoでJSONファイルを作成してみる。

作成するJSONの仕様

作成するJSONの内容については、

  • 結果から移動できるに「リンク先」
  • 結果を表示すると器用の「タイトル」
  • セクション別で処理を分けための「セクション」
  • タグと同じ単語の時に重みを変えるための「タグ」
  • 全文検索用の「本文」
  • ソートさせるための「日付」、
  • 結果表示のための「サマリー」

があれば希望する機能が実装できそうなので、以下の内容としてみた。

[{{ range $index, $page := .Site.Pages }}{{ if $index }},{{ end }}
  {
    "url": "{{ $page.Permalink }}",
    "title": "{{ $page.Title }}",
    "section": "{{ .Section }}",
    "tags": ["{{ if $page.Params.tags }}{{ delimit $page.Params.tags "\",\"" }}{{ else }}{{ end }}"],
    "body": "{{ lower (replace (replace (replace $page.Plain "\t" "") "\n" "") "\\" "") }}",
    "date": "{{ .Date.Format "Jan 2, 2006" }}",
    "summary": "{{ replace (replace (replace .Summary "\n" "") "\n" "") "\\" "" }}"
  }{{ end }}
]

ちなみに、この手のフォーマットの仕様としては

JSON API
A SPECIFICATION FOR BUILDING APIS IN JSON

http://jsonapi.org/

というものもあるみたいなので、今後の参考にしたい。

説明が欲しいのは、タグのところと本文(サマリー)のところかな。

tags

タグのところはちょっとめんどくさくて、タグがあれば "," で繋いで最後に "" で囲むという内容にしていて、見ての通りタグの指定がない場合でも空文字のタグが入ってしまう。

本来だったら空配列にしたいところなんだけど、記述が分かりづらくなるのとタグ無しの記事は殆ど無いのに対応は面倒ってことでこのような実装にしてある。

bodyとsummary

リスト表示用のindex.html用テンプレートで実装するっていうことで、テンプレートに渡される変数の中には本文がない。そこで非公開の変数 .Plain を利用する。 非公開の変数には .Plain.PlainWords があるようだが、.PlainWords はGoLangのスライスになっているためか replacelower などの関数が使えなかった。

また、JSON的にInvalid? な文字があるようなので置換している。これについてはうまくEscape出来る関数が欲しいところ。

ちなみに、replaceRE が使えないのはうちの環境だけ?

作成するパス

今回は「全文検索機能」と「似ている記事」機能の両方で使うことを考えているので、

  • /tools/search/ : 全文検索
  • /tools/related/ : 似ている記事

からアクセスするのが自然な /tools へ作成することにした。具体的には layouts/section/tools.html に「JSONの仕様」で紹介したテンプレートの内容を書いておく。

そうすることで、 content/tools/ があるとJSONファイルを作成するようになる。

お分かりのように文字列的にはJSONなのだが /tools/index.html でアクセスできるし、帰ってくるContent-Type的にも text/html なのでちょっと気持ちが悪い。

だが、AJAXで拾って来てJSON.parseすればい立派なJSONになるので細かいところは気にしないでおこうと思う。気になる人はGitLab.comのビルド時にhtmlからjsonに変更させてやれば良いかもしれない。

Hugo公式の対応

本来であればHugoで公式についても良さそうな機能であり、実際に 「Save data to "data/pages.json" #144」 でやり取りがある。

だけど、2014年からマイルストーンが先延ばし先延ばしになって現在はバージョン指定なしのFutureマイルストーンになっちゃったんで現時点ではあまり期待しないほうが良さそう。


これで、「全文検索」や「似ている記事」を実装する準備が整ったことになり、実際に searchrelated で機能を試すことが出来る。

こちらの実装方法についてはまた別の記事で紹介したいと思う。