Search Algolia index data with Golang client

このブログの記事検索にAlgoliaを使っています。

Algoliaはjsonでデータをクラウドにアップロードし、APIで検索したいキーワードを投げて結果を得ることの出来るサービスです。

AlgoliaはREST API以外にも一通り有名どころの言語のライブラリを提供しています。今回はGolangのライブラリを使用して、私のブログの記事を検索してjsonで結果を得るところまでやってみます。

準備としてとりあえずalgoliasearchをインストールしておきます。

go get github.com/algolia/algoliasearch-client-go/algoliasearch  

簡単なことからやってみる

まずはQuick Startに従ってサンプルデータの検索をやってみます。

Quick Startではデータを登録する例から始まっていますが、今回はサンプルデータを手で直接Algoliaに登録しちゃいます。

contactsという名前でIndexを作成します。

早速登録したデータに対して検索を実行するコードを書いてみます。

search.go

  • ドキュメントのままではエラーになるので(最低限の説明のみなので)多少コードが異なる
  • アプリIDとAPIキーはAlgoliaの管理画面から確認できる
  • 結果をfmt.Printlnで出力している
  • APIキーとか公開されるの前提に使われる感じですが本能的に隠している...
  • クイックスタートにならってjimmie paintで検索してみる
package main

import (  
    "fmt"

    "github.com/algolia/algoliasearch-client-go/algoliasearch"
)

func main() {  
    client := algoliasearch.NewClient("アプリID", "APIキー")

    index := client.InitIndex("contacts")

    res, err := index.Search("jimmie paint", nil)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(res)
}

実行するとこんな結果になりました。

$ go run search.go
{  false map[] map[] [map[state:CA phone:209-525-7568 fax:209-525-4389 lastname:Barninger company:California Paint & Wlpaper Str city:Modesto county:Stanislaus address:Box #-4038 zip:95352 web:http://www.jimmiebarninger.com objectID:9446462 _highlightResult:map[zip:map[value:95352 matchLevel:none matchedWords:[]]phone:map[matchLevel:none matchedWords:[] value:209-525-7568] fax:map[value:209-525-4389 matchLevel:nonematchedWords:[]] email:map[value:<em>jimmie</em>@barninger.com matchLevel:partial fullyHighlighted:falsematchedWords:[jimmie]] company:map[fullyHighlighted:false matchedWords:[paint] value:California <em>Paint</em> & Wlpaper Str matchLevel:partial] address:map[value:Box #-4038 matchLevel:none matchedWords:[]] city:map[value:Modesto matchLevel:none matchedWords:[]] state:map[value:CA matchLevel:none matchedWords:[]]web:map[matchLevel:none matchedWords:[] value:http://www.jimmiebarninger.com] firstname:map[value:<em>Jimmie</em> matchLevel:partial fullyHighlighted:true matchedWords:[jimmie]] lastname:map[matchedWords:[] value:Barninger matchLevel:none] county:map[value:Stanislaus matchLevel:none matchedWords:[]]] firstname:Jimmie email:jimmie@barninger.com followers:3947]] 20  0  1 1 0 0 query=jimmie+paint  1 jimmie paint   false false}

なんじゃこりゃ!

index.Searchの返り値を追ってみます。

index.SearchQueryResを返し、QueryResは構造体のようです(インターフェース型?この辺あんま良くわかってない...)。

この構造体のフィールドに入る値の内容はQuick Start内に説明があります。どうやらHitsに検索して取得されたデータが入るようです。

このままでは見辛いので、jsonで出力するようにしてみます。Marshallすれば良さそう。ついでにインデントもつけてみる。

以下のようにコードを直します。

search.go

package main

import (  
    "bytes"
    "encoding/json"
    "fmt"

    "github.com/algolia/algoliasearch-client-go/algoliasearch"
)

func main() {  
    client := algoliasearch.NewClient("アプリID", "APIキー")

    index := client.InitIndex("contacts")

    res, err := index.Search("jimmie paint", nil)
    if err != nil {
        fmt.Println(err)
    }

    jsonBytes, err := json.Marshal(res)
    if err != nil {
        fmt.Println("JSON Marshal error:", err)
    }

    out := new(bytes.Buffer)
    json.Indent(out, jsonBytes, "", "    ")
    fmt.Println(out.String())
}

実行してみる。

$ go run search.go
{
    "hits": [
        {
            "_highlightResult": {
                "address": {
                    "matchLevel": "none",
                    "matchedWords": [],
                    "value": "Box #-4038"
                },
...
    "hitsPerPage": 20,
    "nbHits": 1,
    "nbPages": 1,
    "page": 0,
    "params": "query=jimmie+paint",
    "processingTimeMS": 1,
    "query": "jimmie paint"
}

良さそう!

自分の記事データに対し検索する

やるにあたって、アプリIDAPIキーインデックス名検索ワードをオプションで渡すようにしてみます。

実行してみます。

$ go run algoliasearch.go -d xxxxxxxx -k yyyyyyyy -i zzzzzzzz -q 'content security'
{
    "hits": [
        {
            "_highlightResult": {
                "created_at": {
                    "matchLevel": "none",
                    "matchedWords": [],
                    "value": "2017-02-03T10:51:30.000Z"
                },
...
    ],
    "hitsPerPage": 20,
    "nbHits": 2,
    "nbPages": 1,
    "page": 0,
    "params": "query=content+security",
    "processingTimeMS": 2,
    "query": "content security"
}

できた!

jqと組み合わせてみる

jqと組み合わせて、検索結果にヒットしたデータのタイトルデータのみ出してみます。

$ go run algoliasearch.go -d xxxxxxxx -k yyyyyyyy -i zzzzzzzz -q 'content security' | jq '.hits[].title'
"Trying out CSP(Content Security Policy)"
"What is do-agent by DigitalOcean"

Yay!

今後の予定

Alfredと組み合わせてみたい。

感想

  • APIで全文検索できるの楽しい
  • クイックスタートは本当に最低限のみの説明って感じなのでちょっと苦労した(Golang力なさ)
    • ソースコード読んでようやくjsonで結果は帰ってこないことを理解した...
  • 基礎力がないのでGolangチュートリアル繰り返したい

参考リンク