Creating and Deploying Indexes
-
This article explains how to create indexes in RavenDB.
For a general overview of indexes, see What are indexes. -
You can either:
- create a Static-index yourself, which involves Defining the index and Deploying it to the RavenDB server, or
- let the RavenDB server create an Auto-index for you based on query patterns.
-
Static-indexes can be created:
- using the Client API, as outlined in this article, or
- from the Indexes list view in the Studio.
Define a static-index
Static-indexes
- Indexes that are explicitly created by the user are called
static
indexes. - Static-indexes can perform calculations, data conversions, and other processes behind the scenes.
This reduces the workload at query time by offloading these costly operations to the indexing phase. - To query with a static-index, you must explicitly specify the index in the query definition.
For more details, see Querying an index.
Define a static-index using a custom class
- To define a static-index using a custom class inherit from
AbstractIndexCreationTask
. -
This method is recommended over the Creating an index using an operation method
for its simplicity and the following advantages:- Strongly-typed syntax:
Provides strong typing when defining the index, making it easier to work with. - Ease of querying:
Lets you use the index class name in a query, instead of hard-coding the index name.// Define a static-index // Inherit from 'AbstractIndexCreationTask' public class Orders_ByTotal : AbstractIndexCreationTask<Order> { // ... }
- Strongly-typed syntax:
- A complete example of creating a static-index is provided below.
Naming convention
- Static-index class names follow a single naming convention:
Each_
in the class name is translated to/
in the index name on the server. - In the above example, the index class name is
Orders_ByTotal
.
The name of the index that will be generated on the server will be:Orders/ByTotal
.
Customizing configuration
- You can set various indexing configuration values within the index definition.
- Setting a configuration value within the index will override the matching indexing configuration values set at the server or database level.
public class Orders_ByTotal : AbstractIndexCreationTask<Order> { public Orders_ByTotal() { // ... // Set an indexing configuration value for this index: Configuration["Indexing.MapTimeoutInSec"] = "30"; } }
Deploy a static-index
- To begin indexing data, the index must be deployed to the server.
- This section provides options for deploying indexes that inherit from
AbstractIndexCreationTask
. - To create and deploy an index using the
IndexDefinition
class viaPutIndexesOperation
,
see Creating a static-index - using an Operation.
Deploy single index
- Use
Execute()
orExecuteIndex()
to deploy a single index. - The following examples deploy index
Ordes/ByTotal
to the default database defined in your DocumentStore object. See the syntax section below for all available overloads.
// Call 'Execute' directly on the index instance
new Orders_ByTotal().Execute(store);
// Call 'ExecuteAsync' directly on the index instance
await new Orders_ByTotal().ExecuteAsync(store);
// Call 'ExecuteIndex' on your store object
store.ExecuteIndex(new Orders_ByTotal());
// Call 'ExecuteIndexAsync' on your store object
await store.ExecuteIndexAsync(new Orders_ByTotal());
Deploy multiple indexes
- Use
ExecuteIndexes()
orIndexCreation.CreateIndexes()
to deploy multiple indexes. - The
IndexCreation.CreateIndexes
method attempts to create all indexes in a single request.
If it fails, it will repeat the execution by calling theExecute
method for each index, one by one,
in separate requests. - The following examples deploy indexes
Ordes/ByTotal
andEmployees/ByLastName
to the default database defined in your DocumentStore object.
See the syntax section below for all available overloads.
var indexesToDeploy = new List<AbstractIndexCreationTask>
{
new Orders_ByTotal(),
new Employees_ByLastName()
};
// Call 'ExecuteIndexes' on your store object
store.ExecuteIndexes(indexesToDeploy);
var indexesToDeploy = new List<AbstractIndexCreationTask>
{
new Orders_ByTotal(),
new Employees_ByLastName()
};
// Call 'ExecuteIndexesAsync' on your store object
await store.ExecuteIndexesAsync(indexesToDeploy);
var indexesToDeploy = new List<AbstractIndexCreationTask>
{
new Orders_ByTotal(),
new Employees_ByLastName()
};
// Call the static method 'CreateIndexes' on the IndexCreation class
IndexCreation.CreateIndexes(indexesToDeploy, store);
var indexesToDeploy = new List<AbstractIndexCreationTask>
{
new Orders_ByTotal(),
new Employees_ByLastName()
};
// Call the static method 'CreateIndexesAsync' on the IndexCreation class
await IndexCreation.CreateIndexesAsync(indexesToDeploy, store);
Deploy ALL indexes from an assembly
- The following overload allows you to deploy ALL indexes from a specified assembly:
// Deploy ALL indexes from the assembly containing the `Orders_ByTotal` class
IndexCreation.CreateIndexes(typeof(Orders_ByTotal).Assembly, store);
// Deploy ALL indexes from the assembly containing the `Orders_ByTotal` class
await IndexCreation.CreateIndexesAsync(typeof(Orders_ByTotal).Assembly, store);
Deploy syntax
// Call this method directly on the index instance
void Execute(IDocumentStore store, DocumentConventions conventions = null,
string database = null);
// Call these methods on the store object
void ExecuteIndex(IAbstractIndexCreationTask index, string database = null);
void ExecuteIndexes(IEnumerable<IAbstractIndexCreationTask> indexes,
string database = null);
// Call these static methods on the IndexCreation class
void CreateIndexes(IEnumerable<IAbstractIndexCreationTask> indexes, IDocumentStore store,
DocumentConventions conventions = null, string database = null);
void CreateIndexes(Assembly assemblyToScan, IDocumentStore store,
DocumentConventions conventions = null, string database = null);
// Call this method directly on the index instance
Task ExecuteAsync(IDocumentStore store, DocumentConventions conventions = null,
string database = null, CancellationToken token = default);
// Call these methods on the store object
Task ExecuteIndexAsync(IAbstractIndexCreationTask index, string database = null,
CancellationToken token = default(CancellationToken));
Task ExecuteIndexesAsync(IEnumerable<IAbstractIndexCreationTask> indexes,
string database = null, CancellationToken token = default(CancellationToken));
// Call these static methods on the IndexCreation class
Task CreateIndexesAsync(IEnumerable<IAbstractIndexCreationTask> indexes,
IDocumentStore store, DocumentConventions conventions = null, string database = null,
CancellationToken token = default(CancellationToken));
Task CreateIndexesAsync(Assembly assemblyToScan, IDocumentStore store,
DocumentConventions conventions = null, string database = null,
CancellationToken token = default(CancellationToken));
Parameter | Type | Description |
---|---|---|
store | IDocumentStore |
Your document store object. |
conventions | DocumentConventions |
The Conventions used by the document store. |
database | string |
The target database to deploy the index to. If not specified, the default database set on the store will be used. |
index | IAbstractIndexCreationTask |
The index object to deploy. |
indexes | IEnumerable<IAbstractIndexCreationTask> |
A list of index objects to deploy. |
assemblyToScan | Assembly |
Deploy all indexes that are contained in this assembly. |
Deployment behavior
Deployment mode:
- When your database spans multiple nodes,
you can choose between Rolling index deployment or Parallel index deployment. - Rolling deployment applies the index to one node at a time,
while Parallel deployment deploys the index on all nodes simultaneously. - Learn more in Rolling index deployment.
When the index you are deploying already exists on the server:
-
If the index definition is updated:
- RavenDB uses a side-by-side strategy for all index updates.
- When an existing index definition is modified, RavenDB creates a new index with the updated definition. The new index will replace the existing index once it becomes non-stale.
- If you want to swap the indexes immediately, you can do so through the Studio.
For more details, see Side by side indexing.
-
If the index definition is unchanged:
- If the definition of the index being deployed is identical to the one on the server,
the existing index will not be overwritten. - The indexed data will remain intact, and the indexing process will not restart.
- If the definition of the index being deployed is identical to the one on the server,
Create a static-index - Example
// Define a static-index:
// ======================
public class Orders_ByTotal : AbstractIndexCreationTask<Order>
{
public class IndexEntry
{
// The index-fields:
public string Employee { get; set; }
public string Company { get; set; }
public decimal Total { get; set; }
}
public Orders_ByTotal()
{
Map = orders => from order in orders
select new IndexEntry
{
// Set the index-fields:
Employee = order.Employee,
Company = order.Company,
Total = order.Lines.Sum(l =>
(l.Quantity * l.PricePerUnit) * (1 - l.Discount))
};
// Customize the index as needed, for example:
DeploymentMode = IndexDeploymentMode.Rolling;
Configuration["Indexing.MapTimeoutInSec"] = "30";
Indexes.Add(x => x.Company, FieldIndexing.Search);
// ...
}
}
public static void Main(string[] args)
{
using (DocumentStore store = new DocumentStore
{
Urls = new[] { "http://localhost:8080" },
Database = "Northwind"
})
{
store.Initialize();
// Deploy the index:
// =================
new Orders_ByTotal().Execute(store);
using (IDocumentSession session = store.OpenSession())
{
// Query the index:
// ================
IList<Order> orders = session
.Query<Orders_ByTotal.IndexEntry, Orders_ByTotal>()
// Query for Order documents that have Total > 100
.Where(x => x.Total > 100)
.OfType<Order>()
.ToList();
}
}
}
Create a static-index - using an Operation
-
An index can also be defined and deployed using the PutIndexesOperation maintenance operation.
-
When using this operation:
-
Unlike the naming convention used with indexes inheriting from
AbstractIndexCreationTask
,
you can choose any string-based name for the index.
However, when querying, you must use that string-based name rather than the index class type. -
You can also modify various low-level settings available in the IndexDefinition and IndexDefinitionBuilder classes.
-
-
Consider using this operation only if inheriting from
AbstractIndexCreationTask
is not an option. -
For a detailed explanation and examples, refer to the dedicated article: Put Indexes Operation.
Creating auto-indexes
Auto-indexes creation
- Indexes created by the server are called
dynamic
orauto
indexes. -
Auto-indexes are created when all of the following conditions are met:
- A query is issued without specifying an index (a dynamic query).
- The query includes a filtering condition.
- No suitable auto-index exists that can satisfy the query.
- Creation of auto-indexes has not been disabled.
- For such queries, RavenDB's Query Optimizer searches for an existing auto-index that can satisfy the query. If no suitable auto-index is found, RavenDB will either create a new auto-index or optimize an existing auto-index. (Static-indexes are not taken into account when determining which auto-index should handle the query).
- Note: dynamic queries can be issued either when querying or when patching.
- Over time, RavenDB automatically adjusts and merges auto-indexes to efficiently serve your queries.
For more details, see Query a collection - with filtering (dynamic query).
Naming convention
- Auto-indexes are easily identified by their names, which start with the
Auto/
prefix. - Their name also includes the name of the queried collection and a list of fields used in the query predicate to filter matching results.
-
For example, issuing the following query:
List<Employee> employees = session .Query<Employee>() .Where(x => x.FirstName == "Robert" && x.LastName == "King") .ToList();
from Employees where FirstName = "Robert" and LastName = "King"
Auto/Employees/ByFirstNameAndLastName
.
Auto-index idle state
- To reduce server load, an auto-index is marked as
idle
when it hasn't been used for a while.
Specifically, if the time difference between the last time the auto-index was queried and the last time a query was made on the database (using any index) exceeds the configured threshold (30 minutes by default), the auto-index will be marked asidle
. - This is done in order to avoid marking indexes as idle for databases that were offline for a long period of time, as well as for databases that were just restored from a snapshot or a backup.
- To set the time before marking an index as idle, use the
Indexing.TimeToWaitBeforeDeletingAutoIndexMarkedAsIdleInHrs configuration key.
Setting this value too high is not recommended, as it may lead to performance degradation by causing unnecessary and redundant work for the indexes. - An
idle
auto-index will resume its work and return tonormal
state upon its next query,
or when resetting the index. - If not resumed, the idle auto-index will be deleted by the server after the time period defined in the
Indexing.TimeToWaitBeforeDeletingAutoIndexMarkedAsIdleInHrs configuration key
(72 hours by default).
Disabling auto-indexes
Why disable:
- Disabling auto-index creation prevents the accidental deployment of resource-consuming auto-indexes that may result from one-time, ad-hoc queries issued from the Studio.
- In production environments, disabling this feature helps avoid the creation and background execution of expensive indexes.
How to disable:
-
You can disable auto-indexes by setting the Indexing.DisableQueryOptimizerGeneratedIndexes configuration key. This will affect all queries made both from the Client API and the Studio.
-
Alternatively, you can disable auto-indexes from the Studio.
However, this will affect queries made only from the Studio.- To disable auto-index creation for a specific query made from the query view, see these Query settings.
- To disable auto-index creation for a specific query made from the patch view, see these Patch settings.
- Disabling auto-index creation for ALL queries made on a database can be configured in the Studio configuration view.