11.6. 継続的なクエリー
継続的なクエリーにより、アプリケーションはクエリーフィルターに現在一致したエントリーを受信するリスナーを登録し、さらにキャッシュ操作の結果としてクエリーされたデータセットへの変更を継続的に通知できます。これには、セットに結合された値の着信一致、更新された一致、変更されて引き続き一致する一致値、およびセットを離れた値の発信一致が含まれます。継続的なクエリーを使用することにより、アプリケーションは、変更を検出するために同じクエリーを繰り返し実行する代わりに、イベントの安定したストリームを受信し、リソースがより効率的に使用されるようになります。たとえば、以下のユースケースすべてで、継続的なクエリーを使用できます。
-
Person エンティティーに
age
プロパティーがあり、ユーザーアプリケーションによって更新される 18〜25 歳の人を返す。 - $2000 を超えるすべてのトランザクションを返す。
- F1 レーサーのラップスピードが 1:45.00 秒未満だったすべての時間を返す (キャッシュにラップエントリーが含まれていて、レース中にラップがライブ入力されていると仮定)。
11.6.1. 連続クエリー実行
継続的クエリーは、以下の場合に通知されるリスナーを使用します。
-
エントリーは、
Join
イベントによって表される指定のクエリーの一致を開始します。 -
一致するエントリーが更新され、
Update
vent によって表されるクエリーの一致が継続されます。 -
エントリーは、
Leave
イベントで表されるクエリーの一致を停止します。
クライアントが継続的なクエリーリスナーを登録すると、すぐにクエリーに一致する結果の受信を開始します (上記のように Join
イベントとして受信された)。さらに、通常は作成、変更、削除、または有効期限イベントを生成するキャッシュ操作の結果として、他のエントリーが Join
イベントとしてクエリーの一致を開始したとき、または Leave
イベントとしてクエリーの一致を停止したときに、後続の通知を受信します。更新されたキャッシュエントリーは、操作の前後でエントリーがクエリーフィルターに一致する場合、Update
イベントを生成します。要約すると、リスナーが Join
、Update
、または Leave
イベントを受信するかどうかを決定するために使用されるロジックは次のとおりです。
- 古い値と新しい値の両方に対するクエリーが false と評価された場合、イベントは抑制されます。
-
古い値に対するクエリーが false と評価され、新しい値に対するクエリーが true と評価された場合、
Join
イベントが送信されます。 -
古い値と新しい値の両方のクエリーが true と評価されると、
Update
イベントが送信されます。 -
古い値に対するクエリーが true と評価され、新しい値に対するクエリーが false と評価された場合、
Leave
イベントが送信されます。 -
古い値に対するクエリーが true と評価され、エントリーが削除または期限切れになると、
Leave
イベントが送信されます。
継続的なクエリーは、グループ化、集約、およびソート操作以外のすべてのクエリー機能を使用できます。
11.6.2. 継続的なクエリーの実行
継続的なクエリーを作成するには、以下を実行します。
- クエリーオブジェクトを作成します。検索セクションを参照してください。
適切なメソッドを呼び出して、キャッシュの ContinuousQuery(
org.infinispan.query.api.continuous.ContinuousQuery
オブジェクト) を取得します。-
リモートモードの
org.infinispan.client.hotrod.Search.getContinuousQuery(RemoteCache<K, V> cache)
-
組み込みモードの
org.infinispan.query.Search.getContinuousQuery(Cache<K, V> cache)
-
リモートモードの
-
以下のように、クエリーと継続的なクエリーリスナー (
org.infinispan.query.api.continuous.ContinuousQueryListener
) を登録します。
continuousQuery.addContinuousQueryListener(query, listener);
以下の例は、埋め込みモードの単純な継続的なクエリーのユースケースを示しています。
継続的クエリーの登録
import org.infinispan.query.api.continuous.ContinuousQuery; import org.infinispan.query.api.continuous.ContinuousQueryListener; import org.infinispan.query.Search; import org.infinispan.query.dsl.QueryFactory; import org.infinispan.query.dsl.Query; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; [...] // We have a cache of Persons Cache<Integer, Person> cache = ... // We begin by creating a ContinuousQuery instance on the cache ContinuousQuery<Integer, Person> continuousQuery = Search.getContinuousQuery(cache); // Define our query. In this case we will be looking for any Person instances under 21 years of age. QueryFactory queryFactory = Search.getQueryFactory(cache); Query query = queryFactory.create("FROM Person p WHERE p.age < 21"); final Map<Integer, Person> matches = new ConcurrentHashMap<Integer, Person>(); // Define the ContinuousQueryListener ContinuousQueryListener<Integer, Person> listener = new ContinuousQueryListener<Integer, Person>() { @Override public void resultJoining(Integer key, Person value) { matches.put(key, value); } @Override public void resultUpdated(Integer key, Person value) { // we do not process this event } @Override public void resultLeaving(Integer key) { matches.remove(key); } }; // Add the listener and the query continuousQuery.addContinuousQueryListener(query, listener); [...] // Remove the listener to stop receiving notifications continuousQuery.removeContinuousQueryListener(listener);
21 歳未満の Person インスタンスがキャッシュに追加されると、リスナーによって受信され、 matches
マップに配置されます。これらのエントリーがキャッシュから削除されるか、年齢が 21 歳以上に変更されると、それらは matches
から削除されます。
11.6.3. 継続的なクエリーの削除
クエリーのそれ以上の実行を停止するには、リスナーを単に削除します。
continuousQuery.removeContinuousQueryListener(listener);
11.6.4. 継続的なクエリーのパフォーマンスに関する注意
継続的なクエリーは、アプリケーションに一定の更新ストリームを提供するように設計されており、特に幅広いクエリーに対して非常に多くのイベントが生成される可能性があります。イベントごとに新規の一時的なメモリー割り当てが行われます。この動作によりメモリーが不足し、クエリーが適切に設計されていない場合、OutOfMemoryErrors
(特にリモートモード) が発生する可能性があります。このような問題を防ぐために、一致するエントリーの数と各一致のサイズの両方の観点から、各クエリーが必要な最小限の情報をキャプチャーし (プロジェクションを使用して興味深いプロパティーをキャプチャできます)、各 ContinuousQueryListener
が受信したすべてのイベントをブロックせずにすばやく処理し、リッスンするキャッシュから一致する新しいイベントの生成につながるアクションの実行を回避するように設計されていることが強く推奨されます。