iOSネイティブアプリでalgoliaを使ってみる

#なぜalgolia？
アプリなら大体ついてる機能、「キーワード検索」。アプリ側にデータを持たせてfilterやsortを使うのは、めちゃめちゃスペックが落ちるので絶対に避けたいです。
ネイティブアプリのエンジニアであれば、Firebaseを愛用している方も多いかと思いますが、Firebaseでサポートされていないのがクエリの「全文検索」です。指定したキーワード通りの単一・複数ドキュメントをとってきたり、ソートのクエリを追加したり、indexをふるなどはできますが、全文検索はサポートされていません。そこで、公式ドキュメントが推奨する「algolia」を使って、全文検索機能を補填しようと思います。
<img width="1398" alt="スクリーンショット 2020-06-05 13.47.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525932/ea6b9e38-127f-7b2e-aa06-913fbc6e0f94.png">

#作るものイメージ
アプリからFirestoreにデータを書き込むと、Cloud Functionsにイベントが発火し、書き込んだ内容をalgoliaに転記するイベントをNode.jsで実装します。algoliaにデータが保存されるので、検索する場合は直接ここにアクセスします。
<img width="860" alt="スクリーンショット 2020-06-05 14.25.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/525932/a1f1adcb-1be5-c376-fa78-0c402714123a.png">

#費用
Cloud Functions自体は無料のSprakプランで使えるのですが、algoliaのようなサードパーティサービスとの連携はBlazeプランが必要です。Blazeプランは無料枠があるので、とりあえずやってみるだけならほぼ費用はかかりません。algoliaも、無料枠があるので、とりあえず、って感じなら総じて無料でできます。
（Blazeプランは従量課金で、通信量を全く管理していなかった結果数100万円の請求がきたという都市伝説を聞くのでお気をつけください・・・）

#実装
###Firebase側の実装
FirestoreもしくはRealtimeDatabaseから書き込まれた際に、検索対象とするデータをalgoliaに転記するfunctionをNode.jsで実装します。具体的には、下記Firebase公式ドキュメントを参照してください。Nodeの管理にはNVM（NodeVersionManager）が推奨されています。Nodeの環境構築で、NVMをHomebrewでインストールしている記事をちょくちょく見かけますが、NVMの公式ドキュメントによればHomebrewによるインストールは非推奨です。Nodeは使うバージョンがプロジェクトによってコロコロ変わったり、管理が激しいので、ドキュメント通りに構築することを強くお勧めします。
また、Firebaseの公式ドキュメントによればNodeのバージョンは8、10が推奨されていますが、10はベータ版のため8をお勧めします。
[CloudFunctionsをデプロイするための環境構築（Firebase公式）](https://firebase.google.com/docs/functions/get-started?hl=ja)

ドキュメント通り進めていき、index.jsファイルを下記の通り実装します。今回は、新規ドキュメントが追加されたらalgoliaに転記するイベントを実装しています。削除時、更新時など、他にも様々な発火条件を設定できます。

```JavaScript:index.js
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const algoliasearch = require('algoliasearch')
const ALGOLIA_ID = functions.config().algolia.app_id
const ALGOLIA_ADMIN_KEY = functions.config().algolia.api_key
const ALGOLIA_SEARCH_KEY = functions.config().algolia.search_key
const ALGOLIA_INDEX_NAME = 'sampleDemo'
const client = algoliasearch(ALGOLIA_ID, ALGOLIA_ADMIN_KEY)

//発火タイミングを指定（今回はonCreate）、発火する場所（コレクション名等）を指定
exports.onProductUpdated = functions.firestore.document('コレクション名/{id}').onCreate((snap, context) => {
const data = snap.data()
data.objectID = context.params.id
// algoliaのindexへ追加
const index = client.initIndex(ALGOLIA_INDEX_NAME)
return index.saveObject(data)
})
```
###アプリ側の実装
CocoaPodか、Carthageでインストールできます。インストールしたら、ソースコードに「InstantSearchClient」をimportしてください。
本来はAPIクライアントを作成してエラーハンドリングをしますが、今回は、とりあえず動かすためのコードでJSONのデコードまでをやります。JSONのサンプルレスポンスも公式に上がっているので、お好みに合わせてどうぞ。

```Swift:ViewController.swift
import UIKit
import InstantSearchClient

class ViewController: UIViewController {

    let appId = "algoliaのアプリID"
    let apiKey = "algoliaのapiKey"

    override func viewDidLoad() {
        super.viewDidLoad()

        let client = Client(appID: appId, apiKey: apiKey)
        let index = client.index(withName: "sampleDemo")
        let query = Query(query: "semple")

        index.search(query, completionHandler: { (content, error) -> Void in
            if let error = error {
                print(error)
            } else {
                guard let content = content else {
                    fatalError("no content")
                }
                let data = try! JSONSerialization.data(withJSONObject: content, options: .prettyPrinted)
                let response = try! JSONDecoder().decode(Hits.self, from: data)
                print(response)
            }
        })
    }
}
```

```Swift:SampleResponse.swift
import Foundation

struct Hits: Codable {
    let hits: [SampleDemo]
}

struct SampleDemo: Codable {
    let title: String
    let content: String
    let objectID: String
}

```

これで全文検索結果が帰ってきます！
あえて検索キーワード「sample」を「semple」にしてリクエストしていますが、ちゃんと帰ってきました。最高！
タイポは、"typoTolerance"がtrue|falseのパラメータを持っているので、状況に応じてタイポの許容可否は変更できます。

#使ってみて
CloudFunctionsの実装は若干慣れが必要ですが、サードパーティサービスとAPI連携できるのは頼もしいです。Firebaseで完結する機能もたくさんあるので、個人開発には向いているかと思います。アプリ側の実装も簡単なので、手ごろに全文検索機能を実装できました。
algoliaは2019年から東京にも拠点を設立しており、今後も楽しみです！！！（早くGoogleが買収してFirebaseに全文検索機能入れろとかいっちゃダメ）

以上