メッセージの検索(復活編)Firebaseすこし遅れましたが明けましておめでとうございます。本年も宜しくお願い申し上げます。Calendar用に書いていた「Firebaseでチャットアプリを作る日記」ですが、今年もペースは落としつつ少しずつ進めていければと思っています。本日は10日目の記事で撃沈したメッセージの検索に再チャレンジします。partyツールを使わない)作戦10日目の記事では、bigramで分割したトークンをドキュメントのarrayフィールドに保持してarray-containsで検索をかける作戦でしたが、array-containsは1回のクエリで1度しか使えないという制約があり撃沈しました。orzそこで作戦を変更してトークンをmapフィールドに保存します。検索することができます。トークンは10日目の記事ではmessagesドキュメントに直接埋め込むつもりでしたが、今回はmessageIndexコレクションのドキュメントとして別の場所に保存します。検索する方式となる為複合インデックスを用意することができなくなりました。ソートは、「ソート指定がない場合はドキュメントIDでソートされる」という仕様を利用します。ドキュメントIDにソート項目をプレフィクスとして付与してmessageIndexesドキュメントを保存します。messageIndexesコレクションに対してクエリを実行します。今回は投稿日降順でソートをかけたいので、投稿日を反転させた日付文字列をIDプレフィックスとします。IDを持たせてmessagesドキュメントを辿れる様にします。実装テキスト分割10日目の記事ではbigram(2文字ずつのトークン)に分割していました。今回もほぼ同様ですが、bigramに合わせてunigram(1文字ずつのトークン)も用意します。これにより1文字のみの部分一致検索も可能となります。いうトークンに分割されます。メッセージの追加messagesドキュメントとmessageIndexesドキュメントをバッチ保存します。});}これで保存されたドキュメントは下記のイメージとなります。});}ユーザーの入力値もbigramで分割してindexesフィールド(map)に対して「==」で検索をかけています。「==」で検索できるものならばmessageIndexesにフィールド追加も可能です。「membersフィールドにサインインユーザーが含まれていること」と、「ユーザー入力のbigramトークンが全てインデックスに含まれていること」を一つのクエリでフィルタしています。一点ハマったので共有しておきます。今回フィールド名(mapのkey)にメッセージから作成したトークンを保存しています。これにはドット含む記号などあらゆる文字が含まれる可能性があります。様にドット区切りで指定しますが、フィールド名に記号が含まれるとこの指定方法が使えなくなります。0-9の様にバッククォートで囲めと書かれていますが、これが期待通り動作しません。正しくはfirebase.firestore.FieldPathを使用する必要がある様です。Overflowセキュリティルール最後にセキュリティルールの追加です。ユーザーがmembersフィールド(array)に設定されている場合のみ登録・参照可能とします。}複合インデックス今回は「==」のみの検索でフィールドソートなしの為、複合インデックスの追加は不要です。サーバー側で設定される為、フロントで取得することができません。その為今回はフロント側システム時刻から計算しています。ユーザーがおかしなローカル時間のPCを使っていると検索結果の時系列が狂ってしまいます。Functions起動してmessageIndexes保存をサーバーサイドで行うこと、でしょうか。これは次回の宿題にしたいと思います。他の解決策やベストプラクティスご存知の方は教えてください。ノイズbigramで検索する為検索結果にノイズが発生する可能性があります。「東京都」で検索した場合「東京」と「京都」を含むメッセージがヒットしてしまいます。メッセージが長文になればなるほどノイズ発生の確率もあがります。4-gramなどの長いトークンを増やせばノイズ減らせるかもしれませんがインデックス量が増加します。トークン分割に形態素解析を行うのもよいかもしれません。これも別の機会に挑戦してみたいと思います。年を跨いだリベンジです!messageIndexesをもう少し工夫することでもう少し柔軟な検索を行うことも出来そうです。その辺りはまた別のブログでまとめたいと思います。メッセージの登録と一覧取得を行います。(2)月別アーカイブリンクはてなブログブログをはじめる週刊はてなブログはてなブログPro参加グループプログラミングテクノロジーはてなブログをはじめよう!knightsoさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。