Search API

Starting in Niagara 4, a new SearchService has been added which allows searching for Entities within selectable scopes (ie. spaces) of a station. The Search API is a simple layer on top of Niagara’s query APIs.

SearchService Properties -

In order to invoke a search, the SearchService must be installed on a station. Here is a complete list and description of all of the properties and actions on the SearchService:

Properties:

Actions

Invoking a search from the SearchService

Invoking a search and retrieving results is handled through actions on the SearchService. Here is a simple example:

Simple Search Example

BSearchService searchService = BSearchService.getService(); // Only works on station side, otherwise use service ord scheme to lookup search service
BOrd searchRequest = BOrd.make("neql:n:point"); // the query
BSearchParams searchParams = new BSearchParams(searchRequest, /*scopes*/Sys.getStation());
BOrd searchTaskOrd = searchService.search(searchParams); // Invokes a search and gives you back an ORD to the BSearchTask
 
// Retrieve all results
BSearchResultSet results = null;
while (results == null || !results.getResultsComplete())
{
  Thread.sleep(100); // Give the search some time to complete
 
  // This code asks for all available results at this time, but you could ask for
  // chunks of results by adjusting the startIndex and maxResults arguments
  BResultsRequest resultsRequest = BResultsRequest.make(searchTaskOrd, /*startIndex*/0, /*maxResults*/-1);
  results = searchService.retrieveResults(resultsRequest);
}
 
// Now that we have all of the results, we can do something with them
results.streamResults().forEach(result -> System.out.println("Found a search result: " + ((BSearchResult)result).getOrd()));

Implementing a SearchProvider

By default, the SearchService is intended to work with QuerySchemes that have registered QueryHandlers. This covers common cases for search providers, such as neql. However, there may be other OrdSchemes that can provide search results, such as BQL. In those cases, you can create a BISearchProvider implemention. Here is an excerpt from the BISearchProvider interface.

BISearchProvider

/**
 * A search provider can be used as an alternative to a query scheme to
 * allow for searching spaces in Niagara.  A search provider must be
 * registered as an agent on any BOrdSchemes that it supports AND it
 * must also register as an agent on any scopes (ie. spaces) that it
 * supports searching.
 */
public interface BISearchProvider extends BIAgent
{
  /**
   * Search the specified scope with the given query ORD.
   * When called by a search task via the SearchService, this method
   * is called on an async executor, so you can do the work on the
   * calling thread.
   *
   * @param queryOrd The query ORD to resolve against the given scope
   * @param scope The scope to resolve the query ORD against
   * @param context The context associated with this search request.  Implementers
   *                should extract any user information from this context in order
   *                to filter results to only those permitted to the user.
   */
  Stream<Entity> search(BOrd queryOrd, BIObject scope, Context context);
}

So to create your own search provider, you simply need to be able to stream Entities back in response to a query Ord for a scope. The context is also important for enforcing user permissions on results. For an example implementation of BISearchProvider, see BBqlSearchProvider.