YMJake.ManticoreSearch.Client
1.2.2
dotnet add package YMJake.ManticoreSearch.Client --version 1.2.2
NuGet\Install-Package YMJake.ManticoreSearch.Client -Version 1.2.2
<PackageReference Include="YMJake.ManticoreSearch.Client" Version="1.2.2" />
<PackageVersion Include="YMJake.ManticoreSearch.Client" Version="1.2.2" />
<PackageReference Include="YMJake.ManticoreSearch.Client" />
paket add YMJake.ManticoreSearch.Client --version 1.2.2
#r "nuget: YMJake.ManticoreSearch.Client, 1.2.2"
#:package YMJake.ManticoreSearch.Client@1.2.2
#addin nuget:?package=YMJake.ManticoreSearch.Client&version=1.2.2
#tool nuget:?package=YMJake.ManticoreSearch.Client&version=1.2.2
ManticoreSearch .NET Client
Handcrafted C# SDK mirroring the official PHP client. Every endpoint, table helper, query builder, result wrapper, and admin API is handwritten.
Features
- Table CRUD, bulk, DDL, PQ search/management, cluster/nodes utilities.
- Fluent typed DSL (
SearchRequestDescriptor<T>) + low-level SQL/CLI escape hatch. - Result wrappers (
ResultSet) with hits + metadata (took,timed_out, facets, profile). - Pluggable node pools and transport hooks (
ILogger,IHttpTransportFactory). - Serializer customization with
System.Text.Jsoncontext support. - Schema mapping via
TableSchemaBuilder+[ManticoreField]+[JsonPropertyName]. - KNN naming aligned to Manticore (
query_vector,doc_id,query).
Model Definition
Use [ManticoreField] for table schema (type, indexed, stored) and [JsonPropertyName] for field name mapping:
public sealed class MovieDocument
{
[JsonPropertyName("id")]
[ManticoreField("bigint")]
public ulong Id { get; set; }
[JsonPropertyName("title")]
[ManticoreField("text", Indexed = true, Stored = true)]
public string Title { get; set; } = string.Empty;
[JsonPropertyName("genre")]
[ManticoreField("text", Indexed = true, Stored = true)]
public string Genre { get; set; } = string.Empty;
[JsonPropertyName("director_id")]
[ManticoreField("bigint")]
public ulong DirectorId { get; set; }
[JsonPropertyName("rating")]
[ManticoreField("float")]
public float Rating { get; set; }
}
Quick Start
var pool = new SingleManticoreNodePool(new Uri("http://127.0.0.1:9308"));
var client = new ManticoreClient(new ManticoreClientSettings(pool));
var table = client.Table("movies");
// Schema is driven by [ManticoreField] annotations
var schema = TableSchemaBuilder.FromType<MovieDocument>();
await table.CreateAsync(schema, silent: true);
await table.AddDocumentsAsync([
new MovieDocument { Id = 1, Title = "Interstellar", Genre = "sci-fi", DirectorId = 1, Rating = 8.6f },
new MovieDocument { Id = 2, Title = "Inception", Genre = "thriller", DirectorId = 1, Rating = 8.8f },
]);
var result = await table.SearchAsync<MovieDocument>(s => s
.Match(m => m.Title, "Interstellar")
.Range(m => m.Rating, gte: 8)
.Limit(5));
foreach (var hit in result.Documents)
{
Console.WriteLine($"{hit.Source!.Title} rating={hit.Source.Rating}");
}
Advanced Query Examples
// Join query with fluent descriptor
await moviesTable.SearchAsync<MovieDocument>(s => s
.Match(m => m.Genre, "sci-fi")
.Join<DirectorDocument>(j => j
.Inner()
.Table("directors")
.On(m => m.DirectorId, d => d.Id)
.Query(q => q.Match(d => d.Country, "US")))
.Sort(sort => sort.Field(m => m.Rating, "desc"))
.Limit(10));
// KNN + ScriptFields
await table.SearchAsync<MovieDocument>(s => s
.Match(m => m.Genre, "thriller")
.ScriptFields(sf => sf.Add("score", "doc['rating'] * params.boost"))
.Knn(k => k
.Field("embedding")
.K(5)
.DocumentId(42)));
Multilingual SQL Sample
var table = client.Table("documents_idx_sample");
await table.DropAsync(silent: true);
var schema = TableSchemaBuilder.FromType<SampleDocument>(d => d
.Column(x => x.Title, "text", opts => opts.Indexed().Stored())
.Column(x => x.Content, "text", opts => opts.Indexed().Stored())
.Column(x => x.Tags, "text", opts => opts.Indexed().Stored()));
await client.Tables().CreateAsync(
"documents_idx_sample",
schema,
new Dictionary<string, object>
{
["min_word_len"] = "1",
["min_infix_len"] = "1",
["expand_keywords"] = "1",
["morphology"] = "none",
["index_exact_words"] = "1",
["ngram_len"] = "2",
["ngram_chars"] = "cjk"
},
silent: true);
// OR tokenization for better recall
var matchExpression = string.Join(" | ", tokens.Select(t => $"\"{t}\""));
var sql = $"SELECT id, title, WEIGHT() AS weight FROM `documents_idx_sample` WHERE MATCH('{matchExpression}') ORDER BY weight DESC LIMIT 10";
var response = await client.SqlAsync(sql, rawResponse: false);
Transport & Authentication
var uris = new[]
{
new Uri("https://node1.example.com:9308"),
new Uri("https://node2.example.com:9308"),
new Uri("https://node3.example.com:9308")
};
var pool = new StaticManticoreNodePool(uris);
var settings = new ManticoreClientSettings(
pool,
sourceSerializerFactory: _ => new DefaultManticoreSerializer(MySourceContext.Default))
.Authentication(new BasicAuthentication("elastic", "changeme"))
.Proxy("http://proxy.internal:8080");
var client = new ManticoreClient(settings);
MySourceContext is your JsonSerializerContext for Source Generation support:
[JsonSerializable(typeof(MovieDocument))]
[JsonSerializable(typeof(DirectorDocument))]
[JsonSourceGenerationOptions(DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
public partial class MySourceContext : JsonSerializerContext { }
Note: Manticore server itself does not enforce built-in HTTP Basic auth by default. Use
.Authentication(...)when your deployment has an auth gateway/reverse proxy (Nginx/API gateway) that validatesAuthorizationheaders before forwarding to Manticore.
Error Handling
The low-level transport maps failures into explicit exception types:
ManticoreConnectionException: network/connectivity failures.ManticoreTimeoutException: request timeout.ManticoreServerException: non-success HTTP status (includesStatusCodeandResponseBody).ManticoreSerializationException: response deserialization failure.
Release Notes
[1.3.0] - 2026-03-12
Changed:
[ManticoreField]no longer carriesName— field name mapping is now handled exclusively by[JsonPropertyName], aligning with Elastic .NET client conventions.ExpressionFieldResolvernow reads[JsonPropertyName]for field name resolution in queries, sort, and highlight.TableSchemaBuildernow reads[JsonPropertyName]for column name resolution.- Join API refactored from
new JoinClause(...)to fluentJoinDescriptor<TDocument>lambda style. QueryDescriptorMatchandMatchPhrasenow have string field name overloads for use in Join queries and dynamic field scenarios.SortDescriptorFieldnow has an Expression overload for type-safe sort field resolution.
Fixed:
- Join query
query_stringreplaced withmatchin examples —query_stringmay silently drop short tokens like"US"as stopwords.
[1.2.0] - 2026-02-26
Changed:
- Refactored SQL internals into focused components:
SqlText,SqlBuilder, andDocumentPayload. - Unified SQL statement composition style across
TableClient,ClusterClient,TablesAdminClient, andNodesClient. - Aligned KNN payload naming with current Manticore conventions:
query_vector,doc_id, andquery.
Added:
- xUnit-based regression tests for KNN serialization, search response shaping, SQL builder formatting, and document payload normalization.
InternalsVisibleTosetup for internal-component unit testing.
[1.1.0] - 2026-02-26
Added:
- Initial public package release for .NET 8 / .NET 10 targets.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
-
net8.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
SQL internals refactor (SqlText/SqlBuilder/DocumentPayload), unified SQL composition in core clients, KNN naming aligned to query_vector/doc_id/query, README + multilingual sample alignment, and expanded xUnit regression coverage.