use apithing::ApiOperation;
use shardex::{
api::{
operations::{OpenIndex, ValidateConfig},
parameters::{OpenIndexParams, ValidateConfigParams},
AddPostings, AddPostingsParams, CreateIndex, CreateIndexParams, Flush, FlushParams, GetStats, GetStatsParams,
Search, SearchParams, ShardexContext,
},
DocumentId, Posting, ShardexConfig,
};
use std::error::Error;
use std::time::Instant;
fn main() -> Result<(), Box<dyn Error>> {
println!("Shardex Configuration Example");
println!("=============================");
let base_dir = std::env::temp_dir().join("shardex_config_examples");
if base_dir.exists() {
std::fs::remove_dir_all(&base_dir)?;
}
std::fs::create_dir_all(&base_dir)?;
println!("\n1. Default Configuration");
println!("------------------------");
let default_params = CreateIndexParams::builder()
.directory_path(base_dir.join("default_index"))
.build()
.expect("Default configuration should be valid");
print_config(&default_params);
println!("\n2. High-Performance Configuration");
println!("---------------------------------");
let high_perf_params = CreateIndexParams::high_performance(base_dir.join("high_perf_index"));
print_config(&high_perf_params);
println!("\n3. Memory-Optimized Configuration");
println!("----------------------------------");
let memory_opt_params = CreateIndexParams::memory_optimized(base_dir.join("memory_opt_index"));
print_config(&memory_opt_params);
println!("\n4. Testing High-Performance Configuration");
println!("=========================================");
println!("Creating index with high-performance config...");
let mut context = ShardexContext::new();
CreateIndex::execute(&mut context, &high_perf_params)?;
let test_data = generate_test_data(20, 256); println!(
"Generated {} test documents with {}-dimensional vectors",
test_data.len(),
256
);
let start_time = Instant::now();
let add_params = AddPostingsParams::new(test_data)?;
AddPostings::execute(&mut context, &add_params)?;
let flush_params = FlushParams::new();
Flush::execute(&mut context, &flush_params)?;
let indexing_time = start_time.elapsed();
println!("Indexing completed in {:?}", indexing_time);
std::thread::sleep(std::time::Duration::from_millis(100));
let stats_params = GetStatsParams::new();
let stats = GetStats::execute(&mut context, &stats_params)?;
println!("Final index statistics:");
println!(" - Shards: {}", stats.total_shards);
println!(" - Postings: {}", stats.total_postings);
println!(
" - Memory usage: {:.2} MB",
stats.memory_usage as f64 / 1024.0 / 1024.0
);
println!(" - Disk usage: {:.2} MB", stats.disk_usage as f64 / 1024.0 / 1024.0);
println!(
" - Avg shard utilization: {:.1}%",
stats.average_shard_utilization * 100.0
);
println!("\n5. Search Performance Testing");
println!("============================");
let query_vector = generate_random_vector(256);
let search_start = Instant::now();
let search_params = SearchParams::new(query_vector, 10)?;
let results = Search::execute(&mut context, &search_params)?;
let search_time = search_start.elapsed();
println!("Search for k=10 completed in {:?}", search_time);
println!("Found {} results", results.len());
if !results.is_empty() {
println!("Top result similarity: {:.4}", results[0].similarity_score);
}
println!("\n6. Reopening Existing Index");
println!("===========================");
drop(context);
let mut reopen_context = ShardexContext::new();
let open_params = OpenIndexParams::new(high_perf_params.directory_path.clone());
OpenIndex::execute(&mut reopen_context, &open_params)?;
let stats_params = GetStatsParams::new();
let reopened_stats = GetStats::execute(&mut reopen_context, &stats_params)?;
println!("Reopened index statistics:");
println!(" - Postings: {}", reopened_stats.total_postings);
println!(
" - Configuration preserved: vector_size = {}",
reopened_stats.vector_dimension
);
println!("\n7. Configuration Validation");
println!("===========================");
println!("Testing invalid configuration (vector_size = 0)...");
let invalid_config = ShardexConfig::new()
.directory_path(base_dir.join("invalid_index"))
.vector_size(0);
let mut validation_context = ShardexContext::new();
let validate_params = ValidateConfigParams::new(invalid_config);
match ValidateConfig::execute(&mut validation_context, &validate_params) {
Ok(true) => println!("Unexpected: Invalid config was accepted"),
Ok(false) => println!("Expected: Invalid config was rejected"),
Err(e) => println!("Error during validation: {}", e),
}
std::fs::remove_dir_all(&base_dir)?;
println!("\nConfiguration examples completed!");
Ok(())
}
fn print_config(params: &CreateIndexParams) {
println!(" Directory: {:?}", params.directory_path);
println!(" Vector size: {}", params.vector_size);
println!(" Shard size: {}", params.shard_size);
println!(" WAL segment size: {} bytes", params.wal_segment_size);
println!(" Batch interval: {}ms", params.batch_write_interval_ms);
println!(" Default slop factor: {}", params.default_slop_factor);
println!(" Bloom filter size: {}", params.bloom_filter_size);
}
fn generate_test_data(count: usize, vector_size: usize) -> Vec<Posting> {
(0..count)
.map(|i| {
let document_id = DocumentId::from_raw((i + 1) as u128);
let vector = generate_random_vector(vector_size);
Posting {
document_id,
start: 0,
length: 100, vector,
}
})
.collect()
}
fn generate_random_vector(size: usize) -> Vec<f32> {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut vector = Vec::with_capacity(size);
let mut hasher = DefaultHasher::new();
for i in 0..size {
i.hash(&mut hasher);
let value = (hasher.finish() % 1000) as f32 / 1000.0;
vector.push(value);
}
let magnitude: f32 = vector.iter().map(|x| x * x).sum::<f32>().sqrt();
if magnitude > 0.0 {
for value in &mut vector {
*value /= magnitude;
}
}
vector
}