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, // 显式设置文档 IDRouting = "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
)。
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
具体聚合类型的实现。
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 的文档调整语法。