Skip to main content

Session: Querying: How to Perform a Faceted (Aggregated) Search

To execute facet (aggregation) query using the session Query method, use the AggregateBy or AggregateUsing methods. This will scope you to the aggregation query builder where you will be allowed to define single or multiple facets for the query using a straightforward and fluent API.

Syntax

IAggregationQuery<T> AggregateBy<T>(FacetBase facet);

IAggregationQuery<T> AggregateBy<T>(IEnumerable<FacetBase> facets);

IAggregationQuery<T> AggregateBy<T>(Action<IFacetBuilder<T>> builder);

IAggregationQuery<T> AggregateUsing<T>(string facetSetupDocumentKey);
Parameters
facetFacetBaseFacetBase implementation defining the scope of the facet and its options (either Facet or RangeFacet)
facetsIEnumerable<FacetBase>Enumerable containing FacetBase implementations
builderAction<IFacetFactory<T>>Builder with a fluent API that constructs a FacetBase instance
facetSetupDocumentIdstringID of a document containing FacetSetup

Facet & RangeFacet

RangeFacet allows you to split the results of the calculations into several ranges, in contrast to Facet where whole spectrum of results will be used to generate a single outcome.

public class Facet
{
public string FieldName { get; set; }

public FacetOptions Options { get; set; }

public Dictionary<FacetAggregation, string> Aggregations { get; set; }

public string DisplayFieldName { get; set; }
}

public class Facet<T>
{
public Expression<Func<T, object>> FieldName { get; set; }

public FacetOptions Options { get; set; }

public Dictionary<FacetAggregation, string> Aggregations { get; set; }

public string DisplayFieldName { get; set; }
}

Builder

IFacetOperations<T> ByRanges(Expression<Func<T, bool>> path, params Expression<Func<T, bool>>[] paths);

IFacetOperations<T> ByField(Expression<Func<T, object>> path);

IFacetOperations<T> ByField(string fieldName);

IFacetOperations<T> WithDisplayName(string displayName);

IFacetOperations<T> WithOptions(FacetOptions options);

IFacetOperations<T> SumOn(Expression<Func<T, object>> path);

IFacetOperations<T> MinOn(Expression<Func<T, object>> path);

IFacetOperations<T> MaxOn(Expression<Func<T, object>> path);

IFacetOperations<T> AverageOn(Expression<Func<T, object>> path);
Parameters
pathstringPoints to the index field that should be used for operation (ByRanges, ByField) or to document field that should be used for aggregation (SumOn, MinOn, MaxOn, AverageOn)
fieldNamestringPoints to the index field that should be used for operation (ByRanges, ByField) or to document field that should be used for aggregation (SumOn, MinOn, MaxOn, AverageOn)
displayNamestringIf set, results of a facet will be returned under this name
optionsFacetOptionsNon-default options that should be used for operation

Options

public FacetTermSortMode TermSortMode { get; set; } = FacetTermSortMode.ValueAsc;

public bool IncludeRemainingTerms { get; set; }

public int Start { get; set; }

public int PageSize { get; set; } = int.MaxValue;
Options
TermSortModeFacetTermSortModeIndicates how terms should be sorted (ValueAsc, ValueDesc, CountAsc, CountDesc)
IncludeRemainingTermsboolIndicates if remaining terms should be included in results
StartintUsed to skip given number of facet results in the outcome
PageSizeintUsed to limit facet results to the given value

Example I

Dictionary<string, FacetResult> facets = session
.Query<Camera>("Camera/Costs")
.AggregateBy(new Facet
{
FieldName = "Manufacturer",
Options = new FacetOptions
{
TermSortMode = FacetTermSortMode.CountDesc
}
})
.AndAggregateBy(new RangeFacet<Camera>
{
Ranges =
{
camera => camera.Cost < 200m,
camera => camera.Cost >= 200m && camera.Cost < 400m,
camera => camera.Cost >= 400m && camera.Cost < 600m,
camera => camera.Cost >= 600m && camera.Cost < 800m,
camera => camera.Cost >= 800m
},
Aggregations =
{
{ FacetAggregation.Average, "Cost" }
}
})
.AndAggregateBy(new RangeFacet<Camera>
{
Ranges =
{
camera => camera.Megapixels < 3.0,
camera => camera.Megapixels >= 3.0 && camera.Megapixels < 7.0,
camera => camera.Megapixels >= 7.0 && camera.Megapixels < 10.0,
camera => camera.Megapixels >= 10.0
}
})
.Execute();

Example II

Dictionary<string, FacetResult> facets = session
.Query<Camera>("Camera/Costs")
.AggregateBy(builder => builder
.ByField(x => x.Manufacturer)
.WithOptions(new FacetOptions
{
TermSortMode = FacetTermSortMode.CountDesc
}))
.AndAggregateBy(builder => builder
.ByRanges(
camera => camera.Cost < 200m,
camera => camera.Cost >= 200m && camera.Cost < 400m,
camera => camera.Cost >= 400m && camera.Cost < 600m,
camera => camera.Cost >= 600m && camera.Cost < 800m,
camera => camera.Cost >= 800m)
.AverageOn(x => x.Cost))
.AndAggregateBy(builder => builder
.ByRanges(
camera => camera.Megapixels < 3.0,
camera => camera.Megapixels >= 3.0 && camera.Megapixels < 7.0,
camera => camera.Megapixels >= 7.0 && camera.Megapixels < 10.0,
camera => camera.Megapixels >= 10.0))
.Execute();

Example III

session.Store(new FacetSetup
{
Facets = new List<Facet>
{
new Facet
{
FieldName = "Manufacturer"
}
},
RangeFacets = new List<RangeFacet>
{
new RangeFacet<Camera>
{
Ranges =
{
camera => camera.Cost < 200m,
camera => camera.Cost >= 200m && camera.Cost < 400m,
camera => camera.Cost >= 400m && camera.Cost < 600m,
camera => camera.Cost >= 600m && camera.Cost < 800m,
camera => camera.Cost >= 800m
}
},
new RangeFacet<Camera>
{
Ranges =
{
camera => camera.Megapixels < 3.0,
camera => camera.Megapixels >= 3.0 && camera.Megapixels < 7.0,
camera => camera.Megapixels >= 7.0 && camera.Megapixels < 10.0,
camera => camera.Megapixels >= 10.0
}
}
}
}, "facets/CameraFacets");

session.SaveChanges();

Dictionary<string, FacetResult> facets = session
.Query<Camera>("Camera/Costs")
.AggregateUsing("facets/CameraFacets")
.Execute();

Remarks

AggregateBy only supports aggregation by a single field. If you want to aggregate by multiple fields, you need to emit a single field that contains all values.