2009年9月14日月曜日

不等式フィルタを使い且つ複数のプロパティでソート

緯度と経度のgeoboxで絞込みを行うことと、日付の降順でソートを行うこと、これらをクエリーだけで実装しようとトライした。
Query query = pm.newQuery(Mutter.class);
query.declareParameters("String geohashFrom, String geohashTo");
query.setFilter("geohash >= geohashFrom && geohash <= geohashTo");
List mutters = (List) query.execute(geohashFrom,geohashTo);
query.setOrdering("geohash ASC, date DESC");
これだと、Geohashの昇順で並べられた中での日付降順という意味になってしまう。

ほしいのは、日付降順で並べられた、限られたgeoboxのデータリスト。つまり、ソートの順番で先に日付を持ってきたいのだが、Geohashの不等式を使っている以上、どうしてもソートの優先順位一位としてGeohashを指定しなければならない。これはGAE/J上の制約。
参考:クエリとインデックス - Google App Engine - Google Code

勿論、
query.setOrdering("date DESC, geohash ASC");
と書くと、例外が発生する。

NestedThrowablesStackTrace:
java.lang.IllegalArgumentException: The first sort property must be the same as the property to which the inequality filter is applied. In your query the first sort property is date but the inequality filter is on geohash

Query query = pm.newQuery(Mutter.class, "ORDER BY date DESC");
とも書いてみたが、例外は発生しないものの、日付降順ではソートされておらず。。。

結局、クエリでソートすることはやめて、JavaでComparatorを使いソートすることにした(^^;)。
import java.util.Comparator;

public class DateComparator implements Comparator<Mutter> {

 // デフォルトは降順
 private boolean order = false;

 public void setOrder(boolean order) {
  this.order = order;
 }

 public int compare(Mutter m0, Mutter m1) {
  if (this.order) {
   // 昇順
   return m0.getDate().compareTo(m1.getDate());
  } else {
   // 降順
   return m1.getDate().compareTo(m0.getDate());
  }
 }
}
取得したListをComparatorでソートする。
Query query = pm.newQuery(Mutter.class);
query.declareParameters("String geohashFrom, String geohashTo");
query.setFilter("geohash >= geohashFrom && geohash <= geohashTo");
List<Mutter> mutters = (List<Mutter>) query.execute(geohashFrom,geohashTo);
Collections.sort(mutters, comparator);
これで日付降順&緯度経度の絞込みができるようになった。久しぶりにComparator書いたから、ちょっと書き方忘れてたよー(^^;)。うーん、でもやっぱりクエリだけでなんとかしたいと思うんだけど、無理かなぁ?