【愚公系列】2022年05月 .NET架构班 065-分布式中间件 .Net Core下使用Elasticsearch落地情况分

举报
愚公搬代码 发表于 2022/05/10 23:34:27 2022/05/10
【摘要】 一、.Net Core下使用Elasticsearch落地情况分析 1.查询商品业务场景落地ProductController类中添加代码/// <summary>/// 商品控制器/// </summary>[ApiController][Route("Product")]public class ProductController : ControllerBase{ privat...

一、.Net Core下使用Elasticsearch落地情况分析

1.查询商品业务场景落地

ProductController类中添加代码

/// <summary>
/// 商品控制器
/// </summary>
[ApiController]
[Route("Product")]
public class ProductController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductController(IProductService productService)
    {
        _productService = productService;
    } 
    /// <summary>
    /// 搜索商品
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public ActionResult<Product> GetProduct(string id)
    {
        var product = _productService.GetProductById(id);

        if (product == null)
        {
            return NotFound();
        }

        return product;
    }
}

ProductService 服务类

/// <summary>
/// 商品服务实现
/// </summary>
public class ProductService : IProductService
{
    private readonly IMongoCollection<Product> _products;

    public ProductService()
    {
        #region 1、单实例连接
            {
                var node = new Uri("http://localhost:9200");
                // var defaultIndex = "products";

                var settings = new ConnectionSettings(node);
                //.DefaultIndex(defaultIndex);

                elasticClient = new ElasticClient(settings);
            }
            #endregion
     
    }

    public Product GetProductById(string id)
        {
            return elasticClient.Get<Product>(id, idx => idx.Index("products")).Source;
        }
 }

2.搜索商品业务场景落地

/// <summary>
/// 商品控制器
/// </summary>
[ApiController]
[Route("Product")]
public class ProductController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductController(IProductService productService)
    {
        _productService = productService;
    } 
    
    /// <summary>
    /// 全文查询
    /// </summary>
    /// <param name="productDto"></param>
    /// <returns></returns>
    [HttpGet("KeywordSearch")]
    public ActionResult<IEnumerable<Product>> GetProductsKeywordSearch([FromQuery]ProductDto productDto)
    {
        var products = _productService.GetProductsKeywordSearch(productDto);

        if (products == null)
        {
            return NotFound();
        }

        return products.ToList();
    }
}

二、.Net Core下使用Elasticsearch的封装

1.nuget包

NEST

2.控制器

ProductController

[ApiController]
[Route("Product")]
public class ProductController : ControllerBase
{
    private readonly ILogger<ProductController> _logger;
    private readonly IProductService _productService;

    public ProductController(ILogger<ProductController> logger, IProductService productService)
    {
        _logger = logger;
        _productService = productService;
    }

    /// <summary>
    /// 查询商品
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public ActionResult<IEnumerable<Product>> GetProducts()
    {
        return _productService.GetProducts().ToList();
    }

    
    /// <summary>
    /// 查询商品
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public ActionResult<Product> GetProduct(string id)
    {
        var product = _productService.GetProductById(id);

        if (product == null)
        {
            return NotFound();
        }

        return product;
    }

    /// <summary>
    /// 查询商品(分页查询)
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("ProductsPage")]
    public ActionResult<IEnumerable<Product>> GetProductsByPage(int page, int pageSize)
    {
        var products = _productService.GetProductsByPage(page, pageSize).ToList();

        if (products == null)
        {
            return NotFound();
        }

        return products;
    }

    /// <summary>
    /// 字段查询
    /// </summary>
    /// <param name="productDto"></param>
    /// <returns></returns>
    [HttpGet("KeywordSearch")]
    public ActionResult<IEnumerable<Product>> GetProductsKeywordSearch([FromQuery]ProductDto productDto)
    {
        var products = _productService.GetProductsKeywordSearch(productDto);

        if (products == null)
        {
            return NotFound();
        }

        return products.ToList();
    }

    /// <summary>
    /// 全文搜索
    /// </summary>
    /// <param name="productDto"></param>
    /// <returns></returns>
    [HttpGet("TextSearch")]
    public ActionResult<IEnumerable<Product>> GetProductsTextSearch([FromQuery] ProductDto productDto)
    {
        var products = _productService.GetProductsTextSearch(productDto);

        if (products == null)
        {
            return NotFound();
        }

        return products.ToList();
    }

    /// <summary>
    /// 聚合查询
    /// </summary>
    /// <param name="productDto"></param>
    /// <returns></returns>
    [HttpGet("AggreateTextSearch")]
    public ActionResult<ValueAggregate> GetProductsAggreateTextSearch([FromQuery] ProductDto productDto)
    {
        var products = _productService.GetProductsAggreateTextSearch(productDto);

        if (products == null)
        {
            return NotFound();
        }

        return products;
    }

    /// <summary>
    /// 添加商品
    /// </summary>
    /// <param name="product"></param>
    /// <returns></returns>
    [HttpPost]
    public ActionResult<Product> PostProduct(Product product)
    {
        _productService.Create(product);
        return CreatedAtAction("GetProduct", new { id = product.Id }, product);
    }

    /// <summary>
    /// 修改商品
    /// </summary>
    /// <param name="id"></param>
    /// <param name="product"></param>
    /// <returns></returns>
    [HttpPut("{id}")]
    public IActionResult PutProduct(string id, Product product)
    {
        if (id != product.Id)
        {
            return BadRequest();
        }

        try
        {
            _productService.Update(product);
        }
        catch (Exception)
        {
            throw;
        }

        return NoContent();
    }

    /// <summary>
    /// 删除商品
    /// </summary>
    /// <param name="id"></param>
    /// <param name="product"></param>
    /// <returns></returns>
    [HttpDelete("{id}")]
    public IActionResult DeleteProduct(string id)
    {

        try
        {
            _productService.Delete(id);
        }
        catch (Exception)
        {
            throw;
        }

        return NoContent();
    }
}

3.CRUD封装

/// <summary>
/// 商品服务接口
/// </summary>
public interface IProductService
{
    IEnumerable<Product> GetProducts();
    IEnumerable<Product> GetProductsByPage(int page, int pageSize);
    IEnumerable<Product> GetProducts(List<string> ids);

    /// <summary>
    /// 全文搜索(keyword查询)
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsKeywordSearch(ProductDto productDto);

    /// <summary>
    /// 全文搜索(text查询)
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsTextSearch(ProductDto productDto);

    /// <summary>
    /// 全文搜索(text范围查询)
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsRangeTextSearch(ProductDto productDto);

    /// <summary>
    /// 全文搜索(text聚合查询)
    /// </summary>
    /// <returns></returns>
    ValueAggregate GetProductsAggreateTextSearch(ProductDto productDto);

    /// <summary>
    /// 全文搜索(text查询)---(排序)
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsTextSearchSort(ProductDto productDto);

    /// <summary>
    /// 全文搜索(MutilText查询)
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsMutilTextSearch(ProductDto productDto);

    /// <summary>
    /// 全文搜索(嵌套文档查询)
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsNestedTextSearch(ProductDto productDto);


    /// <summary>
    /// 全文搜索(扩展(地理位置查询和IP查询))
    /// </summary>
    /// <returns></returns>
    IEnumerable<Product> GetProductsIPTextSearch(ProductDto productDto);

    Product GetProductById(string id);
    void Create(Product Product);
    void CreateList(List<Product> Products);
    void Update(Product Product);
    void UpdateList(List<Product> Products);
    void Delete(string Id);
    void Deletelist(List<Product> Products);
    bool ProductExists(int id);
}
public class ProductService : IProductService
{
    private readonly ElasticClient elasticClient;

    public ProductService(/*IConfiguration configuration*/IOptions<ProductMongoDBOptions> options)
    {
        /* ProductMongoDBOptions productMongoDBOptions = options.Value;
         // 1、建立MongoDB连接
         var client = new MongoClient(productMongoDBOptions.ConnectionString);

         // 2、获取商品库
         var database = client.GetDatabase("productdb");

         // 3、获取商品表(集合)
         _products = database.GetCollection<Product>("Product");*/
        #region 1、单实例连接
        {
           /* var node = new Uri("http://localhost:9200");
            // var defaultIndex = "products";

            var settings = new ConnectionSettings(node);
            //.DefaultIndex(defaultIndex);

            elasticClient = new ElasticClient(settings);*/
        }
        #endregion

        #region 2、集群连接
        {
            var nodes = new Uri[]
            {
                new Uri("http://localhost:9201"),
                new Uri("http://localhost:9202"),
                new Uri("http://localhost:9203"),
            };
            var pool = new StaticConnectionPool(nodes);
            var settings = new ConnectionSettings(pool);

            elasticClient = new ElasticClient(settings);
        }
        #endregion

    }

    public void Create(Product Product)
    {
        elasticClient.Index(Product,idx => idx.Index("products_cluster")); // 创建数据库
    }

    public void CreateList(List<Product> Products)
    {
        elasticClient.IndexMany<Product>(Products, "products");
    }

    public void Delete(string Id)
    {
        elasticClient.Delete<Product>(Id, idx => idx.Index("products"));
    }

    public void Deletelist(List<Product> Products)
    {
        elasticClient.DeleteMany<Product>(Products, "products");
    }

    public Product GetProductById(string id)
    {
        return elasticClient.Get<Product>(id, idx => idx.Index("products")).Source;
    }

    public IEnumerable<Product> GetProducts()
    {
        #region 1、直接查询
        {
            var request = new SearchRequest("products");
            var dems = elasticClient.Search<Product>(request);
            return dems.Documents;
        }
        #endregion

        #region 2、委托查询
        {
            return elasticClient.Search<Product>(s => s
            .Index("products")
            ).Documents;
        }
        #endregion
    }

    public IEnumerable<Product> GetProductsByPage(int page, int pageSize)
    {
        #region 1、直接查询
        {
            var request = new SearchRequest("products");
            request.From = (page-1)* pageSize;
            request.Size = pageSize;

            return elasticClient.Search<Product>(request).Documents;
        }
        #endregion

        #region 2、委托查询
        {
            return elasticClient.Search<Product>(s => s
            .Index("products")
            .From((page - 1) * pageSize)
            .Size(pageSize)
            ).Documents;
        }
        #endregion
    }

    public IEnumerable<Product> GetProducts(List<string> ids)
    {
        List<Product> products = new List<Product>();
        var response = elasticClient.GetMany<Product>(ids, "products");

        foreach (var multiGetHit in response)
        {
            if (multiGetHit.Found)
            {
                products.Add(multiGetHit.Source);
            }
        }
        return products;
    }

    public IEnumerable<Product> GetProductsKeywordSearch(ProductDto productDto)
    {
       return elasticClient.Search<Product>(s => s
        .Index("products_cluster")
        .Query(q => q
          .Match( mq => mq.Field(f => f.ProductTitle).Query(productDto.ProductTitle))
        )
       ).Documents;
    }

    public IEnumerable<Product> GetProductsTextSearch(ProductDto productDto)
    {
        #region 1、单文本查询
        {
            return elasticClient.Search<Product>(s => s
            .Index("products")
            .Query(q => q
              .Term(t => t.ProductTitle, productDto.ProductTitle)
            )
           ).Documents;
        }
        #endregion
    }

    public IEnumerable<Product> GetProductsRangeTextSearch(ProductDto productDto)
    {
        #region 1、单文本范围查询
        {
            return elasticClient.Search<Product>(s => s
            .Index("products")
            .Query(q => q
               .TermRange(tr => tr.Field(f => f.ProductPrice).GreaterThanOrEquals("19.00").LessThan("100.00"))
            )
           ).Documents;
        }
        #endregion
    }

    public ValueAggregate GetProductsAggreateTextSearch(ProductDto productDto)
    {
        #region 1、聚合查询(平均值)
        {
            var ducmentsss = elasticClient.Search<Product>(s => s
                     .Index("products")
                     .Query(q => q.Match(mq => mq.Field(f => f.ProductTitle).Query(productDto.ProductTitle)))
                     .Aggregations(a => a.Average("ProductPrice_Average", aa => aa.Field(f => f.ProductPrice)))
                     .Aggregations(a => a.Min("ProductPrice_Min", aa => aa.Field(f => f.ProductPrice)))
                     .Aggregations(a => a.Max("ProductPrice_Max", aa => aa.Field(f => f.ProductPrice)))
                     .Aggregations(a => a.Sum("ProductPrice_Sum", aa => aa.Field(f => f.ProductPrice)))
                   ).Aggregations.Min("ProductPrice_Max");

            return ducmentsss;
        }
        #endregion

        #region 2、聚合查询(求和)
        {
            /*return elasticClient.Search<Product>(s => s
                    .Index("products")
                    .Query(q => q
                       .Term(t => t.ProductTitle, productDto.ProductTitle)
                    ).Aggregations(a => a
                       .Sum("ProductPrice_Sum", aa => aa.Field(f => f.ProductPrice))
                    )
                   ).Aggregations.Sum("ProductPrice_Sum");*/
        }
        #endregion

        #region 3、聚合查询(最小值)
        {
            /*return elasticClient.Search<Product>(s => s
                    .Index("products")
                    .Query(q => q
                       .Term(t => t.ProductTitle, productDto.ProductTitle)
                    ).Aggregations(a => a
                       .Min("ProductPrice_Min", aa => aa.Field(f => f.ProductPrice))
                    )
                   ).Aggregations.Min("ProductPrice_Min");*/
        }
        #endregion

        #region 4、聚合查询(最大值)
        {
            /*return elasticClient.Search<Product>(s => s
                    .Index("products")
                    .Query(q => q
                       .Term(t => t.ProductTitle, productDto.ProductTitle)
                    ).Aggregations(a => a
                       .Max("ProductPrice_Max", aa => aa.Field(f => f.ProductPrice))
                    )
                   ).Aggregations.Max("ProductPrice_Max");*/
        }
        #endregion

        #region 5、聚合查询(百分数)
        {
            var test = elasticClient.Search<Product>(s => s
                    .Index("products")
                    .Query(q => q
                       .Term(t => t.ProductTitle, productDto.ProductTitle)
                    ).Aggregations(a => a
                       .Percentiles("ProductPrice_Percentiles", aa => aa.Field(f => f.ProductPrice))
                    )
                   ).Aggregations.Percentiles("ProductPrice_Percentiles");

            return null;
        }
        #endregion
    }

    public IEnumerable<Product> GetProductsTextSearchSort(ProductDto productDto)
    {
        #region 1、文本查询(升序排序)
        {
            return elasticClient.Search<Product>(s => s
                    .Index("products")
                    .Query(q => q
                       .Term(t => t.ProductTitle, productDto.ProductTitle)
                    ).Sort(s => s.Ascending(a => a.Id))
                   ).Documents;
        }
        #endregion

        #region 1、文本查询(降序序排序)
        {
            return elasticClient.Search<Product>(s => s
                    .Index("products")
                    .Query(q => q
                       .Term(t => t.ProductTitle, productDto.ProductTitle)
                    ).Sort(s => s.Descending(a => a.Id))
                   ).Documents;
        }
        #endregion
    }

    public IEnumerable<Product> GetProductsMutilTextSearch(ProductDto productDto)
    {
        #region 1、多文本 ||查询
        {
            return elasticClient.Search<Product>(s => s
          .Index("products")
          .Query(q => q
            .Term(t => t.ProductTitle, "tony") || q
            .Term(t => t.ProductDescription,"text")
          )
         ).Documents;
        }
        #endregion

        #region 2、多文本 && 查询
        {
            return elasticClient.Search<Product>(s => s
              .Index("products")
              .Query(q => q
                .Term(t => t.ProductTitle, "tony") && q
                .Term(t => t.ProductDescription, "text")
              )
             ).Documents;
        }
        #endregion
    }


    public IEnumerable<Product> GetProductsNestedTextSearch(ProductDto productDto)
    {
        #region 1、对象嵌套查询
        {
            return elasticClient.Search<Product>(s => s
              .Index("products")
              .Query(q => q
                //.Term(t => t.ProductDescription, "tony")
                /*.Nested(n => n
                  .Path(p => p.productSales)
                  .Query(q => q
                       .Term(m => m
                          .Field( f => f.productSales.SoldCount)
                          .Value("2")
                       )
                    )
                 )*/
               )).Documents;
        }
        #endregion

        #region 2、数组嵌套查询
        {
            return elasticClient.Search<Product>(s => s
              .Index("products")
              .Query(q => q
                //.Term(t => t.ProductDescription, "tony")
                /*.Nested(n => n
                  .Path( p => p.productImages)
                  .Query( q => q
                       .Match( m => m
                          .Field(f => f.productImages[0].ImageStatus)
                          .Query("1")
                        )
                   )
                 )*/
               )).Documents;
        }
        #endregion
    }

    public void Update(Product Product)
    {
        elasticClient.Update<Product>(Product.Id, idx =>
            idx.Upsert(Product).Index("products")
        );
    }

    public void UpdateList(List<Product> Products)
    {
        // elasticClient.PutScript
        // elasticClient.SearchShards
        // elasticClient.UpdateByQuery
    }

    public bool ProductExists(int id)
    {
        return elasticClient.DocumentExists<Product>(id, idx =>idx.Index("products")).Exists;
    }

    public IEnumerable<Product> GetProductsIPTextSearch(ProductDto productDto)
    {
        throw new NotImplementedException();
    }
}

三、扩展

以下是Elasticsearch中crud写法,不过目前Elasticsearch支持sql写法以下适用于老版本

1.索引操作

1.1 创建索引

创建索引yg

PUT /yg
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 0
    }
  }
}
  • number_of_shards是主分片数。
  • number_of_replicas是一个主分片有多少个本。

那么总的分片数就是(number_of_replicas + 1) * number_of_shards

1.2 查看索引

GET /yg/

1.3 删除索引

DELETE /yg/

2.文档操作

2.1 插入文档

自动生成_id

POST /yg/_doc
{
  "title": "The Pursuit of Happyness",
  "actors": [
    "Will Smith",
    "Jaden Smith",
    "Thandie Newton"
  ]
}

指定_id=1

PUT /yg/_doc/1
{
  "title": "The Pursuit of Happyness",
  "actors": [
    "Will Smith",
    "Jaden Smith",
    "Thandie Newton"
  ]
}

覆盖文档

PUT /yg/_doc/1
{
  "title": "xxx"
}

如果是指定_id的情况下文档已经存在的话,会直接进行覆盖,如果里面有些字段没传,那个字段就不会存储了,比如上面的覆盖文档,执行完后去获取_id=1的数据,只能获取到title字段,actors字段是不存在的。

2.2 更新文档

POST /yg/_update/1
{
  "doc":{
    "title": "The Pursuit of Happyness xxx"
  }
}

更新_id=1的数据,注意需要有doc。如果用POST /yg/_update/1这种语法,就直接覆盖了。

2.3 删除文档

删除_id=1的数据

DELETE /yg/_doc/1

2.4 获取文档

获取_id=1的数据

GET /yg/_doc/1

2.5 搜索文档

GET /ygs/_search
{
  "profile": "true",
  "_source": ["movieId", "title","genres"], 
  "sort": [{"movieId": "desc"}],
  "from": 0,
  "size": 3,
  "query": {
    "match_all": {}
  }
}

上面翻译成sql语句是

select movieId, title, genres from ygs order by movieId desc limit 0, 3
  • ygs是之前导入的数据,非前面用的yg,需要测试的话要先导入一下数据。
  • profile 相当于MySQL中的explain
  • _source 是要返回的字段

3.文档数据操作

3.1 文档数据更新

{"index":{"_index":"yg","_id":1}}
{"title": "xxx xx"}

{"index":{"_index":"yg","_id":2}}
{"title": "The Pursuit of Happyness"}

{"update":{"_index":"yg","_id":2}}
{"doc":{"title": "xxx xx"}}

3.2 文档数据读取

GET _mget
{
  "docs": [
    {
      "_index": "yg",
      "_id": 1
    },
    {
      "_index": "yg",
      "_id": 2
    }
  ]
}

如果是对同一个index进行操作,可以在URI指定index

GET yg/_mget
{
  "docs": [
    {
      "_id": 1
    },
    {
      "_id": 2
    }
  ]

3.3 文档数据查询

GET /movies/_msearch
{}
{"from":0,"size":1,"query":{"match_all":{}}}
{}
{"from":0,"size":2,"query":{"match_all":{}}}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。