Elastic學習之旅 (12) .NET 6應用集成ES - 下

大家好,我是Edison。

上一篇:.NET集成ES進行CRUD

寫在開頭

在.NET應用中集成ES一般涉及兩個方面:

(1)將ES當存儲用,類似於MongoDB,做文檔的增刪查改,這一類操作偏CRUD。

(2)對ES中的數據做查詢分析,聚合統計、分組等等,這一類操作偏查詢分析。

上一篇我們瞭解了CRUD,我們今天再來搞定查詢和聚合作爲本系列的結尾!

增加模型

爲了進行今天的查詢和聚合,我們在上一篇的demo項目中增加一個Product模型。都是常規字段,就不再解釋了。

public class Product : ElasticModelBase
{
    public string Ean { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string Brand { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
    public int Quantity { get; set; }
    public DateTime ReleaseDate { get; set; }
}

與此同時,新增一個ProductRepository:

public class ProductRepository : ElasticRepositoryBase<Product>, IProductRepository
{
    public ProductRepository(IElasticProxy elasticProxy) : base(elasticProxy)
    {
    }

    protected override string IndexName => "products";
}

分頁查詢

我們在上一篇的demo項目中其實已經做了分頁查詢的基礎實現了:

public virtual async Task<Tuple<int, IList<T>>> QueryAsync(int page, int limit)
{
  var query = await this.Client.SearchAsync<T>(x => x.Index(this.IndexName)
   .From((page -1) * limit)
   .Size(limit));

  return new Tuple<int, IList<T>>(Convert.ToInt32(query.Total), query.Documents.ToList());
}

但很多時候我們還想要根據某個字段排序,我們可以在上一篇的基類的基礎上重寫一下,在ProductRepository就可以實現:

public override async Task<Tuple<int, IList<Product>>> QueryAsync(int page, int limit)
{
  var query = await this.Client.SearchAsync<Product>(x => x.Index(this.IndexName)
    .From((page - 1) * limit)
    .Size(limit)
    .Sort(x => x.Descending(v => v.ReleaseDate)));

  return new Tuple<int, IList<Product>>(Convert.ToInt32(query.Total), query.Documents.ToList());
}

條件查詢(基於Term)

我們在之前的學習中學習了結構化搜索主要是通過Term來進行查詢,那麼假如我們想要根據EAN字段來查詢某個product,則可以在ProductRepository中新增一個方法來實現:

public async Task<IList<Product>> QueryByEanAsync(string ean)
{
  var result = await this.Client.SearchAsync<Product>(x => x.Index(this.IndexName)
    .Query(q => q.Term(p => p.Ean, ean)));
  return result.Documents.ToList();
}

一般來說,Query的結果默認是document集合。這裏我們測試結果如下:

那麼,如果是多條件查詢呢?比如:根據一個key查詢EAN或Name,這就是多個Term的Or查詢:

public async Task<IList<Product>> QueryByEanOrNameAsync(string key)
{
  var result = await this.Client.SearchAsync<Product>(x => x.Index(this.IndexName)
    .Query(q => q.Term(p => p.Ean, key) || q.Term(p => p.Name, key)));
  return result.Documents.ToList();
}

比如:根據一個key查詢Name並只篩選Status="Active"的product,這就是多個Term的And查詢:

public async Task<IList<Product>> GetActiveProductsByNameAsync(string key)
{
  var result = await this.Client.SearchAsync<Product>(x => x.Index(this.IndexName)
    .Query(q => q.Term(p => p.Name, key) && q.Term(p => p.Status, "Active")));
  return result.Documents.ToList();
}

聚合統計

我們在之前的學習中學習了聚合查詢,那麼這裏我們通過聚合來統計一下Product數據中Price字段的最大值、最小值和平均值:

public async Task<Nest.AggregateDictionary> QueryPriceAggAsync()
{
  var searchResult = await this.Client.SearchAsync<Product>(x => x.Index(this.IndexName)
    .Size(0) // 代表不返回源數據
    .Aggregations(agg => agg.Average("price_avg", avg => avg.Field("price"))
        .Max("price_max", max => max.Field("price"))
        .Min("price_min", min => min.Field("price")))
    );
  return searchResult.Aggregations;
}

聚合分組

如果我們想要根據某個字段分組查詢product數據,那麼可以使用聚合分組:

public async Task<Nest.AggregateDictionary> QueryBrandAggAsync()
{
  var searchResult = await this.Client.SearchAsync<Product>(x => x.Index(this.IndexName)
    .Size(0) // 代表不返回源數據
    .Aggregations(agg => agg.Terms("brandgroup", group => group.Field("brand"))
    ));
  return searchResult.Aggregations;
}

小結

本篇,我們瞭解瞭如何在ASP.NET 6應用中對ES中的數據進行查詢 和 聚合,通過使用這些查詢我們可以在應用中實現一些報表功能。到此,本系列的學習之旅就要跟大家說聲再見了,12篇說多不多,持續輸出就是堅持,希望對你學習ElasticSearch有所幫助。

示例代碼

Github:https://github.com/Coder-EdisonZhou/ElasticSamples

參考資料

博客園,包子wxl,《ElasticSearch使用系列-.NET6對接ES

CSDN,阿星Plus,《.NET Core下使用ES

CSDN,風神.NET,《如何在ASP.NET Core中集成ES

極客時間,阮一鳴,《ElasticSearch核心技術與實戰

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章