低级别 .NET 客户端 (OpenSearch.Net)
OpenSearch.Net 是一个低级别 .NET 客户端,提供了与 OpenSearch 通信的基础层。它不依赖于其他组件,可以处理轮询负载均衡、传输以及基本的请求/响应循环。OpenSearch.Net 包含所有 OpenSearch API 端点作为方法。使用 OpenSearch.Net 时,您需要自行构建查询。
本入门指南介绍了如何连接到 OpenSearch、索引文档和运行查询。有关客户端源代码,请参阅 opensearch-net 仓库。
稳定版本
本文档反映了 GitHub 仓库中可用的最新更新,可能包含当前稳定版本中尚未提供的更改。NuGet 中当前的稳定版本是 1.2.0。
示例
以下示例说明了如何连接到 OpenSearch、索引文档以及对数据发送查询。它使用 Student 类来表示一个学生,相当于索引中的一个文档。
public class Student
{
public int Id { get; init; }
public string FirstName { get; init; }
public string LastName { get; init; }
public int GradYear { get; init; }
public double Gpa { get; init; }
}
安装 Opensearch.Net 客户端
要安装 Opensearch.Net,请下载 Opensearch.Net NuGet 包,并将其添加到您选择的 IDE 中的项目中。在 Microsoft Visual Studio 中,请按照以下步骤操作
- 在解决方案资源管理器面板中,右键单击您的解决方案或项目,然后选择管理解决方案的 NuGet 包。
- 搜索 OpenSearch.Net NuGet 包,然后选择安装。
或者,您可以将 OpenSearch.Net 添加到您的 .csproj 文件中
<Project>
...
<ItemGroup>
<PackageReference Include="Opensearch.Net" Version="1.0.0" />
</ItemGroup>
</Project>
连接到 OpenSearch
创建 OpenSearchLowLevelClient 对象时使用默认构造函数,以连接到默认的 OpenSearch 主机 (https://:9200
)。
var client = new OpenSearchLowLevelClient();
要通过已知地址的单个节点连接到 OpenSearch 集群,请创建一个包含该地址的 ConnectionConfiguration 对象,并将其传递给 OpenSearch.Net 构造函数
var nodeAddress = new Uri("http://myserver:9200");
var config = new ConnectionConfiguration(nodeAddress);
var client = new OpenSearchLowLevelClient(config);
您还可以使用连接池来管理集群中的节点。此外,您可以设置连接配置,使 OpenSearch 以格式化 JSON 的形式返回响应。
var uri = new Uri("https://:9200");
var connectionPool = new SingleNodeConnectionPool(uri);
var settings = new ConnectionConfiguration(connectionPool).PrettyJson();
var client = new OpenSearchLowLevelClient(settings);
要使用多个节点连接到 OpenSearch 集群,请创建包含这些节点地址的连接池。在此示例中,使用了SniffingConnectionPool
,因为它会跟踪集群中被移除或添加的节点,因此最适合自动伸缩的集群。
var uris = new[]
{
new Uri("https://:9200"),
new Uri("https://:9201"),
new Uri("https://:9202")
};
var connectionPool = new SniffingConnectionPool(uris);
var settings = new ConnectionConfiguration(connectionPool).PrettyJson();
var client = new OpenSearchLowLevelClient(settings);
连接到 Amazon OpenSearch 服务
以下示例演示了连接到 Amazon OpenSearch 服务
using OpenSearch.Client;
using OpenSearch.Net.Auth.AwsSigV4;
namespace Application
{
class Program
{
static void Main(string[] args)
{
var endpoint = new Uri("https://search-xxx.region.es.amazonaws.com");
var connection = new AwsSigV4HttpConnection(RegionEndpoint.APSoutheast2, service: AwsSigV4HttpConnection.OpenSearchService);
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
Console.WriteLine($"{client.RootNodeInfo().Version.Distribution}: {client.RootNodeInfo().Version.Number}");
}
}
}
连接到 Amazon OpenSearch Serverless
以下示例演示了连接到 Amazon OpenSearch 无服务器服务
using OpenSearch.Client;
using OpenSearch.Net.Auth.AwsSigV4;
namespace Application
{
class Program
{
static void Main(string[] args)
{
var endpoint = new Uri("https://search-xxx.region.aoss.amazonaws.com");
var connection = new AwsSigV4HttpConnection(RegionEndpoint.APSoutheast2, service: AwsSigV4HttpConnection.OpenSearchServerlessService);
var config = new ConnectionSettings(endpoint, connection);
var client = new OpenSearchClient(config);
Console.WriteLine($"{client.RootNodeInfo().Version.Distribution}: {client.RootNodeInfo().Version.Number}");
}
}
}
使用 ConnectionSettings
ConnectionConfiguration
用于将配置选项传递给 OpenSearch.Net 客户端。ConnectionSettings
继承自 ConnectionConfiguration
并提供额外的配置选项。以下示例使用 ConnectionSettings
来
- 为未指定索引名称的请求设置默认索引名称。
- 启用 gzip 压缩的请求和响应。
- 向 OpenSearch 发送信号以返回格式化 JSON。
- 将字段名称转换为小写。
var uri = new Uri("https://:9200");
var connectionPool = new SingleNodeConnectionPool(uri);
var settings = new ConnectionSettings(connectionPool)
.DefaultIndex("students")
.EnableHttpCompression()
.PrettyJson()
.DefaultFieldNameInferrer(f => f.ToLower());
var client = new OpenSearchLowLevelClient(settings);
索引单个文档
要索引文档,首先需要创建一个 Student 类实例
var student = new Student {
Id = 100,
FirstName = "Paulo",
LastName = "Santos",
Gpa = 3.93,
GradYear = 2021
};
或者,您可以使用匿名类型创建一个 Student 实例
var student = new {
Id = 100,
FirstName = "Paulo",
LastName = "Santos",
Gpa = 3.93,
GradYear = 2021
};
接下来,使用 Index
方法将此 Student 上传到 students
索引中
var response = client.Index<StringResponse>("students", "100",
PostData.Serializable(student));
Console.WriteLine(response.Body);
Index
方法的泛型类型参数指定了响应正文类型。在上面的示例中,响应是一个字符串。
使用 Bulk API 索引多个文档
要索引多个文档,请使用 Bulk API 将多个操作捆绑到一个请求中
var studentArray = new object[]
{
new {index = new { _index = "students", _type = "_doc", _id = "200"}},
new { Id = 200,
FirstName = "Shirley",
LastName = "Rodriguez",
Gpa = 3.91,
GradYear = 2019
},
new {index = new { _index = "students", _type = "_doc", _id = "300"}},
new { Id = 300,
FirstName = "Nikki",
LastName = "Wolf",
Gpa = 3.87,
GradYear = 2020
}
};
var manyResponse = client.Bulk<StringResponse>(PostData.MultiJson(studentArray));
在接受请求正文的 API 中,您可以将请求正文作为匿名对象、字符串、字节数组或流发送。对于接受多行 JSON 的 API,您可以将正文作为字节列表或对象列表发送,如上例所示。PostData
类具有静态方法,可以以所有这些形式发送正文。
搜索文档
要构建 Query DSL 查询,请在请求正文中使用匿名类型。以下查询搜索所有在 2021 年毕业的学生
var searchResponseLow = client.Search<StringResponse>("students",
PostData.Serializable(
new
{
from = 0,
size = 20,
query = new
{
term = new
{
gradYear = new
{
value = 2019
}
}
}
}));
Console.WriteLine(searchResponseLow.Body);
或者,您可以使用字符串来构造请求。使用字符串时,您必须转义 "
字符
var searchResponse = client.Search<StringResponse>("students",
@" {
""query"":
{
""match"":
{
""lastName"":
{
""query"": ""Santos""
}
}
}
}");
Console.WriteLine(searchResponse.Body);
异步使用 OpenSearch.Net 方法
对于需要异步代码的应用程序,OpenSearch.Client 中的所有方法调用都有对应的异步版本
// synchronous method
var response = client.Index<StringResponse>("students", "100",
PostData.Serializable(student));
// asynchronous method
var response = client.IndexAsync<StringResponse>("students", "100",
PostData.Serializable(student));
处理异常
默认情况下,当操作不成功时,OpenSearch.Net 不会抛出异常。特别是,如果响应状态码是该请求的预期值之一,OpenSearch.Net 不会抛出异常。例如,以下查询在不存在的索引中搜索文档
var searchResponse = client.Search<StringResponse>("students1",
@" {
""query"":
{
""match"":
{
""lastName"":
{
""query"": ""Santos""
}
}
}
}");
Console.WriteLine(searchResponse.Body);
响应包含错误状态码 404,这是搜索请求的预期错误代码之一,因此不会抛出异常。您可以在 status
字段中看到状态码
{
"error" : {
"root_cause" : [
{
"type" : "index_not_found_exception",
"reason" : "no such index [students1]",
"index" : "students1",
"resource.id" : "students1",
"resource.type" : "index_or_alias",
"index_uuid" : "_na_"
}
],
"type" : "index_not_found_exception",
"reason" : "no such index [students1]",
"index" : "students1",
"resource.id" : "students1",
"resource.type" : "index_or_alias",
"index_uuid" : "_na_"
},
"status" : 404
}
要配置 OpenSearch.Net 抛出异常,请在 ConnectionConfiguration
上启用 ThrowExceptions()
设置
var uri = new Uri("https://:9200");
var connectionPool = new SingleNodeConnectionPool(uri);
var settings = new ConnectionConfiguration(connectionPool)
.PrettyJson().ThrowExceptions();
var client = new OpenSearchLowLevelClient(settings);
您可以使用响应对象的以下属性来判断响应是否成功
Console.WriteLine("Success: " + searchResponse.Success);
Console.WriteLine("SuccessOrKnownError: " + searchResponse.SuccessOrKnownError);
Console.WriteLine("Original Exception: " + searchResponse.OriginalException);
Success
返回 true,如果响应代码在 2xx 范围内,或者响应代码是该请求的预期值之一。SuccessOrKnownError
返回 true,如果响应成功,或者响应代码在 400–501 或 505–599 范围内。如果 SuccessOrKnownError 为 true,则不会重试请求。OriginalException
保存了不成功响应的原始异常。
示例程序
以下程序创建索引、索引数据并搜索文档。
using OpenSearch.Net;
using OpenSearch.Client;
namespace NetClientProgram;
internal class Program
{
public static void Main(string[] args)
{
// Create a client with custom settings
var uri = new Uri("https://:9200");
var connectionPool = new SingleNodeConnectionPool(uri);
var settings = new ConnectionSettings(connectionPool)
.PrettyJson();
var client = new OpenSearchLowLevelClient(settings);
Console.WriteLine("Indexing one student......");
var student = new Student {
Id = 100,
FirstName = "Paulo",
LastName = "Santos",
Gpa = 3.93,
GradYear = 2021 };
var response = client.Index<StringResponse>("students", "100",
PostData.Serializable(student));
Console.WriteLine(response.Body);
Console.WriteLine("Indexing many students......");
var studentArray = new object[]
{
new { index = new { _index = "students", _type = "_doc", _id = "200"}},
new {
Id = 200,
FirstName = "Shirley",
LastName = "Rodriguez",
Gpa = 3.91,
GradYear = 2019},
new { index = new { _index = "students", _type = "_doc", _id = "300"}},
new {
Id = 300,
FirstName = "Nikki",
LastName = "Wolf",
Gpa = 3.87,
GradYear = 2020}
};
var manyResponse = client.Bulk<StringResponse>(PostData.MultiJson(studentArray));
Console.WriteLine(manyResponse.Body);
Console.WriteLine("Searching for students who graduated in 2019......");
var searchResponseLow = client.Search<StringResponse>("students",
PostData.Serializable(
new
{
from = 0,
size = 20,
query = new
{
term = new
{
gradYear = new
{
value = 2019
}
}
}
}));
Console.WriteLine(searchResponseLow.Body);
Console.WriteLine("Searching for a student with the last name Santos......");
var searchResponse = client.Search<StringResponse>("students",
@" {
""query"":
{
""match"":
{
""lastName"":
{
""query"": ""Santos""
}
}
}
}");
Console.WriteLine(searchResponse.Body);
}
}