Posts Tagged “java”



appengineのSearch Service(full-text search) はまだexperimentalですが非常に魅力的な機能です。
正式リリースされればデータの種類によってはDatastoreの代わりに使用することもできそう。最大の特徴は検索の柔軟性にあるでしょうか。
ただし使ってみていくつか不思議な仕様に気づいたので注意が必要。簡単にまとめてみます。

DATE型は時刻を持てない

DATE: a date with no time component とドキュメントにあるようにあくまで日付だけしか持てないようです。
timestampを管理したい場合などはちょっと工夫が必要ですね。
自分はNUMBER型を使用して、特定日時(例えば2010-01-01 00:00:00)からの秒数で保持するようにしました。
※NUMBER型の範囲は -2,147,483,647 ~ 2,147,483,647

DATE型はSDKにバグ?

eclipseの環境でtime部分をクリアしたDateをこのフィールドに渡しても、= のクエリーでヒットしません。
例えば今日が 2013-04-24 だとして、 new Date() をセットすると、date_field = 2013-04-24 でも date_field >= 2013-04-24 でもヒットしません。
production環境ではtime部分をクリアしてもしなくても = でヒットします。

TEXT型は同一フィールド名で複数の値を保持可能

addFieldを繰り返して同じフィールド名に異なる値を追加できるようです。


Document.newBuilder()
    .addField(Field.newBuilder().setName("text1").setText("hoge")
    .addField(Field.newBuilder().setName("text1").setText("fuga")
    .build();

HTML型も可能でしたがNUMBER型はExceptionが発生しました。

TEXT型に = でクエリーした場合、どういう条件でヒットする?

Numeric operators only match against numeric and date fields. と書いてありますので当然かもしれませんが、TEXT型に = を指定したクエリーを実行しても完全一致にはなりませんでした。
例えば、text_field = hoge というクエリーを実行した場合に

  • “hoge_2” はヒットしません。
  • “this is hoge” はヒットします。
  • “@hoge” はヒットします。

という結果でした。
さらにSDKでは全然結果が異なりました。。(これもバグ??)

完全一致が使えると(全文検索以外に)使い途が広がるのですが、文字種を限定するなど工夫が必要そうです。

とりあえず気づいたのはこんなところですがまだまだ落とし穴があるかもしれません。

Comments App Engine Search (Full text search) の不思議な仕様 はコメントを受け付けていません。



ソースコードは こちら に公開しています。

概要

データストアのRead/Writeの無料課金枠が結構シビアなのでもはやキャッシュなしではやっていけないと思ったのがこれを作るきっかけでした。(速度的にはデータストアの呼び出しがそんなに遅いとは感じないのであくまで課金対策が主眼です。)

既存のコードにできるだけ手を入れないで実現したかったのでApiProxyを使ってdatastoreのAPI呼び出しをhookし、protocol bufferのrequest,responseをそのままキャシュしてはどうかと思いつきました。

キャッシュ対象とするのはQuery(RunQueryメソッド)でGetはもともと安いので対象外としました。RunQueryメソッドをhookしてキャッシュにデータが存在すればdatastore APIは呼び出さずにキャッシュしたレスポンスを返す、キャッシュにデータが存在しなければそのままAPI呼び出しをしてresponseをキャッシュする、というしくみになっています。
同一カインドのデータがPutまたはDeleteされた場合はキャッシュを無効にするようにカインド毎のResetDateを持って管理しています。

WriteよりReadのほうが圧倒的に多いシステムではキャッシュヒット率が高くなるのでこのしくみは有効かと思います。
逆に同一カインドのエンティティが頻繁に更新されるようなシステムではあまり効果がないかもしれません。

必要なライブラリ

  • commons-logging-1.1
  • commons-lang-2.4
  • gdata-core-1.0

使い方

必要なjarファイルを追加して、web.xmlのfilterChain先頭に以下のフィルター設定を追加するだけです。


    <filter>
        <filter-name>CacheContextFilter</filter-name>
        <filter-class>jp.honestyworks.pbcache.ContextFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CacheContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

その他の特徴

  • App EngineのMemcache Quota Limit を超えるサイズのデータも問題なくキャッシュされます。(適切なサイズにchunkされて保存します。)
  • memcacheだけでなくThreadLocalなコンテキストにもキャッシュを保持します。(Request毎にクリアされます。)
  • 上記ローカルキャッシュは使わない設定にすることもできます。
  • Production環境でしか有効になりません。

制限

  • datastore APIのasyncCallはsyncCallにデグレードします。asyncCallの恩恵を受けているシステムでは使用しないほうが良いかと思います。

本題とは関係ないけど、ktrwjr が便利

テストをするにあたり、slim3に組み込まれているktrwjrを使ってみましたがすごく便利!これは素晴らしいです。

ダウンロード

オープンソースとしてありますので自己責任でご自由にお使いください。

フィードバック

使っていただけた方は些細な事でもフィードバックいただけると嬉しいです。protocol buffer はあまり詳しくないので探り探りの実装になってます。
フィードバックは私のtwitterまでお寄せください。 (@miztaka)