Coherenceでは、現在キャッシュされているデータのうち、指定された一連の基準を満たすものに対して、問合せと索引を実行できます。問合せと索引は、Coherence付属のフィルタを採用した単純なものにするか、またはコレクションや配列などの複数値属性に対して実行できます。
Coherenceでは、指定された一連の基準を満たすキャッシュ・エントリを検索できます。結果セットは必要に応じてソートできます。問合せは、コミット読取り分離を使用して評価されます。
問合せは、キャッシュされたデータにしか適用されないことに注意してください(CacheLoader
インタフェースを使用して、問合せに適合するデータが追加で取得されることもありません)。このため、問合せが実行される前にデータセット全体をキャッシュにロードする必要があります。データセットが大きすぎて使用可能なメモリーに収まらない場合は、特定のディメンション(日付など)に従ってキャッシュの内容を制限し、問合せの構造に基づいてキャッシュ問合せとデータベース問合せを手動で切り替えることができます。保守性の面から、通常はキャッシュ対応のデータ・アクセス・オブジェクト(DAO)の内部にこの処理を実装するのが最適です。
索引を付けるには、各パーティション・キャッシュ・ノードで属性を抽出できることが必要です。専用のCacheServer
インスタンスの場合は、これを実現するために(通常は)アプリケーション・クラスをCacheServer
クラスパスにインストールする必要があります。
ローカル・キャッシュおよびレプリケーション・キャッシュについては、索引のないデータに対して問合せがローカルで評価されます。パーティション・キャッシュについては、索引を使用して(使用可能な場合)問合せがクラスタ全体で並列に実行されます。Coherenceにはコストベース・オプティマイザ(CBO)が搭載されています。索引のない属性にアクセスするには、オブジェクトをデシリアライズする必要があります(ただし、他の属性に索引を付けると、評価が必要なオブジェクトを減らすことができます)。
キャッシュの内容を問い合せる操作は、例13-1に示すように非常に単純です。
例13-1 キャッシュの内容の問合せ
ValueExtractor::Handle hExtractor = ReflectionExtractor::create("getAge"); Filter::View vFilter = GreaterEqualsFilter::create(hExtractor, Integer32::valueOf(18)); for (Iterator::Handle hIter = hCache->entrySet(vFilter)->iterator(); hIter->hasNext(); ) { Map::Entry::Handle hEntry = cast<Map::Entry::Handle>(hIter->next()); Integer32::View vKey = cast<Integer32::View>(hEntry->getKey()); Person::Handle hPerson = cast<Person::Handle>(hEntry->getValue()); std::cout << "key=" << vKey << " person=" << hPerson; }
Coherenceでは、coherence::util::Filter
パッケージに多様なフィルタが用意されています。LimitFilter
を使用すると、クライアントに送信されるデータ量を制限できるほか、ユーザー側でページングを実現できます。
例13-2 LimitFilterメソッドの使用方法
int32_t nPageSize = 25; ValueExtractor::Handle hExtractor = ReflectionExtractor::create("getAge"); Filter::View vFilter = GreaterEqualsFilter::create(hExtractor, Integer32::valueOf(18)); // get entries 1-25 LimitFilter::Handle hLimitFilter = LimitFilter::create(vFilter, nPageSize); Set::View vEntries = hCache->entrySet(hLimitFilter); // get entries 26-50 hLimitFilter->nextPage(); vEntries = hCache->entrySet(hLimitFilter);
問合せ可能な属性には、QueryMap
クラスのaddIndex
メソッドで索引を付けることができます。
例13-3 問合せ可能な属性に対する索引付け
// addIndex(ValueExtractor::View vExtractor, boolean_t fOrdered, Comparator::View vComparator) hCache->addIndex(hExtractor, true, NULL);
fOrdered
引数では、索引構造をソートするかどうかを指定します。ソートされた索引は、「2つの日付の間に収まるエントリをすべて選択」や「姓がSで始まる従業員をすべて選択」などの範囲問合せに役立ちます。等価問合せの場合は、順序付けられていない索引を使用できます。この索引を使用すると、領域と時間の面で効率が向上することがあります。
comparator引数は、カスタムのjava.util.Comparator
を提供して索引に順序を付ける場合に使用できます。
注意: このメソッドは、単にキャッシュ実装のヒントとして示したものであり、索引がサポートされていない場合や目的の索引(またはそれに類似した索引)がすでに存在する場合は、キャッシュによって無視されることがあります。アプリケーションでは、確実に索引が提示されるようにするために、索引がすでに存在する場合でもこのメソッドをコールして索引を提示することが求められます。たとえば、分散環境では各サーバーが起動時に同じ索引セットを提示する可能性があり、別のサーバーがすでに同じ索引を要求しているかどうかに関係なく、アプリケーションがそれらの索引を不必要に要求しても不都合は生じません。索引は、Coherence Enterprise Edition以上に備わる機能です。Coherence Standard Editionを使用している場合は、このメソッドの効果を得られません。 |
Coherenceでは必要に応じて問合せを結合することができます。またCoherenceには、索引の使用優先順位を決めるコストベース・オプティマイザ(CBO)が搭載されています。索引を利用するには、問合せで使用されているエクストラクタと同等((Object->equals()
)のエクストラクタを、同じ問合せで使用する必要があります。
Coherence Enterprise EditionまたはGrid Editionを使用している場合は、パーティション・キャッシュがパラレル問合せ機能を使用してQueryMapインタフェースを実装します。Coherence Standard Editionを使用している場合はパラレル問合せ機能を利用できないため、大きなデータセットを問い合せる場合をはじめとして、ほとんどの問合せでパフォーマンスが低下します。
この項では、問合せインタフェースの設計について、コアなコンポーネントから順に詳しく説明していきます。
問合せ処理の概念は、ValueExtractor
インタフェースに基づいています。値エクストラクタは、問合せで指定のオブジェクトから属性を抽出するために使用されます(索引付けの場合も同様)。ほとんどの開発者に必要となるのは、このインタフェースのReflectionExtractor
実装のみです。ReflectionExtractorは、リフレクションを使用してメソッド名(通常はgetName()
のようなgetterメソッド)を参照することにより、値オブジェクトから属性を抽出します。
ReflectionExtractor::Handle hExtractor = ReflectionExtractor::create("getName");
toString()
のようなObject
メソッドをはじめとする任意のvoid引数メソッドを使用できます(プロトタイプ作成/デバッグに有用)。索引には、従来のフィールド索引(オブジェクトのフィールドに付けられた索引)または機能別索引(仮想のオブジェクト属性に付けられた索引)を使用できます。たとえば、クラスにフィールド・アクセッサgetFirstName
およびgetLastName
がある場合、そのクラスではこれらの名前を連結する関数getFullName
を定義し、その関数に索引を付けることができます。
getName
属性を持つオブジェクトが含まれているキャッシュに問合せを実行するには、Filter
を使用する必要があります。フィルタには、指定したオブジェクトが基準を満たしているかどうかを判別するメソッドが1つあります。
Filter::Handle hEqualsFilter = EqualsFilter::create(hExtractor, String::create("Bob Smith"));
特定のフィルタに適合するキャッシュ・エントリを選択する方法は次のとおりです。
例13-4 特定のフィルタに適合するキャッシュ・エントリの選択
for (Iterator::Handle hIter = hCache->entrySet(hEqualsFilter)->iterator(); hIter->hasNext(); ) { Map::Entry::Handle hEntry = cast<Map::Entry::Handle>(hIter->next()); Integer32::View vKey = cast<Integer32::View>(hEntry->getKey()); Person::Handle hPerson = cast<Person::Handle>(hEntry->getValue()); std::cout << "key=" << vKey << " person=" << hPerson; }
エントリを選択してソートする方法は次のとおりです。
例13-5 エントリの選択およびソート
// entrySet(Filter::View vFilter, Comparator::View vComparator) Iterator::Handle hIter = hCache->entrySet(hEqualsFilter, NULL)->iterator();
NULL引数を追加することで、キャッシュ内の比較可能なオブジェクトの自然な順序で結果セットをソートするように指定しています。クライアントでは、Comparatorの実装を提供することで、結果セットの順序を明示的に指定できます。ソート処理を行う場合は、ソートの前に結果セット全体を取得しておく必要があるために、Coherenceで適用できる最適化が著しく制限されるので注意してください。
keySet
形式の問合せをgetAll()
と組み合せることで、メモリー使用量をより細かく制御できます。
例13-6 keySet形式の問合せの使用
// keySet(Filter::View vFilter) Set::View vSetKeys = hCache->keySet(vFilter); Set::Handle hSetPageKeys = HashSet::create(); int32_t PAGE_SIZE = 100; for (Iterator::Handle hIter = vSetKeys->iterator(); hIter->hasNext();) { hSetPageKeys->add(hIter->next()); if (hSetPageKeys->size() == PAGE_SIZE || !hIter->hasNext()) { // get a block of values Map::View vMapResult = hCache->getAll(hSetPageKeys); // process the block // ... hSetPageKeys->clear(); } }
Coherenceでは、コレクションや配列を含めた複数値属性の索引付けおよび問合せがサポートされています。オブジェクトに索引を付けるときには、そのオブジェクトが複数値タイプかどうかがチェックされてから、シングルトンでなくコレクションとして索引が付けられます。このようなコレクションに対する問合せには、ContainsAllFilter
、ContainsAnyFilter
およびContainsFilter
が使用されます。
例13-7 複数値属性に対する索引付けおよび問合せ
Set::Handle hSearchTerms = HashSet::create(); hSearchTerms->add(String::create("java")); hSearchTerms->add(String::create("clustering")); hSearchTerms->add(String::create("books")); // The cache contains instances of a class "Document" which has a method // "getWords" which returns a Collection<String> containing the set of // words that appear in the document. ValueExtractor::Handle hExtractor = ReflectionExtractor::create("getWords"); Filter::View vFilter = ContainsAllFilter::create(hExtractor, hSearchTerms); Set::View vEntrySet = hCache->entrySet(vFilter); // iterate through the search results // ...
ChainedExtractor
実装を使用すると、ゼロ引数(アクセッサ)メソッドの連鎖起動が可能となります。例13-8では、エクストラクタはまず、キャッシュされている各Person
オブジェクトに対し、リフレクションを使用してgetName()
をコールし、返されたString
に対し、リフレクションを使用してlength()
をコールします。このエクストラクタを問合せに渡し、(たとえば)名前が10文字以内の人をすべて、問合せで選択することができます。
例13-8 ChainedExtractor実装の使用
ChainedExtractor::Handle hExtractor = ChainedExtractor::create(ChainedExtractor::createExtractors("getName.length"));
メソッドの起動は、getName.trim.length
のように、無限に連鎖させることができます。