PreEmptive Analytics Workbench User Guide

Custom Queries

The Workbench Query Service interfaces with the Mongo database to provide the Query API that is used by the portal. The service exposes a set of default Server Queries, but additional custom queries can be created and used by the portal's own queries. In general, each new custom indexer will also require a new custom query.

This section walks through the steps for creating a Sample Query (installed as part of the Sample Plugin) for the Sample Indexer we created in an earlier example.

Goal

Recall that the Output Schema for the sample Indexer defined MemoryBucket as a Pivot Key and one data field (ApplicationRunStartCount). Now that the Indexer is ready to publish data to permanent storage, we need a way for Query API clients, such as the Portal, to access these results.

Step 1: Create Query Class

Server Queries implement the interface AggregationInterfaces.Querying.IQuery.

As we will be referring to database-backed fields later in this class, we also use a constructor that takes a FieldKeyFactory instance. As with the Indexer, the Workbench will automatically provide an instance of this object when this Query object is created.

private readonly FieldKeyFactory _fieldKeyFactory;
public SampleQuery(FieldKeyFactory fieldKeyFactory)
{
    _fieldKeyFactory = fieldKeyFactory;
}

Step 2: Define Associated Indexers

Next, we indicate which Indexers must be installed in order for this Query to function properly.

public Type[] DefinePrerequisiteIndexers()
{
    return new[] {typeof (SampleIndexer)};
}

Step 3: Define Query Domain

Each Query object specifies a Domain to clarify its intent and relationship to other Queries. Note that this Domain is not to be confused with the Namespace used by Indexers and database-backed fields. Domains are specifically for organizing Queries exposed through the Query API.

public string Domain
{
    get { return "PreEmptive.Sample"; }
}

Step 4: Define Query Metadata

Finally, we define the actual Query by its metadata: its name and its fields. For this simple example, we will only define two fields, each backed by a database field. Note, however, that Patterns automatically supplement all available Queries; hence, when the Query is activated it will actually have several more fields.

public QueryMetadata QueryMetaData
{
    get 
    {
        return new QueryMetadata
        {
            Name = "Application Runs By Memory",
            Fields = new List<FieldMetadata>
            {
                new FieldMetadata
                {
                    AssociatedFieldKey = _fieldKeyFactory.GetFieldKey(SampleIndexer.Namespace, SampleIndexer.MemoryBucket),
                    FieldName = "MemoryBucket",
                    FriendlyName = "Memory Amount",
                    DataType = typeof(string)
                },
                new FieldMetadata
                {
                    AssociatedFieldKey = _fieldKeyFactory.GetFieldKey(ApplicationRunIndexer.Namespace, ApplicationRunIndexer.ApplicationRunStartCount),
                    FieldName = "ApplicationRunStartCount",
                    FriendlyName = "Application Run Start Count",
                    DataType = typeof(int)
                }
            }
        };
    }
}

We give this Query the name Application Runs By Memory and two fields: MemoryBucket and ApplicationRunStartCount. Note that the field names:

  • Cannot contain whitespace, and
  • Do not need to match up with the name of the associated database field (which is linked separately, in the AssociatedFieldKey property). This allows Queries to stay the same even if the internal structure of calculation changes.

The DataType is the type of data that will be returned (unless we use query transforms, it must match the data type of the associated database field).

The FriendlyName field is optional and provides a human-readable label to the field.

Step 5: Deploy with Indexer

See Step 7 of the Indexer instructions.



Workbench Version 1.2.0. Copyright © 2016 PreEmptive Solutions, LLC