uni-3 log

    Search by

    hugoで作ったblogにalgoliaで全文検索機能を追加する

    作ったページのコンテンツに対して検索をかける機能がほしかったので、algoliaのフリープランを使って全文検索できるページを追加した

    index 用の json を生成

    参考サイトのとおりに作った

    config.tomlに以下を追加

    [outputFormats.Algolia]
      baseName = "algolia"
      isPlainText = true
      mediaType = "application/json"
      notAlternative = true
    [params.algolia]
      vars = ["title", "summary", "content", "date", "publishdate", "description", "permalink", "keywords"]
      params = ["tags", "categories"]
    
    [outputs]
    home = ["HTML", "RSS", "Algolia"]
    
    # hugo v0.6以降はデフォルトでhtmlが表示されないためこちらの設定が必要
    [markup.goldmark.renderer]
    unsafe = true

    出力する json のテンプレートは hugo のCustom Output Formatsを用いて行う

    以下の設定を入れている

    https://blog.piyo.tech/posts/2018-04-07-hugo-search-index/ より

    本文を全部含めてしまうと Algolia の 1 データあたりのデータ上限を超えてしまうので、content は.Plain を 2000 文字で truncate するようにしました。また、サムネイルもを含めるようにしました

    毎回全てのページを更新すると面倒なので、多分 30 日以内に作成した記事のみ json に出力している

    後で作成する search ページを入れたくなかったので title が search のページを除外している

    ./src/layouts/_default/list.algolia.json

    として以下を作成

    {{/* Generates a valid Algolia search index */}}
    {{- $.Scratch.Add "index" slice -}}
    {{- $section := $.Site.GetPage "section" .Section }}
    {{- range .Site.AllPages -}}
      {{- $delta := now.Sub .Date -}}
      {{- if or (and (.IsDescendant $section) (and (not .Draft) (not .Params.private))) $section.IsHome -}}
      {{- if (le $delta.Hours 720) -}}
      {{- if (and (eq .Kind "page") (ne .Title "search")) -}}
        {{- $.Scratch.Add "index" (dict "objectID" .UniqueID "date" .Date.UTC.Unix "description" .Description "dir" .Dir "expirydate" .ExpiryDate.UTC.Unix "fuzzywordcount" .FuzzyWordCount "keywords" .Keywords "kind" .Kind "lang" .Lang "lastmod" .Lastmod.UTC.Unix "permalink" .Permalink "publishdate" .PublishDate "readingtime" .ReadingTime "relpermalink" .RelPermalink "summary" .Summary "title" .Title "type" .Type "url" .URL "weight" .Weight "wordcount" .WordCount "section" .Section "tags" .Params.Tags "categories" .Params.Categories "authors" .Params.Authors "content" (.Content | truncate 3000))}}
      {{- end -}}
      {{- end -}}
      {{- end -}}
    {{- end -}}
    {{- $.Scratch.Get "index" | jsonify -}}

    これでhugo serverにてビルドしたときにpublic/algolia.jsonに index 登録用の json が出力される。

    生成した json を index に登録

    手動でやるならば、algolia のダッシュボードに行き、 該当する index にて、json ファイルをアップロードすれば良い

    自動更新用に、node.js でレコード登録用スクリプト作成

    しかし、更新したときに自動でalgolia.jsonを登録したい。このblogはnetlifyに自動デプロイ用のトリガーを設定しているため

    ビルドに成功したら生成される json ファイルを登録するバッチ処理が走るように設定する

    https://www.algolia.com/doc/api-reference/api-methods/add-objects/ を参考に作る

    npm init
    
    npm install --save algoliasearch
    npm install --save dotenv

    変数の管理は.envで行う

    APP_ID=xxxx
    API_KEY=xxxx
    INDEX_NAME=xxxx
    var algoliasearch = require("algoliasearch")
    require("dotenv").config()
    
    // apiKey need addObject acl
    const appId = process.env.APP_ID
    const apiKey = process.env.API_KEY
    const indexName = process.env.INDEX_NAME
    
    const records = require("../src/public/algolia.json")
    
    var client = algoliasearch(appId, apiKey)
    var index = client.initIndex(indexName)
    
    var res = index.addObjects(records)

    netlify.tomlを編集して hugo コマンドで build した後に node スクリプトを実行する

    [build]
    publish = "./src/public"
    command = "hugo --gc --minify -s ./src --baseUrl='https://blog.uni-3.app' && cd ./algolia && npm install && node main.js""

    のように&&でつなげるだけ

    search 用ページ作成

    参考ページの通りにやっている

    instantsearch.jsを使う。cdnのコードを適当な html へコピペする

    hugo コマンドでsearch.mdを作成。コンテンツ一覧に出さないよう、showPaginationfalseにしておく

    ---
    title: "search"
    date: 2019-01-02T18:49:06Z
    showPagination: false
    ---
    
    <div id="search-box">
    </div>
    
    <ul id="hits">
    </ul>
    
    <div id="pagination">
    </div>
    
    <script>
    // instantSearchを初期化
    var search = instantsearch({
      appId: 'X30EJUS2IA',
      apiKey: '791937af7891a84d16eae4f9176bb7aa',
      indexName: 'prod_blog',
      urlSync: false
    });
    search.addWidget(
      instantsearch.widgets.searchBox({
        container: '#search-box',
       placeholder: 'serch pages',
       poweredBy: true
      })
    );
    search.addWidget(
      instantsearch.widgets.hits({
        container: '#hits',
        templates: {
          empty: 'not found',
          item: '<li><code>{{ dateString }}</code> <a href="{{permalink}}">{{ title }}</a></li>'
        }
      })
    );
    
    search.addWidget(
      instantsearch.widgets.pagination({
        container: '#pagination',
        maxPages: 20,
        scrollTo: false
      })
    );
    
    search.start();
    
    </script>

    サイドバーから飛べるようにしたいのでconfig.tomlに以下を追加するこれは使用しているテーマにより設定方法が異なりそう。

    [[menu.main]]
      weight = 1
      identifier = "search"
      name = "Search"
      pre = "<i class=\"sidebar-button-icon fa fa-lg fa-search\"></i>"
      url = "/search"

    これでひとまず検索用のページも作られる

    参考

    2021, Built with Gatsby. This site uses Google Analytics.