1. 初识Elasticsearch与NEST

Elasticsearch作为分布式搜索和分析引擎,在处理海量数据时表现优异。而NEST作为其官方.NET客户端,就像给C#开发者配了把瑞士军刀。通过对象映射机制,它能把C#的类自动转换成ES文档,配合强类型API设计,让代码可读性飙升。

这里有个冷知识:NEST的查询构建器支持链式调用,这种设计让代码看起来像在说人话。比如Query(q => q.MatchAll())这种写法,是不是比裸写JSON舒服多了?

2. 环境准备

(.NET 6 + NEST 7.17.5) 先装个NuGet包:

Install-Package NEST -Version 7.17.5

创建连接客户端:

var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
    .DefaultIndex("products"); // 设置默认索引

var client = new ElasticClient(settings);

3. 排序的小策略

3.1 基础排序

var searchResponse = await client.SearchAsync<Product>(s => s
    .Query(q => q.MatchAll())
    .Sort(srt => srt
        .Descending(p => p.Price) // 按价格降序
        .Ascending(p => p.CreateTime) // 按创建时间升序
    )
);

// 结果处理示例
foreach (var hit in searchResponse.Hits)
{
    Console.WriteLine($"{hit.Source.Name} 价格:{hit.Source.Price}");
}

3.2 距离排序(地理坐标)

var searchResponse = await client.SearchAsync<Store>(s => s
    .Query(q => q
        .GeoDistance(g => g
            .Field(f => f.Location)
            .Distance("2km")
            .Location(31.2304, 121.4737) // 上海坐标
        )
    )
    .Sort(srt => srt
        .GeoDistance(g => g
            .Field(f => f.Location)
            .Order(SortOrder.Ascending)
            .Unit(DistanceUnit.Kilometers)
            .Points(new GeoCoordinate(31.2304, 121.4737))
        )
    )
);

4. 过滤的艺术

4.1 精确值过滤

var response = client.Search<Product>(s => s
    .Query(q => q
        .Term(t => t
            .Field(f => f.Category.Suffix("keyword")) // 使用keyword类型字段
            .Value("电子产品")
        )
    )
);

4.2 范围过滤

var response = client.Search<Product>(s => s
    .Query(q => q
        .Range(r => r
            .Field(f => f.Price)
            .GreaterThanOrEqualTo(1000)
            .LessThan(5000)
        )
    )
);

4.3 组合过滤

var response = client.Search<Product>(s => s
    .Query(q => q
        .Bool(b => b
            .Must(
                q => q.Term(t => t.Category, "电子产品"),
                q => q.Range(r => r.Price >= 1000)
            )
            .MustNot(q => q
                .Term(t => t.StockQuantity, 0)
            )
        )
    )
);

5. 关联技术:索引映射管理

创建带keyword类型的索引:

var createIndexResponse = client.Indices.Create("products", c => c
    .Map<Product>(m => m
        .Properties(p => p
            .Keyword(k => k.Name(n => n.Category))
            .Number(n => n.Name(n => n.Price).Type(NumberType.Double))
            .Date(d => d.Name(n => n.CreateTime))
        )
    )
);

6. 应用场景剖析

  • 电商平台:商品价格区间过滤+销量排序
  • 物流系统:按距离排序最近的仓库
  • 日志分析:错误日志的等级过滤+时间排序
  • 社交应用:好友动态的时间轴排序

7. 技术优缺点对比

优势

  • 强类型API避免手写JSON的错误
  • LINQ风格的查询构建更符合C#习惯
  • 自动处理连接池和重试机制
  • 丰富的聚合功能支持

不足

  • 学习曲线比直接使用REST API陡峭
  • 版本更新可能导致API变更
  • 复杂查询的性能需要调优

8. 避坑指南

  1. 注意字段类型:text类型字段不能直接排序
  2. 分页陷阱:避免使用from+size处理大数据集
  3. 映射管理:提前规划字段的索引策略
  4. 版本兼容:确保NEST和ES版本匹配
  5. 异常处理:捕获ElasticsearchClientException

9. 最佳实践总结

  • 使用_source参数控制返回字段
  • 为经常过滤的字段添加keyword类型
  • 合理使用Explain()调试查询
  • 定期更新映射时使用别名切换
  • 监控慢查询日志优化性能