Overview
-
Custom sorters let you define your own logic for ordering query results.
They are used only when explicitly requested in the query.
If no custom sorter is used, RavenDB orders the results as described in Sort query results. -
Custom sorters are available when using the Lucene indexing engine.
They are not available with the Corax engine. -
Custom sorters can be deployed at one of the following levels:
- Database-level - can be used only by queries made on that database.
- Server-wide - can be used by queries made on any database in your cluster.
-
If a database custom sorter and a server-wide custom sorter have the same name,
the database custom sorter will be used for the query.
Querying with a custom sorter
Learn how to deploy a database-level custom sorter in: Database-level custom sorters.
Learn how to deploy a server-wide custom sorter in: Server-wide custom sorters.
Once deployed, a custom sorter can be specified in a query to sort the results.
- Query
- Query_async
- DocumentQuery
- RQL
List<Product> products = session
.Query<Product>()
.Where(x => x.UnitsInStock > 10)
// Order by field 'UnitsInStock', pass the name of your custom sorter class
.OrderBy(x => x.UnitsInStock, "MyCustomSorter")
.ToList();
// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MyCustomSorter' class
List<Product> products = await asyncSession
.Query<Product>()
.Where(x => x.UnitsInStock > 10)
// Order by field 'UnitsInStock', pass the name of your custom sorter class
.OrderBy(x => x.UnitsInStock, "MyCustomSorter")
.ToListAsync();
// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MyCustomSorter' class
List<Product> products = session.Advanced
.DocumentQuery<Product>()
.WhereGreaterThan(x => x.UnitsInStock, 10)
// Order by field 'UnitsInStock', pass the name of your custom sorter class
.OrderBy(x => x.UnitsInStock, "MyCustomSorter")
.ToList();
// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MyCustomSorter' class
from "Products"
where UnitsInStock > 10
order by custom(UnitsInStock, "MyCustomSorter")
// Results will be sorted by the 'UnitsInStock' value
// according to the logic from 'MyCustomSorter' class
How to write a custom sorter
-
A custom sorter is written in C# and must inherit from
Lucene.Net.Search.FieldComparator. -
The sorter code must be compilable by the server and include all required using statements.
-
The sorter class must be
public, and the sorter name must match the class name in the code.
For example, if the sorter class is namedMyCustomSorter,
then the sorter must be deployed with the nameMyCustomSorter. -
The sorter code is compiled by the server and can only use assemblies that are already available to the server.
Do not reference external NuGet packages or upload additional DLLs. -
The sorter class must include a public constructor with the following signature.
RavenDB uses this constructor to create the sorter instance when the query is executed.public MyCustomSorter(
// The field passed to custom(...) in the query.
string fieldName,
// The number of result slots the sorter needs to track.
int numHits,
// The position of this sorter when multiple sort clauses are used.
int sortPos,
// Indicates whether descending order was requested.
bool reversed,
// Receives diagnostic output when the sorter is executed through
// the Studio "Test Custom Sorter" debug flow.
// In normal queries, this parameter is null.
// This parameter must be included in the constructor signature.
List<string> diagnostics) -
The sorter must implement the required members inherited from
FieldComparator:CompareSetBottomCompareBottomCopySetNextReader- The indexer:
this[int slot]
-
The following example shows the required structure of a custom sorter. It wraps RavenDB's built-in alphanumeric comparator and delegates the actual sorting logic to it. The example is intentionally minimal.
A real custom sorter can replace the delegated calls with its own comparison logic.using System;
using System.Collections.Generic;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Raven.Server.Documents.Queries.Sorting.AlphaNumeric;
// The class name must match the sorter name.
public class MyAlphaNumericSorter : FieldComparator
{
private readonly AlphaNumericFieldComparator _inner;
// RavenDB creates the sorter using this constructor signature.
// All parameters must be present in this order.
public MyAlphaNumericSorter(
string fieldName,
int numHits,
int sortPos,
bool reversed,
List<string> diagnostics)
{
// fieldName is the field passed in the query:
// order by custom(<field>, "MyAlphaNumericSorter")
_inner = new AlphaNumericFieldComparator(fieldName, numHits);
}
// Compare two values already stored in result slots.
public override int Compare(int slot1, int slot2)
{
return _inner.Compare(slot1, slot2);
}
// Set the current bottom slot.
public override void SetBottom(int slot)
{
_inner.SetBottom(slot);
}
// Compare the current bottom slot with a candidate document.
public override int CompareBottom(int doc, IState state)
{
return _inner.CompareBottom(doc, state);
}
// Store the candidate document's sort value in the specified slot.
public override void Copy(int slot, int doc, IState state)
{
_inner.Copy(slot, doc, state);
}
// Load any per-segment state required by the sorter.
public override void SetNextReader(IndexReader reader, int docBase, IState state)
{
_inner.SetNextReader(reader, docBase, state);
}
// Return the sort value stored in the specified slot.
public override IComparable this[int slot]
{
get { return _inner[slot]; }
}
}Once deployed, you can use the custom sorter in a query:
from Companies
order by custom(Name, "MyAlphaNumericSorter")
Testing a custom sorter
You can test a custom sorter from the Studio before using it in queries.
The Studio test flow is available in the database-level custom sorters view. The test is run in the context of a specific database because it executes a query against documents and indexes in that database.
To learn how to test a sorter, see Test custom sorter.