// ❌ Chậm: Tính score cho tất cả documents
var slow = await _es.SearchAsync<Product>(s => s
.Query(q => q
.Bool(b => b
.Must(
m => m.Term(t => t.Field(f => f.Category).Value("smartphones")),
m => m.Term(t => t.Field(f => f.InStock).Value(true))
)
)
)
);
// ✅ Nhanh: Filter không tính score, được cache
var fast = await _es.SearchAsync<Product>(s => s
.Query(q => q
.Bool(b => b
.Filter(
f => f.Term(t => t.Field(field => field.Category).Value("smartphones")),
f => f.Term(t => t.Field(field => field.InStock).Value(true))
)
)
)
);
// ❌ Lấy toàn bộ document (kể cả description dài)
var allFields = await _es.SearchAsync<Product>(s => s.MatchAll());
// ✅ Chỉ lấy fields cần hiển thị trong list
var listFields = await _es.SearchAsync<Product>(s => s
.Source(src => src
.Includes(i => i.Fields(
f => f.Name,
f => f.Price,
f => f.Category,
f => f.InStock
))
)
.Query(q => q.MatchAll())
);
// Bật request cache cho heavy aggregation queries
var response = await _es.SearchAsync<Product>(s => s
.RequestCache(true) // Cache kết quả ở node level (size=0 queries)
.Size(0)
.Aggregations(a => a
.Terms("categories", t => t.Field(f => f.Category))
)
);
// Preference - cùng user luôn hit cùng shard replica (tận dụng cache)
var response2 = await _es.SearchAsync<Product>(s => s
.Preference($"user-{userId}") // Consistent routing cho cùng user
.Query(q => q.MatchAll())
);
// Tối ưu index cho search-heavy workload
await _es.Indices.CreateAsync<Product>("products", c => c
.Settings(s => s
.NumberOfShards(1) // Bắt đầu với 1, scale sau
.NumberOfReplicas(1) // 1 replica cho HA
.RefreshInterval(new Duration("5s")) // Tăng refresh interval nếu near-real-time không cần
.Analysis(a => a // ... analyzers
)
)
);
// Optimize cho sau khi full reindex (merge segments)
await _es.Indices.ForcemergeAsync("products", f => f
.MaxNumSegments(1) // Gộp tất cả thành 1 segment (read-only index)
);
// Timeout per request
var response = await _es.SearchAsync<Product>(s => s
.Timeout("5s") // Partial results sau 5s thay vì wait mãi
.Query(q => q.MatchAll())
);
// Global timeout trong client settings
var settings = new ElasticsearchClientSettings(new Uri("https://localhost:9200"))
.RequestTimeout(TimeSpan.FromSeconds(30))
.DeadTimeout(TimeSpan.FromMinutes(1)) // Node considered dead sau bao lâu
.MaxDeadTimeout(TimeSpan.FromMinutes(5));
Indexing:
□ Bulk indexing thay vì single document
□ Tắt refresh_interval trong bulk import lớn
□ ForceSegmentMerge sau reindex tĩnh
□ ScaledFloat cho tiền tệ thay vì double
□ Đừng dùng dynamic mapping trong production
Search:
□ Dùng filter thay vì must khi không cần score
□ Chỉ lấy fields cần thiết (source filtering)
□ Search After thay vì deep pagination
□ request_cache=true cho aggregation queries
□ Đặt timeout hợp lý
Cluster:
□ 1 primary shard nếu index < 50GB
□ Ít nhất 1 replica cho production
□ Heap size: 50% RAM, max 31GB
□ Monitor shard count (<1000 per node)
□ Dùng ILM để quản lý time-series data