ElasticSearch NEST操作(3)详细介绍
- 1. 客户端与连接类#
- 2. 索引管理类#
- 1. CreateIndexDescriptor(索引创建描述符)#
- 2. IndexSettingsDescriptor(索引设置描述符)#
- 3. 其他常见索引操作#
- 最佳实践建议#
- 3. 文档操作类#
- 1 IndexRequest
与 IndexDescriptor 核心功能# - 2 BulkDescriptor#
- 3 UpdateRequest
/ UpdateDescriptor # - 4. 查询与过滤类#
- 1. QueryContainer 与 QueryContainerDescriptor#
- 1.1 - 基本查询(Match Query)
- 1.2 - Term 精确匹配
- 1.3 - 多条件组合
- 2. SearchRequest 与 SearchDescriptor#
- 3. BoolQuery#
- 3.1 - 复杂逻辑组合
- 3.2 - 过滤与评分的分离
- 4 总结#
- 5 MultiSearchDescriptor 多个搜索合并一个请求#
- - MultiSearchDescriptor 的使用场景
- - MultiSearchDescriptor 的基本用法
- - MultiSearchDescriptor 的主要方法
- - MultiSearchDescriptor 的响应
- - MultiSearchDescriptor 的完整示例
- - MultiSearchDescriptor 的优点
- - 注意事项
- 5. 聚合类#
- 6. 响应类#
- 7. 映射与类型类#
- 8. 辅助工具类#
- 9. 异步操作#
NEST 是 Elasticsearch 的官方高级 .NET 客户端,提供了强类型的 DSL(领域特定语言)来与 Elasticsearch 交互。以下是 NEST 中常用的核心类及其用途,按功能分类整理:
1. 客户端与连接类#
-
ElasticClient
所有操作的入口类,用于执行索引、搜索、更新、删除等操作。var settings = new ConnectionSettings(new Uri("http://localhost:9200")); var client = new ElasticClient(settings);
-
ConnectionSettings
配置 Elasticsearch 连接参数(如节点地址、认证、超时时间等)。var settings = new ConnectionSettings(new Uri("http://localhost:9200")) .DefaultIndex("my-index");
2. 索引管理类#
1. CreateIndexDescriptor(索引创建描述符)#
用于定义索引的映射、设置(如分片数、副本数)。
方法 | 作用 |
---|---|
.AutoMap<T>() |
根据类 T 的属性自动推断字段类型 |
.NumberOfShards |
主分片数量(创建后不可修改) |
.NumberOfReplicas |
副本数量(可动态调整) |
.Analysis |
配置自定义分词器、过滤器和 tokenizer |
var createIndexResponse = client.Indices.Create("my-index", c => c
.Map<MyDocument>(m => m.AutoMap())
.Settings(s => s.NumberOfShards(3))
);
更详细:
var createResponse = client.Indices.Create("products", c => c
// 1. 映射配置
.Map<Product>(m => m
.AutoMap() // 自动映射 Product 类的属性
.Properties(p => p
.Text(t => t.Name(n => n.Name).Analyzer("ik_max_word")) // 指定分词器
.Number(n => n.Name(n => n.Price).Type(NumberType.Double)) // 明确指定数值类型
.Date(d => d.Name(n => n.CreatedAt).Format("yyyy-MM-dd")) // 自定义日期格式
)
)
// 2. 索引设置
.Settings(s => s
.NumberOfShards(3) // 主分片数
.NumberOfReplicas(1) // 副本数
.Analysis(a => a // 自定义分析器
.Analyzers(an => an
.Custom("my_analyzer", ca => ca
.Tokenizer("standard")
.Filters("lowercase", "asciifolding")
)
)
)
)
);
2. IndexSettingsDescriptor(索引设置描述符)#
配置索引的分词器、分析器等设置。
专门用于配置索引的高级设置,如分词器、存储优化等。
常见配置场景
- 自定义分析器:定义复杂的分词规则。
- 静态配置:如
refresh_interval
控制索引刷新频率。 - 合并策略:优化段合并行为。
示例
var updateSettingsResponse = client.Indices.UpdateSettings("logs", s => s
.Settings(settings => settings
.Analysis(a => a
.TokenFilters(tf => tf
.Synonym("my_synonyms", sf => sf
.SynonymsPath("analysis/synonym.txt") // 从文件加载同义词
)
)
.Analyzers(an => an
.Custom("my_custom_analyzer", ca => ca
.Tokenizer("whitespace")
.Filters("lowercase", "my_synonyms")
)
)
)
.RefreshInterval("30s") // 每30秒刷新一次索引
.Merge(m => m
.Policy(p => p
.SegmentsPerTier(24) // 控制段合并策略
)
)
)
);
关键参数说明
配置项 | 作用 |
---|---|
.Analysis |
定义分词器、过滤器(如同义词、停用词) |
.RefreshInterval |
索引刷新间隔(影响近实时搜索性能) |
.Merge.Policy |
控制 Lucene 段合并策略,优化写入性能 |
3. 其他常见索引操作#
删除索引
var deleteResponse = client.Indices.Delete("old_index");
获取索引信息
var getResponse = client.Indices.Get("products");
var settings = getResponse.Indices["products"].Settings;
关闭/打开索引
// 关闭索引(禁止写入/搜索)
client.Indices.Close("products");
// 打开索引
client.Indices.Open("products");
别名管理
client.Indices.PutAlias("products", "current_products");
最佳实践建议#
- 分片数量:根据数据量和硬件资源合理设置(通常单个分片 10-50GB)。
- 副本数量:生产环境至少 1 个副本,保障高可用。
- 动态映射:通过
dynamic: strict
避免字段自动映射导致污染。 - 分析器测试:使用
Analyze API
提前验证分词效果。
通过合理使用索引管理 API,可以显著优化 Elasticsearch 的写入性能、查询效率和资源利用率。
3. 文档操作类#
1 IndexRequest<T>
与 IndexDescriptor<T>
核心功能#
用于向 Elasticsearch 索引(插入或更新)单个文档。
- 插入新文档:若文档 ID 不存在,直接创建新文档。
- 更新文档:若文档 ID 已存在,默认会覆盖旧文档(类似
PUT
操作)。 - 自动映射:文档字段类型根据
T
类的属性自动推断(需提前创建索引或启用动态映射)。
基础用法示例
1. 直接索引文档(自动处理 ID)
使用 IndexDocument
快捷方法,自动从对象中提取 Id
属性作为文档 ID:
var document = new MyDocument
{
Id = 1,
Name = "Test Document",
Timestamp = DateTime.UtcNow
};
// 自动使用 document.Id 作为文档 ID
var response = client.IndexDocument(document);
HTTP 请求
POST /my-index/_doc/1 HTTP/1.1
Host: localhost:9200
Content-Type: application/json
Accept: application/json
{
"id": 1,
"name": "Test Document",
"timestamp": "2023-10-05T12:34:56.789Z"
}
2. 显式指定操作参数
使用 Index
方法并通过 IndexDescriptor<T>
精细控制索引行为:
var response = client.Index(new IndexRequest<MyDocument>(document)
{
Index = "my-index", // 指定目标索引名称
Id = document.Id, // 显式设置文档 ID
Routing = "user-123", // 按用户ID路由分片
Refresh = Refresh.True, // 操作后立即刷新索引(确保实时可见)
Version = 5 // 乐观并发控制(仅当文档版本为5时更新)
});
关键参数详解
通过 IndexDescriptor<T>
可配置以下核心参数:
方法/参数 | 说明 |
---|---|
.Id(id) |
手动指定文档 ID(默认从对象的 Id 属性获取) |
.Index("index-name") |
指定文档存储的索引名称(若未设置,使用类名小写化,如 mydocument ) |
.Routing("route-key") |
设置路由键,控制文档存储在哪个分片 |
.Version(version) |
乐观锁控制,仅当文档当前版本匹配时更新 |
.Refresh(Refresh.True) |
操作后立即刷新索引(默认false ,若需实时查询需开启,但影响性能) |
.Timeout("30s") |
等待分片响应的超时时间(防止长时间阻塞) |
.OpType(OpType.Create) |
强制仅创建文档(若ID已存在则失败,避免覆盖) |
.Pipeline("my-pipeline") |
指定预处理管道(如数据转换、字段增强) |
高级用法场景
1. 条件索引(避免覆盖)
使用 OpType.Create
强制仅创建新文档,若 ID 存在则抛出异常:
var response = client.Index(document, i => i
.Id(document.Id)
.OpType(OpType.Create) // 类似于 PUT with _create
);
2. 乐观并发控制
通过版本号或时间戳确保并发更新安全:
// 使用版本号控制
var response = client.Index(document, i => i
.Version(document.Version) // 文档当前版本号(从ES读取时获取)
.VersionType(VersionType.External) // 版本由外部系统管理
);
// 使用时间戳控制
var response = client.Index(document, i => i
.IfSequenceNumber(10) // 仅当序列号匹配时更新
.IfPrimaryTerm(2)
);
3. 动态索引名称
根据数据内容动态选择索引(如按时间分片):
string monthlyIndex = $"logs-{DateTime.UtcNow:yyyy-MM}";
var response = client.Index(document, i => i
.Index(monthlyIndex)
);
最佳实践建议
-
ID 生成策略:
- 业务ID:若文档有唯一业务标识(如订单号),优先手动指定
Id
。 - 自动生成:无业务ID时,可省略
Id
,Elasticsearch 会自动生成唯一 ID(GUID)。
- 业务ID:若文档有唯一业务标识(如订单号),优先手动指定
-
路由优化:
- 对高频查询场景,通过
Routing
将相同路由键的文档存于同一分片,提升查询效率。
- 对高频查询场景,通过
-
性能调优:
- 避免频繁刷新:批量导入时设置
Refresh(false)
减少刷新开销。 - 合理分片:根据数据规模设计分片数,避免单个分片过大(推荐 10-50GB)。
- 避免频繁刷新:批量导入时设置
-
错误处理:
- 捕获
ElasticsearchClientException
处理版本冲突、索引不存在等异常。 - 使用重试机制应对网络波动或临时故障。
- 捕获
完整示例
var document = new Product
{
Id = "p-100",
Name = "Elasticsearch Guide",
Price = 45.99,
Category = "books"
};
var indexResponse = client.Index(document, i => i
.Index("products")
.Id(document.Id)
.Routing(document.Category) // 按分类路由分片
.Timeout("10s")
.Refresh(Refresh.WaitFor) // 等待刷新完成后再返回
.Pipeline("product-enricher") // 通过管道处理数据
);
if (indexResponse.IsValid)
{
Console.WriteLine($"文档索引成功!版本:{indexResponse.Version}");
}
else
{
Console.WriteLine($"错误:{indexResponse.DebugInformation}");
}
通过 IndexRequest<T>
和 IndexDescriptor<T>
,开发者可以灵活控制文档的索引行为,结合 Elasticsearch 的版本控制、路由策略和性能优化选项,构建高效可靠的数据写入逻辑。
2 BulkDescriptor
#
批量操作(索引、更新、删除)的容器。
client.Bulk(b => b
.Index("my-index")
.IndexMany(documents)
);
3 UpdateRequest<T>
/ UpdateDescriptor<T>
#
更新文档内容或脚本操作。
4. 查询与过滤类#
-
QueryContainer
/QueryContainerDescriptor<T>
构建查询条件(如term
、match
、bool
查询)。var searchResponse = client.Search<MyDocument>(s => s .Query(q => q .Match(m => m.Field(f => f.Name).Query("test")) ) );
-
SearchRequest<T>
/SearchDescriptor<T>
定义搜索请求的参数(分页、排序、高亮等)。 -
BoolQuery
组合多个查询条件(must
、should
、must_not
)。
(由于技术原因,联网搜索暂不可用)
以下是关于 Elasticsearch 查询组件 QueryContainer
/ QueryContainerDescriptor<T>
、SearchRequest<T>
/ SearchDescriptor<T>
和 BoolQuery
的详细说明及示例:
1. QueryContainer 与 QueryContainerDescriptor #
作用
QueryContainer
:表示一个查询条件的容器,可以包含任意类型的查询(如MatchQuery
、TermQuery
、BoolQuery
等)。QueryContainerDescriptor<T>
:通过 Fluent API 构建查询条件的描述符,最终生成QueryContainer
。
核心功能
- 构建单个查询条件(如
Match
、Term
、Range
)。 - 组合多个查询条件(通过
BoolQuery
)。 - 支持链式调用语法。
示例
1.1 基本查询(Match Query)
var searchResponse = client.Search<MyDocument>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.Name) // 指定字段(自动映射为小写 `name`)
.Query("test") // 搜索关键词
.Operator(Operator.And) // 关键词逻辑关系(AND 或 OR)
)
)
);
生成的 JSON 查询:
{
"query": {
"match": {
"name": {
"query": "test",
"operator": "and"
}
}
}
}
1.2 Term 精确匹配
var query = new QueryContainerDescriptor<MyDocument>()
.Term(t => t
.Field(f => f.Status) // 字段名 `status`
.Value("published") // 精确匹配值
);
var searchResponse = client.Search<MyDocument>(s => s.Query(_ => query));
生成的 JSON 查询:
{
"query": {
"term": {
"status": {
"value": "published"
}
}
}
}
1.3 多条件组合
使用 QueryContainer
组合多个条件:
QueryContainer combinedQuery = new QueryContainerDescriptor<MyDocument>()
.Match(m => m.Field(f => f.Title).Query("elasticsearch"))
&& new QueryContainerDescriptor<MyDocument>()
.Range(r => r.Field(f => f.Price).GreaterThan(100));
var searchResponse = client.Search<MyDocument>(s => s.Query(_ => combinedQuery));
生成的 JSON 查询:
{
"query": {
"bool": {
"must": [
{ "match": { "title": "elasticsearch" } },
{ "range": { "price": { "gt": 100 } } }
]
}
}
}
2. SearchRequest 与 SearchDescriptor #
作用
SearchRequest<T>
:定义搜索请求的配置(分页、排序、高亮、聚合等)。SearchDescriptor<T>
:通过 Fluent API 构建搜索请求的描述符。
核心功能
- 分页(
From
/Size
)。 - 排序(
Sort
)。 - 高亮(
Highlight
)。 - 聚合(
Aggregations
)。 - 源过滤(
Source
)。
示例
2.1 分页与排序
var searchResponse = client.Search<MyDocument>(s => s
.Query(q => q.MatchAll()) // 匹配所有文档
.From(0) // 从第0条开始(第一页)
.Size(10) // 返回10条结果
.Sort(sort => sort
.Descending(f => f.Price) // 按价格降序
.Ascending(f => f.CreatedAt) // 按创建时间升序
)
);
生成的 JSON 请求:
{
"query": { "match_all": {} },
"from": 0,
"size": 10,
"sort": [
{ "price": "desc" },
{ "createdAt": "asc" }
]
}
2.2 高亮显示
var searchResponse = client.Search<MyDocument>(s => s
.Query(q => q
.Match(m => m.Field(f => f.Description).Query("search engine"))
)
.Highlight(h => h
.Fields(f => f
.Field(fd => fd.Description)
.PreTags("<em>")
.PostTags("</em>")
)
)
);
生成的 JSON 请求:
{
"query": {
"match": {
"description": "search engine"
}
},
"highlight": {
"fields": {
"description": {
"pre_tags": ["<em>"],
"post_tags": ["</em>"]
}
}
}
}
3. BoolQuery#
作用
用于组合多个查询条件的逻辑关系:
Must
:所有条件必须满足(AND 逻辑)。Should
:至少满足一个条件(OR 逻辑)。MustNot
:必须不满足条件(NOT 逻辑)。Filter
:过滤条件(不参与相关性评分,仅过滤)。
示例
3.1 复杂逻辑组合
var searchResponse = client.Search<MyDocument>(s => s
.Query(q => q
.Bool(b => b
.Must(
m => m.Match(mq => mq.Field(f => f.Title).Query("elasticsearch")),
m => m.Range(r => r.Field(f => f.Price).GreaterThan(100))
)
.Should(
s => s.Term(t => t.Field(f => f.Category).Value("books")),
s => s.Term(t => t.Field(f => f.Category).Value("tutorials"))
)
.MustNot(
mn => mn.Term(t => t.Field(f => f.Status).Value("deleted"))
)
.Filter(
f => f.DateRange(d => d.Field(f => f.CreatedAt).GreaterThan("2023-01-01"))
)
)
)
);
生成的 JSON 查询:
{
"query": {
"bool": {
"must": [
{ "match": { "title": "elasticsearch" } },
{ "range": { "price": { "gt": 100 } } }
],
"should": [
{ "term": { "category": "books" } },
{ "term": { "category": "tutorials" } }
],
"must_not": [
{ "term": { "status": "deleted" } }
],
"filter": [
{ "range": { "createdAt": { "gt": "2023-01-01" } } }
]
}
}
}
3.2 过滤与评分的分离
var searchResponse = client.Search<MyDocument>(s => s
.Query(q => q
.Bool(b => b
.Must(
m => m.Match(mq => mq.Field(f => f.Description).Query("fast"))
)
.Filter(
f => f.Term(t => t.Field(f => f.IsPublic).Value(true)),
f => f.Range(r => r.Field(f => f.Rating).GreaterThan(4))
)
)
)
);
生成的 JSON 查询:
{
"query": {
"bool": {
"must": [
{ "match": { "description": "fast" } }
],
"filter": [
{ "term": { "isPublic": true } },
{ "range": { "rating": { "gt": 4 } } }
]
}
}
}
4 总结#
QueryContainer
和QueryContainerDescriptor<T>
用于构建单个或组合查询条件。SearchRequest<T>
和SearchDescriptor<T>
用于定义搜索的全局参数(分页、排序、高亮等)。BoolQuery
是组合复杂查询逻辑的核心工具,支持must
、should
、must_not
和filter
。
通过灵活使用这些组件,可以实现从简单到复杂的搜索需求,并优化查询性能和结果相关性。
MultiSearchDescriptor
是 NEST 框架中用于构建 多搜索请求 的类。它允许你在一次 API 调用中发送多个独立的搜索请求,并一次性获取所有搜索结果。这种方式可以显著减少网络开销,特别适合需要同时执行多个查询的场景。
5 MultiSearchDescriptor 多个搜索合并一个请求#
- 批量执行搜索请求:将多个搜索请求打包成一个请求发送到 Elasticsearch。
- 减少网络开销:避免多次 HTTP 请求的开销。
- 统一管理搜索结果:所有搜索结果会在一个响应中返回,便于后续处理。
MultiSearchDescriptor 的使用场景
- 同时查询多个索引或类型。
- 执行多个独立的查询条件(如不同字段、不同过滤条件)。
- 需要减少网络请求次数以提高性能。
MultiSearchDescriptor 的基本用法
以下是一个简单的示例,展示如何使用 MultiSearchDescriptor
执行多个搜索请求:
var client = new ElasticClient(new ConnectionSettings(new Uri("http://localhost:9200")));
// 定义多个搜索请求
var multiSearchResponse = client.MultiSearch(ms => ms
.Search<MyDocument>("first-search", s => s
.Query(q => q.Match(m => m.Field(f => f.Name).Query("test")))
)
.Search<MyDocument>("second-search", s => s
.Query(q => q.Term(t => t.Field(f => f.Category).Value("electronics")))
)
);
// 获取每个搜索请求的结果
var firstSearchResponse = multiSearchResponse.GetResponse<MyDocument>("first-search");
var secondSearchResponse = multiSearchResponse.GetResponse<MyDocument>("second-search");
MultiSearchDescriptor 的主要方法
-
Search<T>
添加一个搜索请求,指定搜索的名称和查询条件。.Search<MyDocument>("search-name", s => s .Query(q => q.MatchAll()) )
-
GetResponse<T>
从MultiSearchResponse
中获取指定名称的搜索请求结果。var response = multiSearchResponse.GetResponse<MyDocument>("search-name");
MultiSearchDescriptor 的响应
MultiSearchResponse
包含所有搜索请求的响应结果。- 通过
GetResponse<T>
方法获取指定名称的搜索结果。 - 可以通过索引或名称访问每个独立的
ISearchResponse<T>
。
- 通过
MultiSearchDescriptor 的完整示例
以下是一个更完整的示例,展示如何定义多个搜索请求并处理结果:
var client = new ElasticClient(new ConnectionSettings(new Uri("http://localhost:9200")));
// 定义多个搜索请求
var multiSearchResponse = client.MultiSearch(ms => ms
.Search<MyDocument>("search-by-name", s => s
.Query(q => q.Match(m => m.Field(f => f.Name).Query("test")))
.Size(10)
)
.Search<MyDocument>("search-by-category", s => s
.Query(q => q.Term(t => t.Field(f => f.Category).Value("electronics")))
.Size(5)
)
);
// 检查是否成功
if (multiSearchResponse.IsValid)
{
// 获取第一个搜索请求的结果
var searchByNameResponse = multiSearchResponse.GetResponse<MyDocument>("search-by-name");
if (searchByNameResponse.IsValid)
{
var documents = searchByNameResponse.Documents;
Console.WriteLine($"Found {documents.Count} documents by name.");
}
// 获取第二个搜索请求的结果
var searchByCategoryResponse = multiSearchResponse.GetResponse<MyDocument>("search-by-category");
if (searchByCategoryResponse.IsValid)
{
var documents = searchByCategoryResponse.Documents;
Console.WriteLine($"Found {documents.Count} documents by category.");
}
}
else
{
Console.WriteLine("MultiSearch request failed.");
}
MultiSearchDescriptor 的优点
- 性能优化:减少网络请求次数,降低延迟。
- 代码简洁:将多个搜索请求集中管理,便于维护。
- 灵活性:支持不同类型的搜索请求(如不同索引、不同查询条件)。
注意事项
- 每个搜索请求的名称必须唯一,否则会覆盖之前的请求。
- 如果某个搜索请求失败,不会影响其他请求的执行。
- 需要确保 Elasticsearch 集群能够处理批量请求的负载。
通过 MultiSearchDescriptor
,你可以高效地执行多个搜索请求,并统一管理结果,非常适合复杂查询场景。
5. 聚合类#
-
AggregationContainer
/AggregationContainerDescriptor<T>
构建聚合分析(如terms
、date_histogram
)。var response = client.Search<MyDocument>(s => s .Aggregations(a => a .Terms("group_by_field", t => t.Field(f => f.Category)) ) );
-
TermsAggregation
/DateHistogramAggregation
具体聚合类型的实现。
在 Elasticsearch 的 NEST 客户端中,使用 AggregationContainer
和对应的描述器(如 TermsAggregation
/DateHistogramAggregation
)可以灵活构建聚合分析。以下是不同场景下的实现示例:
1. Terms 聚合(按字段分组统计)#
按某个字段的值分组,统计每个分组的文档数量:
var response = client.Search<MyDocument>(s => s
.Aggregations(a => a
.Terms("group_by_category", t => t
.Field(f => f.Category) // 指定分组字段
.Size(10) // 返回前10个分组
.Order(o => o.CountDescending()) // 按文档数降序排序
)
)
);
// 提取聚合结果
var termsAgg = response.Aggregations.Terms("group_by_category");
foreach (var bucket in termsAgg.Buckets)
{
Console.WriteLine($"Category: {bucket.Key}, Count: {bucket.DocCount}");
}
json
{
"aggs": {
"group_by_category": {
"terms": {
"field": "Category",
"size": 10,
"order": {
"_count": "desc"
}
}
}
}
}
2. Date Histogram 聚合(按时间间隔分组)#
按时间间隔(如按月)分组统计文档数量:
var response = client.Search<MyDocument>(s => s
.Aggregations(a => a
.DateHistogram("group_by_month", dh => dh
.Field(f => f.Timestamp) // 指定时间字段
.CalendarInterval(DateInterval.Month) // 按月分组
.Format("yyyy-MM") // 格式化日期输出
)
)
);
// 提取聚合结果
var dateHistogram = response.Aggregations.DateHistogram("group_by_month");
foreach (var bucket in dateHistogram.Buckets)
{
Console.WriteLine($"Month: {bucket.Key}, Count: {bucket.DocCount}");
}
json
{
"aggs": {
"group_by_month": {
"date_histogram": {
"field": "Timestamp",
"calendar_interval": "month",
"format": "yyyy-MM"
}
}
}
}
3. 嵌套聚合(子聚合)#
在分组后,对子组进行二次聚合(如计算平均值):
var response = client.Search<MyDocument>(s => s
.Aggregations(a => a
.Terms("group_by_category", t => t
.Field(f => f.Category)
.Aggregations(sa => sa
.Average("avg_price", avg => avg.Field(f => f.Price)) // 子聚合:计算价格平均值
)
)
)
);
// 提取主聚合和子聚合结果
var termsAgg = response.Aggregations.Terms("group_by_category");
foreach (var bucket in termsAgg.Buckets)
{
var avgPrice = bucket.Average("avg_price");
Console.WriteLine($"Category: {bucket.Key}, Avg Price: {avgPrice.Value}");
}
json
{
"aggs": {
"group_by_category": {
"terms": {
"field": "Category"
},
"aggs": {
"avg_price": {
"avg": {
"field": "Price"
}
}
}
}
}
}
4. 多级聚合(复杂嵌套)#
结合多层聚合,例如先按时间分组,再按类别分组,最后计算统计指标:
var response = client.Search<MyDocument>(s => s
.Aggregations(a => a
.DateHistogram("group_by_month", dh => dh
.Field(f => f.Timestamp)
.CalendarInterval(DateInterval.Month)
.Aggregations(sa => sa
.Terms("subgroup_by_category", t => t
.Field(f => f.Category)
.Aggregations(ssa => ssa
.Sum("total_sales", sum => sum.Field(f => f.Sales))
)
)
)
)
)
);
// 解析多层聚合结果
var dateHistogram = response.Aggregations.DateHistogram("group_by_month");
foreach (var monthBucket in dateHistogram.Buckets)
{
Console.WriteLine($"Month: {monthBucket.Key}");
var termsAgg = monthBucket.Terms("subgroup_by_category");
foreach (var categoryBucket in termsAgg.Buckets)
{
var totalSales = categoryBucket.Sum("total_sales");
Console.WriteLine($" Category: {categoryBucket.Key}, Sales: {totalSales.Value}");
}
}
json
{
"aggs": {
"group_by_month": {
"date_histogram": {
"field": "Timestamp",
"calendar_interval": "month"
},
"aggs": {
"subgroup_by_category": {
"terms": {
"field": "Category"
},
"aggs": {
"total_sales": {
"sum": {
"field": "Sales"
}
}
}
}
}
}
}
}
关键类型说明#
TermsAggregation
: 对应 Elasticsearch 的terms
聚合,用于按字段值分组。DateHistogramAggregation
: 对应date_histogram
聚合,用于按时间区间分组。AggregationContainerDescriptor<T>
: 通过链式调用配置聚合参数(如字段名、排序规则)。AggregationDictionary
: 响应中的聚合结果容器,通过聚合名称(如group_by_category
)获取结果。
通过组合这些聚合类型和方法,可以构建从简单到复杂的数据分析逻辑,满足多维度的统计需求。
6. 响应类#
-
ISearchResponse<T>
搜索操作的响应结果,包含文档和聚合数据。var documents = searchResponse.Documents; // 获取匹配的文档 var termsAgg = searchResponse.Aggregations.Terms("group_by_field");
-
IndexResponse
/BulkResponse
单个文档索引或批量操作的响应结果。
7. 映射与类型类#
-
TypeMappingDescriptor<T>
定义索引的字段映射(类型、分词器、是否存储等)。client.Indices.Create("my-index", c => c .Map<MyDocument>(m => m .AutoMap() // 自动映射 .Properties(p => p .Text(t => t.Name(n => n.Name).Analyzer("standard")) ) ) );
-
属性注解
通过属性标记字段映射(如[Text(Name = "field_name")]
)。
8. 辅助工具类#
-
Id
表示文档的唯一标识,支持多种类型(如string
、int
)。var id = new Id(document);
-
Routing
指定文档的路由值。 -
Nest.JsonNetSerializer
集成 JSON.NET 序列化器,支持自定义序列化逻辑。
9. 异步操作#
所有方法均有异步版本(如 SearchAsync
、IndexAsync
),支持 async/await
。
示例场景
创建索引并索引文档
var client = new ElasticClient(new ConnectionSettings(new Uri("http://localhost:9200")));
// 创建索引
client.Indices.Create("my-index", c => c
.Map<MyDocument>(m => m.AutoMap())
);
// 索引文档
var document = new MyDocument { Id = 1, Name = "Example" };
client.IndexDocument(document);
执行复杂搜索
var response = client.Search<MyDocument>(s => s
.Query(q => q
.Bool(b => b
.Must(mu => mu.Match(m => m.Field(f => f.Name).Query("test"))))
)
.Aggregations(a => a
.DateHistogram("by_month", dh => dh.Field(f => f.Date).CalendarInterval(DateInterval.Month))
)
);
以上是 NEST 中常用的核心类,覆盖了索引管理、文档操作、搜索、聚合等主要功能。具体使用时需结合 Elasticsearch 的版本和 NEST 的文档调整语法。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析