Working with Value Extractors and Simplifying Queries in Oracle Coherence 3.5

0
225
4 min read

Coherence allows you to do look up one or more objects based on attributes other than the identity by specifying a filter for set-based operations defined by the QueryMap interface.

public interface QueryMap extends Map {
Set keySet(Filter filter);
Set entrySet(Filter filter);
Set entrySet(Filter filter, Comparator comparator);
...
}

As you can see from the previous interface definition, all three methods accept a filter as the first argument, which is an instance of a class implementing a very simple com.tangosol.util.Filter interface:

public interface Filter {
boolean evaluate(Object o);
}

Basically, the Filter interface defines a single method, evaluate, which takes an object to evaluate as an argument and returns true if the specified object satisfies the criteria defined by the filter, or false if it doesn’t.

This mechanism is very flexible, as it allows you to filter your cached objects any way you want. For example, it would be quite simple to implement a filter that can be used to retrieve all the account transactions in a specific period:

public class TransactionFilter implements Filter {
private Long m_accountId;
private Date m_from;
private Date m_to;
public TransactionFilter(Long accountId, Date from, Date to) {
m_accountId = accountId;
m_from = from;
m_to = to;
}
public boolean evaluate(Object o) {
Transaction tx = (Transaction) o;
return tx.getId().getAccountId().equals(m_accountId)
&& tx.getTime().compareTo(from) >= 0
&& tx.getTime().compareTo(to) <= 0;
}
}

While the previous sample filter implementation is perfectly valid and will return correct results if executed against the transactions cache, it would be very cumbersome if you had to define every single query criterion in the application by implementing a custom filter class as we did previously.

Fortunately, Coherence provides a number of built-in filters that make custom filter implementation unnecessary in the vast majority of cases.

Built-in filters

Most queries can be expressed in terms of object attributes and standard logical and relational operators, such as AND, OR, equals, less than, greater than, and so on. For example, if we wanted to find all the transactions for an account, it would be much easier if we could just execute the query analogous to the select * from Transactions where account_id = 123 SQL statement than to write a custom filter that checks if the accountId attribute is equal to 123.

The good news is that Coherence has a number of built-in filters that allow us to do exactly that. The following table lists all the filters from the com.tangosol.util.filter package that you can use to construct custom queries:

As you can see, pretty much all of the standard Java logical operators and SQL predicates are covered. This will allow us to construct query expressions as complex as the ones we can define in Java code or the SQL where clause.

The bad news is that there is no query language in Coherence that allows you to specify a query as a string. Instead, you need to create the expression tree for the query programmatically, which can make things a bit tedious.

For example, the where clause of the SQL statement we specified earlier, select * from Transactions where account_id = 123, can be represented by the following Coherence filter definition:

Filter filter = new EqualsFilter("getId.getAccountId", 123);

In this case it is not too bad: we simply create an instance of an EqualsFilter that will extract the value of an accountId attribute from a Transaction.Id instance and compare it with 123. However, if we modify the query to filter transactions by date as well, the filter expression that we need to create becomes slightly more complex:

Filter filter = new AndFilter(
new EqualsFilter("getId.getAccountId", accountId),
new BetweenFilter("getTime", from, to));

If you need to combine several logical expressions, this can quickly get out of hand, so we will look for a way to simplify filter creation shortly. But first, let’s talk about something we used in the examples without paying much attention to it—value extractors.

Value extractors

As you can see from the previous examples, a query is typically expressed in terms of object attributes, such as accountId or time, while the evaluate method defined by the Filter interface accepts a whole object that the attributes belong to, such as a Transaction instance.

That implies that we need a generic way to extract attribute values from an object instance—otherwise, there would be no way to define reusable filters, such as the ones in the table earlier that ship with Coherence, and we would be forced to implement a custom filter for each query we need to execute. In order to solve this problem and enable extraction of attribute values from an object, Coherence introduces value extractors.

A value extractor is an object that implements a com.tangosol.util.ValueExtractor interface:

public interface ValueExtractor {
Object extract(Object target);
}

The sole purpose of a value extractor is to extract a derived value from the target object that is passed as an argument to the extract method . The result could be a single attribute value, a combination of multiple attributes (concatenation of first and last name, for example), or in general, a result of some transformation of a target object.

LEAVE A REPLY

Please enter your comment!
Please enter your name here