Elastic.Clients.Esql
0.4.1
Prefix Reserved
dotnet add package Elastic.Clients.Esql --version 0.4.1
NuGet\Install-Package Elastic.Clients.Esql -Version 0.4.1
<PackageReference Include="Elastic.Clients.Esql" Version="0.4.1" />
<PackageVersion Include="Elastic.Clients.Esql" Version="0.4.1" />
<PackageReference Include="Elastic.Clients.Esql" />
paket add Elastic.Clients.Esql --version 0.4.1
#r "nuget: Elastic.Clients.Esql, 0.4.1"
#:package Elastic.Clients.Esql@0.4.1
#addin nuget:?package=Elastic.Clients.Esql&version=0.4.1
#tool nuget:?package=Elastic.Clients.Esql&version=0.4.1
Elastic.Clients.Esql
Execute ES|QL queries against Elasticsearch with LINQ. This package connects the Elastic.Esql translation engine to a real cluster via Elastic.Transport. Pair with Elastic.Mapping for a fully AOT-compatible query pipeline from LINQ expression to typed results.
Why?
Elastic.Esql translates LINQ to ES|QL strings. This package adds the HTTP layer to actually run them -- connection pooling, authentication, error handling, async queries, and result materialization into typed C# objects.
Quick Start
using var client = new EsqlClient(new Uri("https://my-cluster:9200"));
// LINQ query -- translates and executes in one step
var errors = await client.Query<LogEntry>()
.Where(l => l.Level == "ERROR")
.OrderByDescending(l => l.Timestamp)
.Take(10)
.ToListAsync();
Configuration
// Simple -- just a URI
using var client = new EsqlClient(new Uri("https://localhost:9200"));
// With authentication and mapping context
var transport = new DistributedTransport(
new TransportConfiguration(new Uri(url), new ApiKey(apiKey)));
var settings = new EsqlClientSettings(transport)
{
MappingContext = MyContext.Instance, // From Elastic.Mapping source generator
Defaults = new EsqlQueryDefaults
{
TimeZone = "America/New_York",
Locale = "en-US"
}
};
using var client = new EsqlClient(settings);
Query Patterns
LINQ fluent syntax
var topBrands = await client.Query<Product>()
.Where(p => p.InStock)
.GroupBy(p => p.Brand)
.Select(g => new { Brand = g.Key, Avg = g.Average(p => p.Price), Count = g.Count() })
.OrderByDescending(x => x.Avg)
.Take(5)
.ToListAsync();
LINQ query syntax
var results = await (
from log in client.Query<LogEntry>()
where log.Level == "ERROR"
where log.Duration > 500
orderby log.Timestamp descending
select new { log.Message, log.Duration }
).ToListAsync();
Lambda expression
var results = await client.QueryAsync<LogEntry>(q =>
q.Where(l => l.Level == "ERROR").Take(10));
Raw ES|QL
var results = await client.QueryAsync<LogEntry>(
"FROM logs-* | WHERE log.level == \"ERROR\" | LIMIT 10");
Inspect the generated query
Every queryable's .ToString() returns the ES|QL without executing:
var query = client.Query<Product>()
.Where(p => p.Price > 100)
.OrderBy(p => p.Name);
Console.WriteLine(query.ToString());
// FROM products
// | WHERE price > 100
// | SORT name
Async Queries
For long-running queries, use the async query API. Results auto-delete from the cluster on dispose:
await using var asyncQuery = await client.QueryAsyncQuery<LogEntry>(
q => q.Where(l => l.Level == "ERROR"),
new EsqlAsyncQueryOptions
{
WaitForCompletionTimeout = TimeSpan.FromSeconds(5),
KeepAlive = TimeSpan.FromMinutes(10)
});
if (asyncQuery.IsRunning)
Console.WriteLine($"Query {asyncQuery.QueryId} still running...");
var results = await asyncQuery.ToListAsync(); // Polls until complete
// Query automatically deleted from cluster when disposed
Per-Query Options
Override client defaults on individual queries:
var results = await client.Query<LogEntry>()
.Where(l => l.Level == "ERROR")
.WithTimeZone("Europe/London")
.WithProfile()
.WithColumnar()
.ToListAsync();
Testing
Generate ES|QL strings without an Elasticsearch connection:
var client = EsqlClient.InMemory(MyContext.Instance);
var esql = client.Query<Product>()
.Where(p => p.InStock && p.Price < 50)
.OrderBy(p => p.Name)
.ToString();
Assert.Equal("""
FROM products
| WHERE (in_stock == true AND price < 50)
| SORT name
""", esql);
AOT Compatible
The full pipeline is AOT ready when used with Elastic.Mapping:
- Query translation (
Elastic.Esql) -- pure expression tree walking, no reflection-based serialization - Field resolution (
Elastic.Mapping) -- source-generated constants aligned with yourSystem.Text.Jsoncontext - HTTP transport (
Elastic.Transport) -- AOT-compatible HTTP client
Link your JsonSerializerContext to [ElasticsearchMappingContext] and field names, JSON serialization, and ES|QL queries all derive from the same compile-time source of truth.
Architecture
Elastic.Clients.Esql -- This package: EsqlClient, transport, execution
references:
Elastic.Esql -- LINQ-to-ES|QL translation (no HTTP dependency)
Elastic.Mapping -- Type metadata and field resolution (source generator)
Elastic.Transport -- Low-level HTTP client for Elasticsearch
If you only need ES|QL string generation (no execution), depend on Elastic.Esql directly.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Elastic.Esql (>= 0.4.1)
- Elastic.Mapping (>= 0.4.1)
- Elastic.Transport (>= 0.11.1)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.0)
- System.Text.Json (>= 10.0.0)
-
net10.0
- Elastic.Esql (>= 0.4.1)
- Elastic.Mapping (>= 0.4.1)
- Elastic.Transport (>= 0.11.1)
-
net8.0
- Elastic.Esql (>= 0.4.1)
- Elastic.Mapping (>= 0.4.1)
- Elastic.Transport (>= 0.11.1)
- System.Text.Json (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.