# manticoresearch-client **Repository Path**: ymjake/manticoresearch-client ## Basic Information - **Project Name**: manticoresearch-client - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-11-26 - **Last Updated**: 2025-11-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ManticoreSearch .NET Client Handcrafted C# SDK mirroring the official PHP client. Every endpoint, table helper, query builder, result wrapper, and admin API is handwritten—no OpenAPI artifacts remain. ## Features - Table CRUD, bulk, DDL, PQ search/management, cluster/nodes utilities. - Strongly typed `SearchRequestDescriptor` + lightweight `QueryDsl` clauses (match/bool/range/geo/knn/script fields/join) mirroring Elastic’s fluent API. - `ResultSet` exposes hits, took, timed_out, facets, profile metadata. - Connection pool with pluggable node pools (`StaticManticoreNodePool`, `SingleManticoreNodePool`, etc.), custom `ILogger`, `IHttpTransportFactory`; failing all nodes raises `NoMoreNodesException` with retry details. - Fluent options/helpers (node pools, `.Authentication()`, debug hooks, serializer overrides, proxy knobs) that mirror PHP config plus a public `ExecuteAsync` escape hatch for brand-new endpoints. - Attribute + fluent schema mapping via `TableSchemaBuilder` and `[ManticoreField]` so tables can be created straight from your POCOs and tweaked in code. - Prefix/Wildcard DSLs expose analyzer/boost/case-sensitivity/max-expansion knobs in addition to the basic match. - Low-level escape hatch: `client.LowLevel.SqlAsync` / `client.LowLevel.CliAsync` mirror PHP’s `Client::sql()` / `::cli()` for direct statement execution. - Separate request/response and source serializers with `System.Text.Json` context factories, so you can plug in generated `JsonSerializerContext` types the same way Elastic’s client does. ## Quick Start ```csharp var pool = new SingleManticoreNodePool(new Uri("http://127.0.0.1:9308")); var client = new ManticoreClient(new ManticoreClientSettings(pool)); var table = client.Table("movies"); var schema = TableSchemaBuilder.FromType(descriptor => descriptor .Column(m => m.Title, "text", opts => opts.Indexed().Stored()) .Column("created_at", "timestamp")); await table.CreateAsync(schema, silent: true); await table.AddDocumentAsync(new { title = "Interstellar", rating = 8.5 }, id: 1); var typed = await table.SearchAsync(s => s .Match(m => m.Title, "Interstellar") .Term(x => x.Genre, "sci-fi") .Range(x => x.Rating, gte: 8) .Limit(5)); foreach (var hit in new ResultSet(typed)) { Console.WriteLine($"{hit.Id}: {hit.Source?.Title}"); } // Run a vector search that reuses bool filters var knn = await table.SearchAsync(s => s .Match(m => m.Description, "space exploration") .WithKnnVector("embedding", new[] { 0.25f, 0.73f, -0.11f }, k: 10)); ``` ## Advanced search helpers ```csharp await table.SearchAsync(s => s .Match(m => m.Genre, "thriller") .Join( type: "inner", table: "directors", leftField: m => m.DirectorId, rightField: "id", leftFieldType: "int", joinQuery: new QueryStringQueryClause("country:US")) .ScriptField("score", "doc['rating'] * params.boost") .WithKnnDocument("embedding", documentId: 42, k: 5)); // Prefix/Wildcard sugar now exposes analyzer/boost/case sensitivity await table.SearchAsync(s => s .Prefix(m => m.Title, "star", analyzer: "keyword", boost: 1.5) .Wildcard("description", "space*", caseSensitive: false, maxExpansions: 50)); ``` ## Flexible update-by-query `TableClient.UpdateDocumentsAsync` now takes any query shape: ```csharp await table.UpdateDocumentsAsync( new { rating = 9.0 }, new BoolQueryClause( must: new object[] { new MatchQueryClause("title", "classic"), new RangeQueryClause("year", lessThanOrEqual: 1980) })); ``` No need to squeeze everything through `QueryFilter` anymore—POCO, `JsonObject`, or any `QueryDsl` clause all work. ## Direct SQL / CLI access Need to run a raw `DESCRIBE` or DDL statement like the PHP client does? Use the exposed low-level transport: ```csharp var describe = await client.LowLevel.CliAsync("DESCRIBE `movies`"); Console.WriteLine(describe.Payload?["cli_output"]); ``` `LowLevel.SqlAsync` mirrors `/sql` (read-only) whereas `LowLevel.CliAsync` allows full DDL/DML via the Buddy CLI endpoint. ## Calling custom endpoints If the server ships a fresh API before the SDK catches up, craft the endpoint manually and run it through `ManticoreClient.ExecuteAsync`: ```csharp var endpoint = new CustomEndpoint("/experimental/foo", HttpMethod.Post) .WithBody(new { key = "value" }); var response = await client.ExecuteAsync(endpoint); ``` ## Transport tweaks & fluent settings ```csharp 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 DefaultManticoreSourceSerializer(MySourceContext.Default)) .Authentication(new BasicAuthentication("elastic", "changeme")) .Proxy("http://proxy.internal:8080") .DisableDirectStreaming(); var client = new ManticoreClient(settings); ``` Need a literal single-node setup? Pass a single URI: ```csharp var pool = new SingleManticoreNodePool(new Uri("https://search.internal:9443/api")); var settings = new ManticoreClientSettings( pool, sourceSerializerFactory: _ => new DefaultManticoreSourceSerializer(MySourceContext.Default)) .DisableDirectStreaming() .Authentication(new BasicAuthentication("elastic", "Oov35Wtxj5DzpZNzYAzFb0KZ")); var client = new ManticoreClient(settings); ``` `MySourceContext` is whatever `JsonSerializerContext` you generated via `System.Text.Json` source generators—pass delegates so we can instantiate them lazily, Elastic-style. All of these hooks mirror the PHP client’s connection array but offer fluent, immutable `.NET` ergonomics.