|
Key
This line was removed.
This word was removed. This word was added.
This line was added.
|
Comment:
Changes (0)
View Page HistoryThis section contains the following information:
{toc:maxLevel=2}
h2. Query Functionality
Coherence provides the ability to search for cache entries that meet a given set of criteria. The result set may be sorted if desired. Queries are evaluated with Read Committed isolation.
It should be noted that queries apply only to currently cached data (and will not use the CacheLoader interface to retrieve additional data that may satisfy the query). Thus, the dataset should be loaded entirely into cache before queries are performed. In cases where the dataset is too large to fit into available memory, it may be possible to restrict the cache contents along a specific dimension (for example, "date") and manually switch between cache queries and database queries based on the structure of the query. For maintainability, this is usually best implemented inside a cache-aware data access object (DAO).
Indexing requires the ability to extract attributes on each Partitioned cache node; in the case of dedicated CacheServer instances, this implies (usually) that application classes must be installed in the CacheServer classpath.
For Local and Replicated caches, queries are evaluated locally against unindexed data. For Partitioned caches, queries are performed in parallel across the cluster, using indexes if available. Coherence includes a Cost-Based Optimizer (CBO). Access to unindexed attributes requires object deserialization (though indexing on other attributes can reduce the number of objects that must be evaluated).
h2. Simple Queries
Querying cache content is very simple:
{code:java}
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;
}
{code}
{note:title=Querying Partitioned Caches}
When using the Coherence Enterprise Edition or Grid Edition, the Partitioned Cache implements the QueryMap interface using the Parallel Query feature. When using Coherence Standard Edition, the Parallel Query feature is not available, resulting in lower performance for most queries, particularly when querying large data sets.
{note}
{note:title=Querying Near Caches}
Although queries can be executed through a near cache, the query will not use the front portion of a near cache. If using a near cache with queries, the best approach is to use the following sequence:
{code:java}
Set::View vSetKeys = hCache->keySet(vFilter);
Map::View vMapResult = hCache->getAll(vSetKeys);
{code}
{note}
Coherence provides a wide range of filters in the {doxygen:coherence::util::Filter} package. A {doxygen:coherence::util::filter::LimitFilter|LimitFilter} may be used to limit the amount of data sent to the client, and also to provide "paging" for users:
{code:java}
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);
{code}
Any queryable attribute may be indexed with the {{addIndex}} method of the {doxygen:coherence::util::QueryMap|QueryMap} class:
{code:java}
// addIndex(ValueExtractor::View vExtractor, boolean_t fOrdered, Comparator::View vComparator)
hCache->addIndex(hExtractor, true, NULL);
{code}
The {{fOrdered}} argument specifies whether the index structure is sorted. Sorted indexes are useful for range queries, including "select all entries that fall between two dates" and "select all employees whose family name begins with 'S'". For "equality" queries, an unordered index may be used, which may have better efficiency in terms of space and time.
The {{comparator}} argument can be used to provide a custom {{java.util.Comparator}} for ordering the index.
{info}
This method is only intended as a hint to the cache implementation, and as such it may be ignored by the cache if indexes are not supported or if the desired index (or a similar index) already exists. It is expected that an application will call this method to suggest an index even if the index may already exist, just so that the application is certain that index has been suggested. For example, in a distributed environment each server will likely suggest the same set of indexes when it starts, and there is no downside to the application blindly requesting those indexes regardless of whether another server has already requested the same indexes.
Indexes are a feature of [Coherence Enterprise Edition or higher|Coherence Features by Edition]. This method will have no effect when using [Coherence Standard Edition|Coherence Features by Edition].
{info}
Note that queries can be combined by Coherence if necessary, and also that Coherence includes a cost-based optimizer (CBO) to prioritize the usage of indexes. To take advantage of an index, queries must use extractors that are equal (({{Object->equals()}}) to the one used in the query.
h2. Query Concepts
This section goes into more detail on the design of the query interface, building up from the core components.
The concept of querying is based on the {doxygen:coherence::util::ValueExtractor|ValueExtractor} interface. A value extractor is used to extract an attribute from a given object for the purpose of querying (and similarly, indexing). Most developers will need only the {doxygen:coherence::util::extractor::ReflectionExtractor|ReflectionExtractor} implementation of this interface. The {{ReflectionExtractor}} uses reflection to extract an attribute from a value object by referring to a method name, typically a "getter" method like {{getName()}}.
{code:java}
ReflectionExtractor::Handle hExtractor = ReflectionExtractor::create("getName");
{code}
Any "void argument" method can be used, including {{Object}} methods like {{toString()}} (useful for prototyping/debugging). Indexes may be either traditional "field indexes" (indexing fields of objects) or "functional indexes" (indexing "virtual" object attributes). For example, if a class has field accessors "getFirstName" and "getLastName", the class may define a function "getFullName" which concatenates those names, and this function may be indexed.
To query a cache that contains objects with "{{getName}}" attributes, a {doxygen:coherence::util::Filter|Filter} must be used. A filter has a single method which determines whether a given object meets a criterion.
{code:java}
Filter::Handle hEqualsFilter = EqualsFilter::create(hExtractor, String::create("Bob Smith"));
{code}
To select the entries of a cache that satisfy a particular filter:
{code:java}
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;
}
{code}
To select and also sort the entries:
{code:java}
// entrySet(Filter::View vFilter, Comparator::View vComparator)
Iterator::Handle hIter = hCache->entrySet(hEqualsFilter, NULL)->iterator();
{code}
The additional {{NULL}} argument specifies that the result set should be sorted using the "natural ordering" of {{Comparable}} objects within the cache. The client may explicitly specify the ordering of the result set by providing an implementation of {{Comparator}}. Note that sorting places significant restrictions on the optimizations that Coherence can apply, as sorting requires that the entire result set be available prior to sorting.
Using the {doxygen:coherence::util::QueryMap|keySet} form of the queries -- combined with getAll() -- may provide more control over memory usage:
{code:java}
// 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();
}
}
{code}
h2. Queries Involving Multi-Value Attributes
Coherence supports indexing and querying of multi-value attributes including collections and arrays. When an object is indexed, Coherence will check to see if it is a multi-value type, and will then index it as a collection rather than a singleton. The {doxygen:coherence::util::filter::ContainsAllFilter|ContainsAllFilter} ,{doxygen:coherence::util::filter::ContainsAnyFilter|ContainsAnyFilter} and {doxygen:coherence::util::filter::ContainsFilter|ContainsFilter} are used to query against these collections.
{code:java}
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
// ...
{code}
h2. ChainedExtractor
The {doxygen:coherence::util::extractor::ChainedExtractor|ChainedExtractor} implementation allows chained invocation of zero-argument (accessor) methods.
{code:java}
ChainedExtractor::Handle hExtractor =
ChainedExtractor::create(ChainedExtractor::createExtractors("getName.length"));
{code}
In the example above, the extractor will first use reflection to call {{getName()}} on each cached {{Person}} object, and then use reflection to call {{length()}} on the returned {{String}}. This extractor could be passed into a query, allowing queries (for example) to select all people with names not exceeding 10 letters. Method invocations may be chained indefinitely, for example {{"getName.trim.length"}}.