JDOが全然使えないことが明らかになるにつれ、最近ではLow level APIを使う方も多くなってきた。Low level APIは、シンプルで扱いやすく、パフォーマンスにも問題ないことがうけて支持されているのだろう。しかし、機能的には全然足りないので、自分たちで何とか解決しなければならない課題も多い。前方一致検索もその一つである。
Low level APIで前方一致かつPagingが難しい件
前方一致検索は、JDOではcontent.startsWithを使えばできるようであるが、Low level APIでも、検索項目をソートすることで一応できることはできる。しかしPagingについては、2Page目以降を特定する方法が必要ななため、できないと思っていた。
例えば、下図のように、”コーヒー”で前方一致検索した場合に、同じ商品名の”コーヒー010”が複数存在する可能性があるため、次ページにおいて、どのレコードから表示すればよいかわからない。この問題は、Low level APIでは、GREATER_THAN_OR_EQUALなどのInequality filterが、1つしか使えないという制約に起因するものである。(追記10/29:LESS_THANも使えることがわかっている。参照=>Keyとカウンタは別々に考えるといいかも)
)そこで、「複雑なクエリのためのプロパティを仕込んでおく方法」を参考に、前方一致検索でかつPagingする方法を考えてみた。ただ、さらに安い順でソートしたり、全文検索などはできない。これらについては、TaskQueueを使って対応するしかないと考えている。
また、ここでは、商品のデータ件数は無限にあるという前提で考えている。小規模なものであれば考える必要はないのかもしれないが、これまで繰り返し述べているように、クラウドの最大のメリットはスケーラビリティだと思っているので、それを阻害するような制約は排除すべきであると思う。
実装方法およびサンプル
具体的には以下のようにする。
1Page目:
キーワード(word=”コーヒー”)で検索する。Low-level Datastore APIのQueryで、商品名プロパティに対して条件をGREATER_THAN_OR_EQUAL指定。Reflex GAEのEntityConverter#convertでCondition指定をし、対象項目が指定されたwordで始まっていなければ結果に含めないようにする。(この処理はIn Memory)
2Page目以降:
キーワード(word=”コーヒー” )、最後の商品名(nextword=“コーヒー010”)、および、最後の連番(number=009)を指定する。
Low-level Datastore APIのQueryで、商品名+連番プロパティに対してnextword + number条件をGREATER_THANで指定。EntityConverter#convertでCondition指定をし、対象項目が指定されたwordで始まっていなければ結果に含まないようにする。 (この処理はIn Memory)
前方一致でかつPagingを行うサンプル
1ページ目
2ページ目