トレタ開発者ブログ

飲食店向け予約/顧客台帳サービス「トレタ」、モバイルオーダー「トレタO/X」などを運営するトレタの開発メンバーによるブログです。

サービス開発で高速全文検索APIのAlgoliaを使用した際の処理フローと感じたAlgoliaの特徴

はじめに

皆様、こんにちは!
『あつまれ どうぶつの森』でゴリラの住民ばかりが島に集まるトレタのサーバサイドエンジニア兼佐久間まゆちゃんのプロデューサーの@hiroki_tanakaです。
現在、私が携わっているプロダクトでAlgoliaという高速検索APIを使用しています。 今回はAlgoliaとは何か?から実際に使用してみて感じたことをご紹介します!

そもそもAlgoliaとは?

  • 高速な全文検索APIサービスのSaaS。
  • 一番の売りは検索速度の圧倒的な速さ。
    • 公式が出しているデモサイトもあり、試してみることが可能です。
  • Algolia内にJSON 形式でデータを保持し、その中で検索を行います。
    • 検索可能にする属性や検索順の重み付け設定はGUIから柔軟に行うことが出来ます。
  • RubyPHP Java Go Scale Swiftなどの様々な言語向けにAPIを提供しています。
  • Algoliaは登録したレコード数及び検索APIの実行アクセス回数での従量課金制。
    • 1万レコード・10万APIアクセスまでは無料で使用することができます。
  • 既存のサービスではTwitchやStripeで使用されています。
  • 余談ですが、Googleが提供しているBaaS:Firebaseでは『検索を実現したい場合はAlgoliaを併用すべし』という記載があります。これはFirestoreに検索のAPI機能がなく、コレクション全体をクライアント側に保持し、強引にフロントエンドで検索するというのは現実的ではないためです。

用語解説

Algoliaは一般的なRDBとは若干異なる用語でデータを扱います。

  • Index:RDBでいうテーブル。データレコードの集合でデータの大本です。
  • Attribute:RDBでいうカラム。AlgoliaはKey/Valueでデータを保存します。

処理フローとサンプルコード

プロダクトはiOSアプリでフロントエンドはSwift・バックエンドはFirebaseでサーバレスとし、検索をAlgoliaが行う構成としました。
また、必要なテーブルが1つしかないことから、RDBを持たずにデータを全てAlgoliaに集約しました。

検索処理のフローとしては、以下のようになります。

  1. Algoliaに必要なIndexを作成し、JSON形式のデータを登録する。
  2. SwiftからAlgoliaのSearch APIを呼出、Algoliaから検索結果のJSONデータを返却する。
  3. 検索結果を画面に描画する。

以下がSwiftを用いてAlgolia上のIndexからデータを取得するサンプルコードになります。
今回はサンプルとしてIndex:moviesがあり、Attribute:titleを検索可能設定しているとします。

/// 使用するAlgoliaのアプリケーションIDとAPIキーを指定
private let appId = "application_ID"
private let apiKey = "API_KEY"

/// Algoliaクライアントを作成
let client = Client(appID: appId, apiKey: apiKey)
/// 検索対象のIndexを指定
let index = client.index(withName: "movies")
/// 検索クエリの作成
let query = Query(query: "すみっコぐらし")

/// Algoliaへの検索処理実行
index.search(query, completionHandler: { (content, error) -> Void in
  if error == nil {
      print("Result: \(content!)")
  }
})

Algoliaの検索時に特徴的な箇所

  • 検索時にTypoを許容するように設定できる点

Algoliaは検索ワードのTypoを許容し、検索ワードに近い単語を取得するようにデフォルト設定ではなっています。
そのため、先程のすみっコぐらしを検索したいと思った場合、すもっコぐらしすみっコくらしで検索した場合でも検索結果に含まれます。
ただし、2箇所以上のTypoが含まれている場合は、Algoliaは結果を返しません。
Typo許容の設定をオフにして、Typoなしで一致するレコードのみが取得する場合は、typoToleranceというオプションをfalseにすれば解決します。

query.typoTolerance = .false
  • 単数形・複数形の区別を無視できる点

単数形・複数形を無視して、同等の単語としてAlgolia上では扱われるような設定がデフォルトで有効になっています。
そのため、複数形で検索した場合も単数形の単語が検索結果としてヒットしてしまいます。
例:carsで検索した場合、carもヒットします。
単数形・複数形の区別を有効にするためには、下記のようにignorePluralsというオプションをfalseにすれば解決します。

index.setSettings([
  "queryLanguages": ["en"],   /// 設定対象の言語を指定。enは英語。
  "ignorePlurals": false
])
  • 検索ワード自体に一致しなくても、検索ワードを分解した文字を全て含んでいるレコードを検索結果に含める点

Algoliaは検索ワードを文字に分解して、例え検索ワード自体が含まれていなくても分解した文字を全て含んでいるレコードがある場合、検索結果に含めてしまいます。
例:くらしという検索ワードの場合、 の全ての文字が含まれているクラフト紙(くらふとし)などもヒットしてしまいます。
この設定を無効化しようと試してみたのですが、Algoliaの検索設定やクエリへの追加条件ではこれを回避することは出来ませんでした。。。
最終的に、Algoliaから検索結果を取得した後に改めてSwift側で検索ワードとの一致をチェックするフィルター処理を入れるように致しました。
(有効な回避策を知っている方は教えて頂けるととても嬉しいです(´>ω<`) )

終わりに

Algoliaを使用することでSQLを記載することなく、高速な検索処理が作成でき、プログラムからのAPIの操作も非常に使いやすくとても便利でした。
また、導入障壁も低いのでアプリケーションのプロトタイプ作成やクイックスタートには非常に向いていると思います。
ただ、RDBほど柔軟に検索クエリを書くことが出来ないことが少しつらいなーとは感じました。

終わりの終わりに

トレタに少しでも興味を持っていただいた方がいれば、ぜひ遊びに来てくださいヽ(*´∀`)/
仲間も募集しています!

© Toreta, Inc.

Powered by Hatena Blog