高级客户端ElasticClient提供了一种强类型查询DSL,它与Elasticsearch查询DSL一对一映射。
它可以从Visual Studio中的Package Manager Console安装
Install-Package NESTNEST是一个高级别的Elasticsearch .NET客户端,仍然非常贴近原始的Elasticsearch API。 所有的请求和响应通过类型暴露,使其成为快速建立和运行的理想选择。
在封面下,NEST使用Elasticsearch.Net低级客户端发送请求和响应,使用并扩展了Elasticsearch.Net中的许多类型。 低级客户端本身仍然通过.LowLevel属性暴露在高级客户端上。
要连接到本地运行在http://localhost:9200上的Elasticsearch就像实例化客户端的一个新实例一样简单
var client = new ElasticClient();通常,您可能需要将其他配置选项传递给客户端,例如Elasticsearch的地址,如果它在远程计算机上运行。 这是ConnectionSettings进来的地方 可以实例化一个实例来为客户端提供不同的配置。
var settings = new ConnectionSettings(new Uri("http://example.com:9200")) .DefaultIndex("people"); var client = new ElasticClient(settings);在此示例中,如果没有为请求提供其他索引,还可以为请求中的POCO泛型类型参数推断默认索引。 ConnectionSettings上还有许多其他配置选项,它从ConnectionConfiguration继承,ConnectionConfiguration用于将其他配置选项传递给Elasticsearch.Net中的低级客户端。
指定默认索引是可选的,但如果没有为给定请求推断索引,NEST可能会引发异常。 要了解更多关于如何为请求指定索引的信息,请参阅索引名称推断。
ConnectionSettings不限于传递Elasticsearch的单个地址。 NEST中有几种不同类型的连接池可用,每种具有不同的特性,可用于配置客户端。 以下示例使用与群集中的三个Elasticsearch节点的地址对接的SniffingConnectionPool,并且客户端将使用此类型的池来维护可以以循环方式发送请求的群集中的可用节点列表。
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 ConnectionSettings(connectionPool) .DefaultIndex("people"); var client = new ElasticClient(settings);一旦客户端被配置为连接到Elasticsearch,我们需要获得一些数据到集群中来处理。
想象一下,我们有以下普通CLR对象(POCO)
public class Person { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }同步或异步地对POCO的单个实例进行索引,就像
var person = new Person { Id = 1, FirstName = "Martijn", LastName = "Laarman" }; var indexResponse = client.Index(person); var asyncIndexResponse = await client.IndexAsync(person);同步方法返回一个IIndexResponse
异步方法返回一个可以等待的Task<IIndexResponse>
NEST中可用的所有方法都会同时显示为同步和异步版本,后者在方法名称上使用惯用的* Async后缀。
这将将文档索引到端点/people/person/1。 NEST足够聪明,可以从Person CLR类型推断类型,并通过在POCO上查找Id属性来推断文档的id。 看看Ids参考,看看NEST可以配置为推断文档的id的其他方式。 ConnectionSettings上配置的默认索引已被用作请求的索引名称。
默认情况下,当将POCO序列化为JSON文档以发送到Elasticsearch时,NEST camel会在POCO上列出属性名称。 您可以使用ConnectionSettings上的.DefaultFieldNameInferrer(Func<string,string>)方法来更改此行为。
现在我们索引了一些文件,我们可以开始搜索它们
var searchResponse = client.Search<Person>(s => s .From(0) .Size(10) .Query(q => q .Match(m => m .Field(f => f.FirstName) .Query("Martijn") ) ) ); var people = searchResponse.Documents;people现在拥有名叫Martijn的前十名人士。 该查询的搜索端点是/people/person/_search,索引"people")和类型"person")值已从
ConnectionSettings上的默认索引搜索上的Person通用类型参数 索引中的所有类型可以使用.AllTypes() var searchResponse = client.Search<Person>(s => s .AllTypes() .From(0) .Size(10) .Query(q => q .Match(m => m .Field(f => f.FirstName) .Query("Martijn") ) ) );它使用ConnectionSettings指定的默认索引作为搜索请求中的索引,向搜索端点/people/_search生成请求。
类似地,可以使用.AllIndices()对所有索引中的person类型执行搜索
var searchResponse = client.Search<Person>(s => s .AllIndices() .From(0) .Size(10) .Query(q => q .Match(m => m .Field(f => f.FirstName) .Query("Martijn") ) ) );它会向搜索端点/_all/person/_search生成请求,从搜索方法的通用类型参数中获取person类型。
可以提供.AllTypes()和.AllIndices()以在所有索引中的所有类型上执行搜索,生成/_search的请求
var searchResponse = await client.SearchAsync<Person>(s => s .AllIndices() .AllTypes() .From(0) .Size(10) .Query(q => q .Match(m => m .Field(f => f.FirstName) .Query("Martijn") ) ) );可以在请求中提供单个或多个索引和类型名称; 请参阅Indices paths和Document paths上的文档。
迄今为止所有的搜索示例都使用了NEST的Fluent API,它使用lambda表达式构造一个具有模拟在Elasticsearch的基于JSON的查询DSL中表达的查询结构的结构的查询。
NEST还暴露了一个对象初始化器语法,也可以用于构造查询,对于那些不深入嵌套的lambda表达式(布局是关键!)的人来说。
这是与上一个例子相同的查询,这次使用Object Initializer语法构造
var searchRequest = new SearchRequest<Person>(Nest.Indices.All, Types.All) { From = 0, Size = 10, Query = new MatchQuery { Field = Infer.Field<Person>(f => f.FirstName), Query = "Martijn" } }; var searchResponse = await client.SearchAsync<Person>(searchRequest);所有索引和类型都在构造函数中指定
如本节开头所示,高级别客户端仍然通过客户端上的.LowLevel属性从Elasticsearch.Net暴露低级客户端。 低级客户端可能在您可能已经拥有代表您要发送的请求的JSON并且不希望将其转换为Fluent API或Object Initializer语法的情况下可用,或者也许 客户端有一个错误,可以通过发送请求作为字符串或匿名类型来解决。
通过.LowLevel属性使用低级客户端意味着您可以获得最好的两个世界:
使用高级客户端 使用低级别的客户端,使用NEST中的所有强类型,并使用基于JSON.Net的串行器进行反序列化。这是一个例子
var searchResponse = client.LowLevel.Search<SearchResponse<Person>>("people", "person", new { from = 0, size = 10, query = new { match = new { field = "firstName", query = "Martijn" } } }); var responseJson = searchResponse.Body;这里,查询表示为匿名类型,但响应的正文是从NEST返回的相同响应类型的具体实现。
除了结构化和非结构化搜索之外,Elasticsearch还可以基于搜索查询来聚合数据
var searchResponse = await client.SearchAsync<Person>(s => s .Size(0) .Query(q => q .Match(m => m .Field(f => f.FirstName) .Query("Martijn") ) ) .Aggregations(a => a .Terms("last_names", ta => ta .Field(f => f.LastName) ) ) ); var termsAggregation = searchResponse.Aggs.Terms("last_names");在这个例子中,像以前一样发行一个match查询来搜索名字叫“Martijn”的人。 这一次,
设置大小为0,因为我们不希望返回匹配此查询的前10个文档,因此我们只对聚合结果感兴趣 指定`terms`聚合,以将匹配文档分组到基于姓氏的桶中。termsAggregation可用于获取每个桶的文档数量,每个桶将以姓氏键入。
有关详细信息,请参阅 Writing aggregations。
