- .NET Clients: other versions:
- Introduction
- Installation
- Breaking changes
- API Conventions
- Elasticsearch.Net - Low level client
- NEST - High level client
- Troubleshooting
- Search
- Query DSL
- Full text queries
- Term level queries
- Exists Query Usage
- Fuzzy Date Query Usage
- Fuzzy Numeric Query Usage
- Fuzzy Query Usage
- Ids Query Usage
- Prefix Query Usage
- Date Range Query Usage
- Long Range Query Usage
- Numeric Range Query Usage
- Term Range Query Usage
- Regexp Query Usage
- Term Query Usage
- Terms Set Query Usage
- Terms List Query Usage
- Terms Lookup Query Usage
- Terms Query Usage
- Wildcard Query Usage
- Compound queries
- Joining queries
- Geo queries
- Specialized queries
- Span queries
- NEST specific queries
- Aggregations
- Metric Aggregations
- Average Aggregation Usage
- Boxplot Aggregation Usage
- Cardinality Aggregation Usage
- Extended Stats Aggregation Usage
- Geo Bounds Aggregation Usage
- Geo Centroid Aggregation Usage
- Geo Line Aggregation Usage
- Max Aggregation Usage
- Median Absolute Deviation Aggregation Usage
- Min Aggregation Usage
- Percentile Ranks Aggregation Usage
- Percentiles Aggregation Usage
- Rate Aggregation Usage
- Scripted Metric Aggregation Usage
- Stats Aggregation Usage
- String Stats Aggregation Usage
- Sum Aggregation Usage
- T Test Aggregation Usage
- Top Hits Aggregation Usage
- Top Metrics Aggregation Usage
- Value Count Aggregation Usage
- Weighted Average Aggregation Usage
- Bucket Aggregations
- Adjacency Matrix Usage
- Auto Date Histogram Aggregation Usage
- Children Aggregation Usage
- Composite Aggregation Usage
- Date Histogram Aggregation Usage
- Date Range Aggregation Usage
- Diversified Sampler Aggregation Usage
- Filter Aggregation Usage
- Filters Aggregation Usage
- Geo Distance Aggregation Usage
- Geo Hash Grid Aggregation Usage
- Geo Tile Grid Aggregation Usage
- Global Aggregation Usage
- Histogram Aggregation Usage
- Ip Range Aggregation Usage
- Missing Aggregation Usage
- Multi Terms Aggregation Usage
- Nested Aggregation Usage
- Parent Aggregation Usage
- Range Aggregation Usage
- Rare Terms Aggregation Usage
- Reverse Nested Aggregation Usage
- Sampler Aggregation Usage
- Significant Terms Aggregation Usage
- Significant Text Aggregation Usage
- Terms Aggregation Usage
- Variable Width Histogram Usage
- Pipeline Aggregations
- Average Bucket Aggregation Usage
- Bucket Script Aggregation Usage
- Bucket Selector Aggregation Usage
- Bucket Sort Aggregation Usage
- Cumulative Cardinality Aggregation Usage
- Cumulative Sum Aggregation Usage
- Derivative Aggregation Usage
- Extended Stats Bucket Aggregation Usage
- Max Bucket Aggregation Usage
- Min Bucket Aggregation Usage
- Moving Average Ewma Aggregation Usage
- Moving Average Holt Linear Aggregation Usage
- Moving Average Holt Winters Aggregation Usage
- Moving Average Linear Aggregation Usage
- Moving Average Simple Aggregation Usage
- Moving Function Aggregation Usage
- Moving Percentiles Aggregation Usage
- Normalize Aggregation Usage
- Percentiles Bucket Aggregation Usage
- Serial Differencing Aggregation Usage
- Stats Bucket Aggregation Usage
- Sum Bucket Aggregation Usage
- Matrix Aggregations
- Metric Aggregations
Getting started
editGetting started
editElasticsearch.Net is a low level Elasticsearch .NET client that has no dependencies on other libraries and is unopinionated about how you build your requests and responses.
Connecting
editTo connect to Elasticsearch running locally at http://localhost:9200
is as simple as
instantiating a new instance of the client
var lowlevelClient = new ElasticLowLevelClient();
Often you may need to pass additional configuration options to the client such as the address of Elasticsearch if it’s running on
a remote machine. This is where ConnectionConfiguration
comes in; an instance can be instantiated to provide
the client with different configuration values.
var settings = new ConnectionConfiguration(new Uri("http://example.com:9200")) .RequestTimeout(TimeSpan.FromMinutes(2)); var lowlevelClient = new ElasticLowLevelClient(settings);
In this example, a default request timeout was also specified that will be applied to all requests, to determine after how long the client should cancel a request.
There are many other configuration options on ConnectionConfiguration
to control things such as
- Basic Authentication header to send with all requests
- whether the client should connect through a proxy
- whether HTTP compression support should be enabled on the client
Connection pools
editConnectionConfiguration
is not restricted to being passed a single address for Elasticsearch. There are several different
types of Connection pool available, each with different characteristics that can be used to
configure the client. The following example uses a SniffingConnectionPool seeded with the addresses
of three Elasticsearch nodes in the cluster, and the client will use this type of pool to maintain a list of available nodes within the
cluster to which it can send requests in a round-robin fashion.
var uris = new[] { new Uri("http://localhost:9200"), new Uri("http://localhost:9201"), new Uri("http://localhost:9202"), }; var connectionPool = new SniffingConnectionPool(uris); var settings = new ConnectionConfiguration(connectionPool); var lowlevelClient = new ElasticLowLevelClient(settings);
Indexing
editOnce a client had been configured to connect to Elasticsearch, we need to get some data into the cluster to work with. Imagine we have the following Plain Old CLR Object (POCO)
public class Person { public string FirstName { get; set; } public string LastName { get; set; } }
Indexing a single instance of this POCO, either synchronously or asynchronously, is as simple as
var person = new Person { FirstName = "Martijn", LastName = "Laarman" }; var indexResponse = lowlevelClient.Index<BytesResponse>("people", "1", PostData.Serializable(person)); byte[] responseBytes = indexResponse.Body; var asyncIndexResponse = await lowlevelClient.IndexAsync<StringResponse>("people", "1", PostData.Serializable(person)); string responseString = asyncIndexResponse.Body;
synchronous method that returns an |
|
asynchronous method that returns a |
All available methods within Elasticsearch.Net are exposed as both synchronous and asynchronous versions, with the latter using the idiomatic *Async suffix for the method name.
Both index requests will index the document to the endpoint /people/person/1
.
An anonymous type can also be used to represent the document to index
var person = new { FirstName = "Martijn", LastName = "Laarman" }; var ndexResponse = await lowlevelClient.IndexAsync<BytesResponse>("people", "1", PostData.Serializable(person)); byte[] responseStream = ndexResponse.Body;
For API’s that take a body you can send the body as an (anonymous) object, byte[], string, stream. Additionally for API’s that
take multilined json you can also send a list of objects or a list of bytes to help you format this. These are all encapsulated
by PostData
and you can use the static methods on that class to send the body in whatever form you have it.
Check out the documentation on Post Data to see all of these permutations in action.
The generic type parameter on the method specifies the type of the response body. In the last example, we return the response as a string from Elasticsearch, forgoing any deserialization.
Bulk indexing
editIf you need to index many documents, Elasticsearch has a Bulk API that can be used to perform many operations in one request
var people = new object[] { new { index = new { _index = "people", _type = "person", _id = "1" }}, new { FirstName = "Martijn", LastName = "Laarman" }, new { index = new { _index = "people", _type = "person", _id = "2" }}, new { FirstName = "Greg", LastName = "Marzouka" }, new { index = new { _index = "people", _type = "person", _id = "3" }}, new { FirstName = "Russ", LastName = "Cam" }, }; var ndexResponse = lowlevelClient.Bulk<StringResponse>(PostData.MultiJson(people)); string responseStream = ndexResponse.Body;
The client will serialize each item seperately and join items up using the \n
character as required by the Bulk API. Refer to the
Elasticsearch Bulk API documentation for further details and supported operations.
Searching
editNow that we have indexed some documents we can begin to search for them.
The Elasticsearch Query DSL can be expressed using an anonymous type within the request
var searchResponse = lowlevelClient.Search<StringResponse>("people", PostData.Serializable(new { from = 0, size = 10, query = new { match = new { firstName = new { query = "Martijn" } } } })); var successful = searchResponse.Success; var responseJson = searchResponse.Body;
responseJson
now holds a JSON string for the response. The search endpoint for this query is
/people/person/_search
and it’s possible to search over multiple indices and types by changing the arguments
supplied in the request for index
and type
, respectively.
Strings can also be used to express the request
var searchResponse = lowlevelClient.Search<BytesResponse>("people", @" { ""from"": 0, ""size"": 10, ""query"": { ""match"": { ""firstName"": { ""query"": ""Martijn"" } } } }"); var responseBytes = searchResponse.Body;
As you can see, using strings is a little more cumbersome than using anonymous types because of the need to escape
double quotes, but it can be useful at times nonetheless. responseBytes
will contain
the bytes of the response from Elasticsearch.
Elasticsearch.Net does not provide typed objects to represent responses; if you need this, you should consider
using NEST, that does map all requests and responses to types. You can work with
strong types with Elasticsearch.Net but it will be up to you as the developer to configure Elasticsearch.Net so that
it understands how to deserialize your types, most likely by providing your own IElasticsearchSerializer implementation
to ConnectionConfiguration
.
Handling Errors
editBy default, Elasticsearch.Net is configured not to throw exceptions if a HTTP response status code is returned that is not in the 200-300 range, nor an expected response status code allowed for a given request e.g. checking if an index exists can return a 404.
The response from low level client calls provides a number of properties that can be used to determine if a call is successful
var searchResponse = lowlevelClient.Search<BytesResponse>("people", PostData.Serializable(new { match_all = new {} })); var success = searchResponse.Success; var successOrKnownError = searchResponse.SuccessOrKnownError; var exception = searchResponse.OriginalException;
Response is in the 200 range, or an expected response for the given request |
|
Response is successful, or has a response code between 400-599 that indicates the request cannot be retried. |
|
If the response is unsuccessful, will hold the original exception. |
Using these details, it is possible to make decisions around what should be done in your application.
The default behaviour of not throwing exceptions can be changed by setting .ThrowExceptions()
on ConnectionConfiguration
var settings = new ConnectionConfiguration(new Uri("http://example.com:9200")) .ThrowExceptions(); var lowlevelClient = new ElasticLowLevelClient(settings);
And if more fine grained control is required, custom exceptions can be thrown using .OnRequestCompleted()
on
ConnectionConfiguration
var settings = new ConnectionConfiguration(new Uri("http://example.com:9200")) .OnRequestCompleted(apiCallDetails => { if (apiCallDetails.HttpStatusCode == 418) { throw new TimeForACoffeeException(); } }); var lowlevelClient = new ElasticLowLevelClient(settings);