データ・アフィニティは、関連するキャッシュ・エントリ・グループが単一のキャッシュ・パーティションに含まれることを保証する概念を表します。これにより、フォルト・トレランスを犠牲にすることなく、すべての関連データが単一のプライマリ・キャッシュ・ノードで管理されます。
同じキャッシュ・サービスで管理されている場合、アフィニティは通常、複数のキャッシュにまたがります。たとえば、Order-LineItemのようなマスター/ディテール・パターンでは、Orderオブジェクトが、関連付けられているLineItemオブジェクトのコレクション全体と共存する場合があります。
これには、2つの利点があります。まず、一連の関連項目に対する問合せおよびトランザクションを、単一のキャッシュ・ノードのみで管理できます。また、すべての並行操作がローカルで管理可能なため、クラスタ化された同期処理が不要です。
キャッシュ問合せ、InvocableMap
操作、getAll
、putAll
およびremoveAll
の各メソッドなど、Coherenceには、アフィニティの恩恵を受ける各種の標準操作があります。
注意: データ・アフィニティは、値ではなくエントリ・キーに関して指定されます。その結果、対応付け情報がキー・クラスに存在している必要があります。同様に、対応付けロジックは、値クラスではなくキー・クラスに適用されます。 |
アフィニティは、パーティション・キーとの関係で指定されます。前述のOrder
-LineItem
の例では、Order
オブジェクトが正常にパーティション化され、LineItem
オブジェクトは適切なOrder
オブジェクトと関連付けられます。
この対応付けを実際の親キーに直接関連付ける必要はなく、親キーの機能マッピングになるだけで十分です。親キーの単一フィールド(一意でない場合でも可能)、または親キーの整数ハッシュを使用できます。重要なのは、すべての子キーで同じ関連キーを返すことだけです。関連キーが実際のキーであるかどうかは重要ではありません(このキーは、単なるグループIDになる)。これにより、親キーの情報を含まない子キー・クラスのサイズを最小限に抑えることができます(導出データであるため、データ・サイズを明示的に決定できるほか、キー動作への影響はない)。対応付けを汎用化しすぎると(同じグループIDに関連付けられたキーが多すぎる場合)、均一に分散されないことがあります(親キーに関係なく、すべての子キーが同じ対応付けキーを返した場合、子キーはすべて単一パーティションに割り当てられ、クラスタ全体には分散されない)。
一連のキャッシュ・エントリが共存していることを確認するには、2つの方法があります。対応付けが、値ではなくキャッシュ・キーに基づいていることを確認します(そうでない場合、キャッシュ・エントリを更新するとパーティションが変更される可能性がある)。また、Order
が子LineItems
と共存していても、Coherenceでは複数のキャッシュにまたがった複合操作(たとえば、Order
とLineItems
のコレクションを単一の起動リクエストcom.tangosol.util.InvocableMap.EntryProcessor
で更新する操作など)が現時点でサポートされていないことを確認します。
アプリケーションで定義されたキーの場合、キャッシュ・キーのクラスでは、com.tangosol.net.cache.KeyAssociation
が次のように実装されることがあります。
アプリケーションでカスタムのKeyAssociator
が提供されている場合もあります。
例5-2 カスタムのKeyAssociator
import com.tangosol.net.partition.KeyAssociator; public class LineItemAssociator implements KeyAssociator { public Object getAssociatedKey(Object oKey) { if (oKey instanceof LineItemId) { return ((LineItemId) oKey).getOrderId(); } else if (oKey instanceof OrderId) { return oKey; } else { return null; } } public void init(PartitionedService service) { } }
キー・アソシエータは、NamedCache
に関して、関連付けられている<distributed-scheme>要素で構成できます。
例5-4は、アフィニティを使用してより効率的な問合せ(NamedCache.entrySet(Filter)
)およびキャッシュ・アクセス(NamedCache.getAll(Collection)
)を作成する方法を示しています。
例5-4 アフィニティを使用した効率的な問合せの作成
OrderId orderId = new OrderId(1234); // this Filter will be applied to all LineItem objects to fetch those // for which getOrderId() returns the specified order identifier // "select * from LineItem where OrderId = :orderId"Filter filterEq = new EqualsFilter("getOrderId", orderId); // this Filter will direct the query to the cluster node that currently owns // the Order object with the given identifier Filter filterAsc = new KeyAssociatedFilter(filterEq, orderId); // run the optimized query to get the ChildKey objects Set setLineItemKeys = cacheLineItems.keySet(filterAsc); // get all the Child objects immediately Set setLineItems = cacheLineItems.getAll(setLineItemKeys); // Or remove all immediately cacheLineItems.keySet().removeAll(setLineItemKeys);