See the WebSphere eXtreme Scale Wiki for links to eXtreme Scale Version 7.0 documentation.
If you log in
with your developerWorks ID, you can leave comments and feedback for the development team.
ObjectGrid V6.1 introduces enhanced query capabilities for entities that are stored in the ObjectGrid. The syntax is mostly compatible with the Java Persistence API (JPA) standard. With these queries, objects can be retrieved by using non-key or partial-key attributes, and can perform simple aggregations, such as sum/avg/min/max, against all the data that matches a query. Applications can construct a query by using the EntityManager.createQuery
API method, which returns a Query object that can then be invoked to obtain the query results. The query object also customizes the query before actually issuing the query. The query is issued automatically when any method that is returning the result is called.
How are query results stored?
Query results are basically a list of attributes. For example, the query select a,b,c from X where y=z returns a list of rows that contain a, b, and c. This list is actually stored in a transaction-scoped ObjectMap, where the key is a long row identifier in Tuple
form and the value contains the query result attributes, also in tuple form. Obtain the map by using the Query.getResultMap() method. The map is associated with an EntityMetadata
, which describes the content of each row in the map that is associated with it. The following example illustrates a query that retrieves specific parts of the matching Customers and how to access the resulting rows:
Query q = em.createQuery("select c.id, c.firstName, c.surname from Customer c where c.surname=?1");
q.setParameter(1, "Claus");
Iterator iter = q.getResultIterator();
while(iter.hasNext())
{
Object[] row = (Object[])iter.next();
System.out.println("Found a claus with id " + row[ 0 ] + ", firstName: " + row[ 1 ] + ", surname: " + row[ 2 ]);
}
If you use the Query object to access the data, the generated long row identifier is hidden. The long is visible only when you use the ObjectMap to access the result. After the transaction completes, this Map disappears.
Additionally, the Map is also visible only to the Session that is being used, such as the thread that creates it. The Map uses a tuple for the key that contains a single attribute, and a long that contains the row ID. The value is another tuple that contains attribute for each column in the result set, as illustrated in the following example:
Query q = em.createQuery("select c.id, c.firstName, c.surname from
Customer c where c.surname=?1");
q.setParameter(1, "Claus");
ObjectMap qmap = q.getResultMap();
Tuple keyTuple = qmap.getEntityMetadata().getKeyMetadata().createTuple();
for(long i = 0; true; ++i)
{
keyTuple.setAttribute(0, new Long(i));
Tuple row = (Tuple)qmap.get(keyTuple);
if(row == null) break;
System.out.println(" I Found a claus with id " + row.getAttribute(0) + ", firstName: " + row.getAttribute(1) + ", surname: " + row.getAttribute(2));
}
The query and the loop now retrieves each result row by using the normal Map APIs. Because the key for the Map is a tuple, create one by completing the following steps:
- Issue the createTuple method result in keyTuple.
- Retrieve all of the rows that have a row ID that begins at 0. The loop is complete when you receive a null return, which indicates that the key is not found.
- Set the first attribute of keyTuple as the long attribute that you want to find. The value returned by get is also a tuple that contains an attribute for each column in the query result.
- Issue the getAttribute method to obtain each attribute from the value tuple.
Projecting query result rows to Objects
In the following example, each query row returns as a CustomerQueryResult object rather than an Object.
Query q2 = em.createQuery("select c.id, c.firstName, c.surname from Customer c where c.surname=?1");
q2.setResultEntityName("CustomerQueryResult");
q2.setParameter(1, "Claus");
Iterator iter2 = q2.getResultIterator(CustomerQueryResult.class);
while(iter2.hasNext())
{
CustomerQueryResult row = (CustomerQueryResult)iter2.next();
System.out.println("Found a claus with id " + row.id + ", firstName: " + row.firstName + ", surname: " + row.surname);
}
em.getTransaction().commit();
In the next example, ResultEntityName is specified in the query, which signals the query engine to project each row to a specific object. In this case, the specific object CustomerQueryResult:
@Entity
public class CustomerQueryResult {
@Id long rowId;
String id;
String firstName;
String surname;
};
The results of the query are projected to the CustomerQueryResult object. Do not register query result entities with ObjectGrid during the system startup process to avoid creating a global map with the same name, which causes the query to not complete. Additionally, a PersistenceException will be thrown, indicating that the map name is a duplicate.
© Copyright IBM Corporation 2007,2009. All Rights Reserved.