This user guide specifies how to include and use the .NET client in your application.
Include OpenSearch.Client in your .csproj file.
<Project>
...
<ItemGroup>
<PackageReference Include="OpenSearch.Client" Version="1.*" />
</ItemGroup>
</Project>
You can connect to your OpenSearch cluster via a single node, or by specifying multiple nodes using a node pool. Using a node pool has a few advantages over a single node, such as load balancing and cluster failover support.
Connecting to a single node
var node = new Uri("http://myserver:9200");
var config = new ConnectionSettings(node);
var client = new OpenSearchClient(config);
Connecting to multiple nodes using a connection pool
var nodes = new Uri[]
{
new Uri("http://myserver1:9200"),
new Uri("http://myserver2:9200"),
new Uri("http://myserver3:9200")
};
var pool = new StaticConnectionPool(nodes);
var settings = new ConnectionSettings(pool);
var client = new OpenSearchClient(settings);
Indexing a document is as simple as:
var tweet = new Tweet
{
Id = 1,
User = "kimchy",
PostDate = new DateTime(2009, 11, 15),
Message = "Trying out OSC, so far so good?"
};
var indexingResponse = client.Index(tweet, idx => idx.Index("mytweetindex")); //or specify index via settings.DefaultIndex("mytweetindex");
All the calls have async variants:
var indexingResponseTask = client.IndexAsync(tweet, idx => idx.Index("mytweetindex")); // returns a Task<IndexResponse>
// Or, in an async-context
var indexingResponse = await client.IndexAsync(tweet, idx => idx.Index("mytweetindex")); // awaits a Task<IndexResponse>
var getResponse = client.Get<Tweet>(indexingResponse.Id, idx => idx.Index("mytweetindex")); // returns an IGetResponse mapped 1-to-1 with the OpenSearch JSON response
var tweet = getResponse.Source; // the original document
OpenSearch.Client exposes a fluent interface and a powerful query DSL
var searchResponse = client.Search<Tweet>(s => s
.Index("mytweetindex") //or specify index via settings.DefaultIndex("mytweetindex");
.From(0)
.Size(10)
.Query(q => q
.Term(t => t.User, "kimchy") || q
.Match(mq => mq.Field(f => f.User).Query("osc"))
)
);
As well as an object initializer syntax:
var request = new SearchRequest
{
From = 0,
Size = 10,
Query = new TermQuery { Field = "user", Value = "kimchy" } ||
new MatchQuery { Field = "description", Query = "OSC" }
};
var searchResponse = client.Search<Tweet>(request);
From the documentation on Term-level queries:
Term-level queries search an index for documents that contain an exact search term...
When working with text data, use term-level queries for fields mapped as keyword only.
Term-level queries are not suited for searching analyzed text fields. To return analyzed fields, use a full-text query.
The above search example includes a TermQuery
matching documents with user:kimchy
.
Term-level queries with empty or null values however are stripped from search requests by default.
To search for documents which contain a non-null but empty field value (i.e. an empty string) include an IsVerbatim
property or a .Verbatim()
clause like this:
var request = new SearchRequest
{
From = 0,
Size = 10,
Query = new TermQuery { Field = "user", Value = "", IsVerbatim = true },
};
var searchResponse = client.Search<Tweet>(request);
In Fluent syntax this might look like:
var result = await OpenSearchClient.SearchAsync<Tweet>(s => s
.Index(index)
.From(0)
.Size(10)
.Query(q => q
.Bool(b => b
.Must(m => m.Term(t => t.Verbatim().Field(f => f.User).Value(string.Empty)))
)
)
);
OpenSearch.Client also includes and exposes the low-level OpenSearch.Net client that you can fall back to in case anything is missing:
IOpenSearchLowLevelClient lowLevelClient = client.LowLevel;
// Generic parameter of Search<> is the type of .Body on response
var response = lowLevelClient.Search<SearchResponse<Tweet>>("mytweetindex", PostData.Serializable(new
{
from = 0,
size = 10,
fields = new [] {"id", "name"},
query = new {
term = new {
name = new {
value= "OSC"
}
}
}
}));
An implementation of AWS SigV4 request signing for performing IAM authentication against the managed Amazon OpenSearch Service. It can be used with both the low-level OpenSearch.Net client as well as the higher-level OpenSearch.Client client.
Include OpenSearch.Net.Auth.AwsSigV4 along with your preferred client in your .csproj file.
<Project>
...
<ItemGroup>
<PackageReference Include="OpenSearch.Client" Version="1.*" />
<PackageReference Include="OpenSearch.Net.Auth.AwsSigV4" Version="1.*" />
</ItemGroup>
</Project>
The only wiring required is to use the AwsSigV4HttpConnection
implementation of IConnection
.
With OpenSearch.Client
var endpoint = new Uri("https://example-aaabbbcccddd111222333.us-east-1.es.amazonaws.com");
var connection = new AwsSigV4HttpConnection();
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
With OpenSearch.Net
var endpoint = new Uri("https://example-aaabbbcccddd111222333.us-east-1.es.amazonaws.com");
var connection = new AwsSigV4HttpConnection();
var config = new ConnectionConfiguration(endpoint, connection);
var client = new OpenSearchLowLevelClient(config);
By default, AwsSigV4HttpConnection
will use the same default logic as the AWS SDK for .NET to determine the credentials and region to use.
However, you may explicitly specify one or both to override this logic, for example:
Explicitly setting the region, but the credentials coming from the environment
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."
var endpoint = new Uri("https://example-aaabbbcccddd111222333.ap-southeast-2.es.amazonaws.com");
var connection = new AwsSigV4HttpConnection(RegionEndpoint.APSoutheast2);
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
Explicitly setting credentials, such as to assume a role, but the region coming from the environment
export AWS_REGION="ap-southeast-2"
var endpoint = new Uri("https://example-aaabbbcccddd111222333.ap-southeast-2.es.amazonaws.com");
var credentials = new AssumeRoleAWSCredentials(
FallbackCredentialsFactory.GetCredentials(),
"arn:aws:iam::123456789012:role/my-open-search-ingest-role",
"my-ingest-application");
var connection = new AwsSigV4HttpConnection(credentials);
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
Explicitly setting credentials and region, such as to assume a role
var endpoint = new Uri("https://example-aaabbbcccddd111222333.ap-southeast-2.es.amazonaws.com");
var credentials = new AssumeRoleAWSCredentials(
FallbackCredentialsFactory.GetCredentials(),
"arn:aws:iam::123456789012:role/my-open-search-ingest-role",
"my-ingest-application");
var connection = new AwsSigV4HttpConnection(credentials, RegionEndpoint.APSoutheast2);
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
Use the "aoss"
service code to make requests to Amazon OpenSearch Serverless, otherwise all configuration options are identical to above.
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..."
var endpoint = new Uri("https://aaabbbcccddd111222333.ap-southeast-2.aoss.amazonaws.com");
var connection = new AwsSigV4HttpConnection(RegionEndpoint.APSoutheast2, service: AwsSigV4HttpConnection.OpenSearchServerlessService);
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
A low-level, dependency free client that is a simple .NET wrapper for the REST API. It allows you to build and represent your own requests and responses according to you needs.
Include OpenSearch.Net in your .csproj file.
<Project>
...
<ItemGroup>
<PackageReference Include="OpenSearch.Net" Version="1.0.0" />
</ItemGroup>
</Project>
Connecting using the low-level client is very similar to how you would connect using OpenSearch.Client. In fact, the connection constructs that OpenSearch.Client use are actually OpenSearch.Net constructs. Thus, single node connections and connection pooling still apply when using OpenSearch.Net.
var node = new Uri("http://myserver:9200");
var config = new ConnectionConfiguration(node);
var client = new OpenSearchLowLevelClient(config);
Note the main difference here is that we are instantiating an OpenSearchLowLevelClient
rather than OpenSearchClient
, and ConnectionConfiguration
instead of ConnectionSettings
.