Synchronous, asynchronous, and cursored search
You can run a search by using any of the following methods: synchronous, asynchronous, or cursored search. You can start a search through method calls or by sending an event.
There are three types of search:
- Synchronous search
- Sends the query to the server and obtains all results before returning. This type of search is the simplest form of search, but it might require a long time to run depending on the number of results obtained. It is recommended for small result sets or in cases in which an application requires the entire result set to be retrieved before displaying it.
- Asynchronous search
- Sends the query to the server and then immediately returns. A secondary thread is created internally, and callbacks are made to a callback class provided to indicate that results have arrived. The callback class is called with portions of the result set until all query results have been returned. Using this type of search typically allows faster first-page display for queries.
- Cursored search
- Sends the query to the server and obtains a cursor that can be used to retrieve the results from the server when required. This type of search is like an asynchronous search but it requires the application to pull the results from the server, rather than having them pushed by the server by using a callback. Additional resources are required on the server for maintaining the search results for this type of search. The cursored search is recommended for searches that are expected to have large result sets. The reason for this is that only a cursored query allows you the option of iterating through the result set without having the entire result set loaded into memory at the same time. Synchronous and asynchronous searches both use collections that maintain a reference to the item until you clear the query results. Only the cursor allows you to process the entire result set without maintaining references to all the items. The Java™ beans sample TCursorSearch demonstrates the best usage strategies to minimize the amount of memory used when processing the results.
Starting a search
To initiate a query string search using methods, set the properties on the bean for synchronous or asynchronous search, maximum search results, and the version. For simple searches, you can call generateQueryExpression method to obtain a query string for searching an entity by specifying a set of attribute names, operators, and attribute values. Otherwise, you must generate the query string yourself.
You can use the following methods for different search operations:
- setQueryString
- Queries string-based search.
- runQuery
- Starts a search.
- getResults
- Obtains the results of synchronous searches. The getResults method returns a CMBResultData object. For asynchronous searches, the CMBSearchReplyEvents are also generated when the results are obtained from the server. The frequency of these events is set using the setCallbackThreshold method.
- CMBResultData.setResults
- Provides the results to the CMBSearchResults bean.
- CMBResultData.getResultObject()
- Obtains the CMBResultSetCursor from a cursor search. The CMBResultData.getResultObject() method processes the query results by iterating through the cursor. Use the CMBSearchResults bean to process the results for non-cursored searches and the CMBSearchResults.setResults method to provide the results to the CMBSearchResults bean.
To cancel an asynchronous query, you can call the CMBQueryService.cancelQuery() method. For Content Manager V8 datastores, calling the CMBQueryService.cancelQuery() method stops the query operation on the server and frees the resources that were used to run the query.
You can also set a timeout on the CMBQueryService bean that defines the maximum amount of time you want a query to run on the server. If the query takes longer than the defined timeout value, the search operation is stopped and an error is returned. For synchronous searches, a CMBException message is thrown, with an error code indicating that the query timed out.
Synchronous search example
The following code segment illustrates setting a synchronous query string search and iterating through the results:
CMBQueryService queryService = connection.getQueryService();
queryService.setAsynchSearch(false);// synchronous search
queryService.setMaxResults(1000);// limit the result set
queryService.setVersion(CMBBaseConstant.CMB_LATEST_VERSION);
// only return the most recent version of an item
CMBQueryService.QueryCriterion crit1 =
queryService.new QueryCriterion("Source", "=",
new String[] {"Import"});
String queryString = queryService.generateQueryExpression
("NOINDEX", new CMBQueryService.QueryCriterion[] {crit1},
CMBBaseConstant.CMB_QS_TYPE_XPATH, true);
queryService.setQueryString(queryString,
CMBBaseConstant.CMB_QS_TYPE_XPATH);
queryService.runQuery();
CMBResultData results = (CMBResultData)queryService.getResults();
// results are always a CMBResultData object
CMBSearchResults searchResults = new CMBSearchResults();
searchResults.setConnection(connection);
searchResults.newResults(results);
for (int i = 0; i < searchResults.getCount(); i++)
{
CMBItem item = searchResults.getItem(i);
}Asynchronous search example
To run this query using asynchronous search, you would essentially use the same process. The only difference is that you would receive the results in a callback class rather than getting them from the CMBQueryService bean.
See the following example of how to run this query asynchronously:
// First define the search callback class
class SearchReplyListener implements CMBSearchReplyListener {
CMBQueryService queryService;
CMBSearchResults searchResults;
public SearchReplyListener(CMBQueryService queryService,
CMBSearchResults searchResults) {
this.queryService = queryService;
this.searchResults = searchResults;
}
public void onCMBSearchReply(CMBSearchReplyEvent evt) {
try {
if (evt.getStatus() == CMBBaseConstant.CMB_STATUS_RESULT_NEW) {
// Always use newResults for the first set of results
searchResults.newResults(queryService.getResults());
} else if (evt.getStatus() == CMBBaseConstant.CMB_STATUS_RESULT_MORE) {
searchResults.appendResults(queryService.getResults());
} else if (evt.getStatus() == CMBBaseConstant.CMB_STATUS_RESULT_END) {
searchResults.appendResults(queryService.getResults());
}
else if (evt.getStatus() == CMBBaseConstant.CMB_STATUS_FAILED) {
Throwable t = (Throwable)evt.getData();
if (t != null)
t.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}Run the query by using the following code example:
CMBQueryService queryService = connection.getQueryService();
CMBSearchResults searchResults = new CMBSearchResults();
searchResults.setConnection(connection);
queryService.setAsynchSearch(true); // asynchronous search
queryService.setMaxResults(1000); // limit the result set
queryService.setVersion(CMBBaseConstant.CMB_LATEST_VERSION);
// only return the most recent version of an item
CMBQueryService.QueryCriterion crit1 =
queryService.new QueryCriterion("Source", "=", new String[]
{"Import"});
String queryString = queryService.generateQueryExpression
("NOINDEX", new CMBQueryService.QueryCriterion[] {crit1},
CMBBaseConstant.CMB_QS_TYPE_XPATH, true);
queryService.setQueryString(queryString, CMBBaseConstant.CMB_QS_TYPE_XPATH);
queryService.addCMBSearchReplyListener
(new SearchReplyListener(queryService, searchResults));
queryService.runQuery();Cursored search example
The AsynchSearch property is not applicable to cursored queries. To run the same query as the previous example by using a cursor, perform the following steps:
CMBQueryService queryService = connection.getQueryService();
queryService.setMaxResults(1000); // limit the result set
// only return the most recent version of an item
queryService.setVersion(CMBBaseConstant.CMB_LATEST_VERSION);
CMBQueryService.QueryCriterion crit1 = queryService.new QueryCriterion
("Source", "=", new String[] {"Import"});
String queryString = queryService.generateQueryExpression("NOINDEX",
new CMBQueryService.QueryCriterion[] {crit1},
CMBBaseConstant.CMB_QS_TYPE_XPATH, true);
queryService.setQueryString(queryString, CMBBaseConstant.CMB_QS_TYPE_XPATH);
queryService.runQueryWithCursor();
// results are always a CMBResultData object
CMBResultData results = (CMBResultData)queryService.getResults();
// To get the memory benefits of using a cursor, you must use the
// CMBResultSetCursor to iterate through the results
CMBResultSetCursor cursor = (CMBResultSetCursor)data.getResultObject();
while (cursor.isValid() && !cursor.isEnd()) {
CMBItem result = cursor.fetchNext();
}