#Index API
The Index API provides methods for creating and managing indexes to optimize query performance.
#Creating Indexes
#Path Index
// Single path
container.CreateIndex(new PathIndex("name-idx", "/product/name"));
// Multiple paths
container.CreateIndex(new PathIndex("product-paths",
"/product/name",
"/product/category",
"/product/brand"));
// Attribute path
container.CreateIndex(new PathIndex("id-idx", "/product/@id"));#Value Index
// Numeric index for range queries
container.CreateIndex(new ValueIndex("price-idx",
"/product/price",
ValueType.Decimal));
// Date index
container.CreateIndex(new ValueIndex("date-idx",
"/order/orderDate",
ValueType.Date));
// String index (for sorting and equality)
container.CreateIndex(new ValueIndex("name-val-idx",
"/product/name",
ValueType.String));#Full-Text Index
// Basic full-text
container.CreateIndex(new FullTextIndex("description-idx",
"/product/description"));
// With options
container.CreateIndex(new FullTextIndex("content-idx",
"/article/content",
new FullTextOptions
{
Language = "en",
Stemming = true,
StopWords = true,
CaseSensitive = false,
MinTokenLength = 2
}));#Structural Index
// Enable structural navigation optimization
container.CreateIndex(new StructuralIndex("struct-idx"));#Metadata Index
// Index document metadata fields
container.CreateIndex(new MetadataIndex("meta-idx",
"author", "created", "category"));#Index Definition Classes
#PathIndex
var index = new PathIndex
{
Name = "product-paths",
Paths = ["/product/name", "/product/category"],
IncludeNamespaces = false // Ignore namespaces in matching
};#ValueIndex
var index = new ValueIndex
{
Name = "price-idx",
Path = "/product/price",
ValueType = ValueType.Decimal,
Collation = null // Use default collation
};#FullTextIndex
var index = new FullTextIndex
{
Name = "content-idx",
Path = "/article/content",
Options = new FullTextOptions
{
Language = "en",
Stemming = true,
StopWords = true,
CustomStopWords = ["the", "a", "an"],
CaseSensitive = false,
MinTokenLength = 2,
MaxTokenLength = 50
}
};#Index Options
#Create If Not Exists
container.CreateIndexIfNotExists(new PathIndex("name-idx", "/product/name"));#Recreate Index
container.CreateIndex(index, recreateIfExists: true);#Deferred Indexing
container.CreateIndex(index, new IndexOptions
{
BuildImmediately = false // Create definition only, build later
});
// Later: build the index
container.RebuildIndex("price-idx");#Managing Indexes
#List Indexes
foreach (var info in container.ListIndexes())
{
Console.WriteLine($"Name: {info.Name}");
Console.WriteLine($"Type: {info.Type}");
Console.WriteLine($"Paths: {string.Join(", ", info.Paths)}");
Console.WriteLine($"Size: {info.SizeBytes} bytes");
Console.WriteLine($"Entries: {info.EntryCount}");
Console.WriteLine();
}#Get Index Info
var info = container.GetIndexInfo("price-idx");
Console.WriteLine($"Name: {info.Name}");
Console.WriteLine($"Type: {info.Type}");
Console.WriteLine($"Created: {info.CreatedAt}");
Console.WriteLine($"Last rebuilt: {info.LastRebuiltAt}");
Console.WriteLine($"Size: {info.SizeBytes}");
Console.WriteLine($"Entry count: {info.EntryCount}");#Drop Index
container.DropIndex("old-idx");
// Safe drop
if (container.IndexExists("old-idx"))
{
container.DropIndex("old-idx");
}#Rebuild Index
// Rebuild specific index
container.RebuildIndex("price-idx");
// Rebuild all indexes
container.RebuildIndexes();
// Rebuild with progress
container.RebuildIndex("price-idx", new RebuildOptions
{
Progress = new Progress<IndexRebuildProgress>(p =>
{
Console.WriteLine($"Progress: {p.DocumentsProcessed}/{p.TotalDocuments}");
})
});#Index Statistics
var stats = container.GetIndexStats("price-idx");
Console.WriteLine($"Entry count: {stats.EntryCount}");
Console.WriteLine($"Unique values: {stats.UniqueValueCount}");
Console.WriteLine($"Size: {stats.SizeBytes} bytes");
Console.WriteLine($"Tree depth: {stats.TreeDepth}");
Console.WriteLine($"Fragmentation: {stats.Fragmentation:P}");
Console.WriteLine($"Avg entry size: {stats.AverageEntrySize} bytes");#Query Optimization
#Explain Index Usage
var plan = db.Explain("""
for $p in collection('products')//product
where $p/price > 100
order by $p/name
return $p
""");
foreach (var index in plan.IndexesUsed)
{
Console.WriteLine($"Using index: {index.Name}");
Console.WriteLine($" Type: {index.Type}");
Console.WriteLine($" Estimated selectivity: {index.Selectivity:P}");
}#Force Index Usage
var results = db.Query("""
(: pragma use-index=price-idx :)
for $p in collection('products')//product
where $p/price > 100
return $p
""");#Disable Index Usage
var results = db.Query("""
(: pragma no-index :)
for $p in collection('products')//product
return $p
""");#Index Selection Guidelines
|
Query Pattern |
Recommended Index |
|---|---|
|
|
Path Index |
|
|
Path Index on |
|
|
Value Index (Decimal) |
|
|
Value Index (Date) |
|
|
Full-Text Index |
|
|
Structural Index |
|
|
Metadata Index |
#Error Handling
try
{
container.CreateIndex(index);
}
catch (IndexExistsException ex)
{
Console.WriteLine($"Index already exists: {ex.IndexName}");
}
catch (InvalidIndexDefinitionException ex)
{
Console.WriteLine($"Invalid index: {ex.Message}");
}
try
{
container.DropIndex("nonexistent");
}
catch (IndexNotFoundException ex)
{
Console.WriteLine($"Index not found: {ex.IndexName}");
}#Best Practices
-
Index selectively - Only index frequently queried paths
-
Match query patterns - Design indexes for your actual queries
-
Use value indexes for ranges - Path indexes only help with existence
-
Monitor index size - Large indexes slow writes
-
Rebuild periodically - After bulk deletes
-
Test with explain - Verify indexes are being used
-
Consider composite indexes - Multiple paths in one index
#Next Steps
|
Concepts |
Execution |
Optimization |
|---|---|---|
|
IndexingIndexing concepts |
Query APIQuery execution |
Performance TuningOptimization tips |