PreEmptive Analytics Workbench User Guide

Custom Patterns

Each Query offered by the Query API typically relates to a specific scenario - features, sessions, exceptions, and so on. However, some pieces of information are useful in many Queries; for example, it's very useful to filter all data by Application, or Date Range. To publish and provide this data for retrieval, across all Queries, the Workbench offers an Enhanced API construct, the Pattern.

A Pattern adds additional definitions to all Indexers, all Queries, or both:

Patterns themselves cannot extract data from incoming messages, and must rely on Indexers to do so. To facilitate Pattern data being applied to as much data as possible, any fields that are defined by Indexers and used by Patterns will be copied down to children, regardless of the allowCopyToChildren setting for that field.

Example

The following example demonstrates the steps for creating a Custom Pattern, by modifying the Sample Indexer (installed as part of the Sample Plugin).

Goal

Our Sample Indexer and Sample Query examples allowed us to track application runs by Available Memory. If we want to track all of our data by Available Memory, we can convert these components into a Pattern instead.

Step 1: Remove Own Output Schema

For our example, we will re-use the Sample Indexer created in the Custom Indexer page, and convert it into a Pattern, while still retaining the relevant extraction code from the Indexer.

Our first step is to stop our Indexer from publishing data on its own, because that data will instead be correlated over a variety of scenarios, rather than just Application Runs. To do this, we define our Output Schemas as null.

public override OutputSchema[] DefineOutputSchemas()
{
    return null;
}

Step 2: Augment Indexers

If a Pattern modifies Indexers, it implements AggregationInterfaces.Schema.IIndexerPattern. The method defined by this interface, ExtendOutputSchemaWithPattern, takes the array containing all defined OutputSchema objects, and returns another such array for the Workbench to use as well.

Our example is typical: we add our own Pivot Key, MemoryBucket, to each output schema. This ensures that all published data can be filtered and separated by each memory bucket, which we defined per-run in our extraction process.

public const string PatternName = "MemoryPattern";
public OutputSchema[] ExtendOutputSchemaWithPattern(OutputSchema[] outputSchemas)
{
    //Comment out the following line when you want to use the Sample Pattern listed in the documentation walkthrough
    //return null;
    return outputSchemas.Select(outputSchema =>
    {
        var pivotKeys = new HashSet<FieldKey>(outputSchema.PivotKeys)
                        {
                            GetFieldKey(MemoryBucket)
                        };
        return new OutputSchema(outputSchema.Name + "_"+ PatternName, this)
        {
            RequiredFields = outputSchema.RequiredFields,
            PivotKeys = pivotKeys
        };
    }).ToArray();
}

The names we give to these new Schemas are based on the Schema from which they were derived. For instance, the Feature Indexer defines a StartInformation schema on each Feature temp-bin, so our Pattern would add an additional schema to that bin called StartInformation_MemoryPattern.

Step 3: Augment Queries

If a Pattern modifies Queries, it implements AggregationInterfaces.Schema.IQueryPattern. The method defined by this interface, ExtendQuery, takes a single Query object, and returns a list of additional fields to add to that Query's Metadata (QueryMetaData).

In our case, we always add our MemoryBucket field to the given Query. We also add filtering to this field, to allow clients to receive data from only one Memory Bucket at a time.

public FieldMetadata[] ExtendQuery(IQuery query)
{
    return new[]
    {
        new FieldMetadata
        {
            AssociatedFieldKey = GetFieldKey(MemoryBucket),
            FieldName = "MemoryAmount",
            FriendlyName = "Memory Amount",
            DataType = typeof(string),
            Filters = new List<FilterMetadata>()
            {
                new FilterMetadata()
                {
                    Type = FilterType.Many.ToString(),
                    Filter = new PickFilter(new object[0])
                }
            }
        }
    };
}

Because all Queries will now have this field available, there isn't a need for the original Sample Query we created - it can be removed or commented out.

Note: Be sure to choose FieldNames that will be unique across every other Query that is available in the Workbench. If you use a FieldName that is likely to be used by another query (e.g. Count) then it will cause a conflict with that query's normal data.

Step 4: Update Portal

Once you have a pattern indexer working and exposed via a Server Query, you'll need to update the Portal to make use of it. The most common way is to add a table widget with the filter option (and update the report configuration with an appropriate filters.fields value), which will allow filtering the entire Portal by the data from the pattern.

Limitations

There are a few limitations to using Patterns:



Workbench Version 1.2.0. Copyright © 2016 PreEmptive Solutions, LLC