ヘッダーをスキップ
Oracle® Coherenceクライアント・ガイド
リリース3.7.1
B65027-01
  ドキュメント・ライブラリへ移動
ライブラリ
製品リストへ移動
製品
目次へ移動
目次

前
 
次
 

12 キャッシュの問合せ(C++)

Coherenceでは、現在キャッシュされているデータのうち、指定された一連の基準を満たすものに対して、問合せと索引を実行できます。問合せと索引は、Coherence付属のフィルタを採用した単純なものにするか、またはコレクションや配列などの複数値属性に対して実行できます。

この章の内容は次のとおりです。

12.1 問合せ機能

Coherenceでは、指定された一連の基準を満たすキャッシュ・エントリを検索できます。結果セットは必要に応じてソートできます。問合せは、コミット読取り分離を使用して評価されます。

問合せは、キャッシュされたデータにしか適用されないことに注意してください(CacheLoaderインタフェースを使用して、問合せに適合するデータが追加で取得されることもありません)。このため、問合せが実行される前にデータセット全体をキャッシュにロードする必要があります。データセットが大きすぎて使用可能なメモリーに収まらない場合は、特定のディメンション(日付など)に従ってキャッシュの内容を制限し、問合せの構造に基づいてキャッシュ問合せとデータベース問合せを手動で切り替えることができます。保守性の面から、通常はキャッシュ対応のデータ・アクセス・オブジェクト(DAO)の内部にこの処理を実装するのが最適です。

索引を付けるには、各パーティション・キャッシュ・ノードで属性を抽出できることが必要です。専用のCacheServerインスタンスの場合は、これを実現するために(通常は)アプリケーション・クラスをCacheServerクラスパスにインストールする必要があります。

ローカル・キャッシュおよびレプリケーション・キャッシュについては、索引のないデータに対して問合せがローカルで評価されます。パーティション・キャッシュについては、索引を使用して(使用可能な場合)問合せがクラスタ全体で並列に実行されます。Coherenceにはコストベース・オプティマイザ(CBO)が搭載されています。索引のない属性にアクセスするには、オブジェクトをデシリアライズする必要があります(ただし、他の属性に索引を付けると、評価が必要なオブジェクトを減らすことができます)。

12.2 単純な問合せ

キャッシュの内容を問い合せる操作は、例12-1に示すように非常に単純です。

例12-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を使用すると、クライアントに送信されるデータ量を制限できるほか、ユーザー側でページングを実現できます。

例12-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);

問合せ可能な属性には、addIndexクラスのQueryMapメソッドで索引を付けることができます。

例12-3 問合せ可能な属性に対する索引付け

// addIndex(ValueExtractor::View vExtractor, boolean_t fOrdered, Comparator::View vComparator)
hCache->addIndex(hExtractor, true, NULL);

fOrdered引数では、索引構造をソートするかどうかを指定します。ソートされた索引は、「2つの日付の間に収まるエントリをすべて選択」や「姓がSで始まる従業員をすべて選択」などの範囲問合せに役立ちます。等価問合せの場合は、順序付けられていない索引を使用できます。この索引を使用すると、領域と時間の面で効率が向上することがあります。

comparator引数は、索引の順序付け用にカスタムのjava.util.Comparatorを指定します。


注意:

このメソッドは、単にキャッシュ実装のヒントとして示したものであり、索引がサポートされていない場合や目的の索引(またはそれに類似した索引)が存在する場合は、キャッシュによって無視されることがあります。アプリケーションでは、確実に索引が提示されるようにするために、索引が存在する場合でもこのメソッドをコールして索引を提示することが求められます。たとえば、分散環境では各サーバーが起動時に同じ索引セットを提示する可能性があり、別のサーバーが同じ索引を要求しているかどうかに関係なく、アプリケーションがそれらの索引を不必要に要求しても不都合は生じません。

Coherenceでは必要に応じて問合せを結合することができます。またCoherenceには、索引の使用優先順位を決めるコストベース・オプティマイザ(CBO)が搭載されています。索引を利用するには、問合せで使用されているエクストラクタと同等((Object->equals())のエクストラクタを、同じ問合せで使用する必要があります。

12.2.1 パーティション・キャッシュの問合せ

パーティション・キャッシュは、Parallel Query機能を使用してQueryMapインタフェースを実行するため、大きなデータセットでも高性能の問合せが可能です。

12.2.2 ニア・キャッシュの問合せ

ニア・キャッシュを通じて問合せを実行することは可能ですが、問合せではニア・キャッシュのフロント部分が使用されません。問合せでニア・キャッシュを使用する場合は、次のシーケンスを使用するのが最適のアプローチです。

Set::View vSetKeys   = hCache->keySet(vFilter);
Map::View vMapResult = hCache->getAll(vSetKeys);

12.3 問合せの概念

この項では、問合せインタフェースの設計について、コアなコンポーネントから順に詳しく説明していきます。

問合せ処理の概念は、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"));

特定のフィルタに適合するキャッシュ・エントリを選択する方法は次のとおりです。

例12-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;
    }

エントリを選択してソートする方法は次のとおりです。

例12-5 エントリの選択およびソート

// entrySet(Filter::View vFilter, Comparator::View vComparator)
Iterator::Handle hIter = hCache->entrySet(hEqualsFilter, NULL)->iterator();

NULL引数を追加することで、キャッシュ内の比較可能なオブジェクトの自然な順序で結果セットをソートするように指定しています。クライアントでは、Comparatorの実装を提供することで、結果セットの順序を明示的に指定できます。ソート処理を行う場合は、ソートの前に結果セット全体を取得しておく必要があるために、Coherenceで適用できる最適化が著しく制限されるので注意してください。

keySet形式の問合せをgetAll()と組み合せることで、メモリー使用量をより細かく制御できます。

例12-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();
        }
    }

12.4 複数値属性が関係する問合せ

Coherenceでは、コレクションや配列を含めた複数値属性の索引付けおよび問合せがサポートされています。オブジェクトに索引を付けるときには、そのオブジェクトが複数値タイプかどうかがチェックされてから、シングルトンでなくコレクションとして索引が付けられます。このようなコレクションに対する問合せには、ContainsAllFilterContainsAnyFilterおよびContainsFilterが使用されます。

例12-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
// ...

12.5 ChainedExtractor

ChainedExtractor実装を使用すると、ゼロ引数(アクセッサ)メソッドの連鎖起動が可能となります。例12-8では、エクストラクタはまず、キャッシュされている各Personオブジェクトに対し、リフレクションを使用してgetName()をコールし、返されたStringに対し、リフレクションを使用してlength()をコールします。このエクストラクタを問合せに渡し、(たとえば)名前が10文字以内の人をすべて、問合せで選択することができます。

例12-8 ChainedExtractor実装の使用

ChainedExtractor::Handle hExtractor =
        ChainedExtractor::create(ChainedExtractor::createExtractors("getName.length"));

メソッドの起動は、getName.trim.lengthのように、無限に連鎖させることができます。

12.6 QueryRecorder

QueryRecorderクラスは指定されたフィルタの説明またはトレース・レコードを生成します。このクラスは、クラスタ内のすべてのノードを問い合せ、結果を集約する機能を持つ並列アグリゲータの実装です。このクラスでは2種類のレコードがサポートされています。その1つはQueryRecorder::explainレコードで、問合せ処理の間に実行されたフィルタの評価の見積りコストを提供します。もう1つはQueryRecorder::traceレコードで、問合せ処理の間に実行されたフィルタの評価の実際のコストを提供します。両方の問合せレコードでは、フィルタで索引が使用可能かどうかが考慮されます。EXPLAIN PLANレコードおよびトレース・レコードで提供されるデータの詳細は、『Oracle Coherence開発者ガイド』を参照してください。

問合せレコードを作成するには、RecordTypeパラメータを指定する新しいQueryRecorderインスタンスを作成します。テストするインスタンスとフィルタをAggregateメソッドのパラメータとして含めます。次の例では、説明レコードを作成しています。

NamedCache::Handle hCache = CacheFactory::getCache("MyCache");

IdentityExtractor::View hExtract = IdentityExtractor::getInstance();
OrFilter::Handle hFilter = OrFilter::create(
   GreaterEqualsFilter::create(hExtract, Integer32::create(50)),
   LessEqualsFilter::create(hExtract, Integer32::create(20)));
 
QueryRecord::View vRecord = cast<QueryRecord::View>(hCache->aggregate(
   (Filter::View) hFilter, QueryRecorder::create(QueryRecorder::explain)));

cout << vRecord;

トレース・レコードを作成するには、RecordTypeパラメータをtraceに変更します。

QueryRecord::View vRecord = cast<QueryRecord::View>(hCache->aggregate(
   (Filter::View) hFilter, QueryRecorder::create(QueryRecorder::trace)));