Popular blog tags

C# NEST 客户端 访问 Elasticsearch服务器

Published

Elasticsearch架设起来之后,以服务器的方式运行。Elasticsearch对外提供RESTFUL Api接口,通过以下方式访问:

1.GUI方面:有像kopf之类的Plugin可以用。
2.自己写程序操作接RESTFUL Api
3.通过浏览器访问
4.客户端Elasticsearch .NET:像是连Stack Overflow都使用的NEST。

 

 NEST is a high level .NET client for Elasticsearch which provides a way to call Elasticsearch REST APIs via strongly-typed, easy to use, query DSL.

Elasticsearch.Net. NEST uses the Elasticsearch.Net low level client to dispatch requests and responses, using and extending many of the types within Elasticsearch.Net.

elastic团队开发了2个Elasticsearch .NET的套件,一个是Elasticsearch.Net,一个是NEST,而两者的差异只在于NEST是Elasticsearch.Net的Wrapper,NEST还是base on Elasticsearch.Net,只是NEST提供比较友善的使用方式,让我们在Coding的时候踩的雷比较少,如果我们需要比较进阶的操作是NEST没有提供的,我们还是可以使用Elasticsearch.Net。

 

Elasticsearch和关系型数据库sql server术语对照表

关系数据库      ⇒ 数据库        ⇒  表         ⇒ 行              ⇒ 列(Columns)
 
Elasticsearch  ⇒ 索引(Index)   ⇒ 类型(type)  ⇒ 文档(Docments)  ⇒ 字段(Fields)  

 

建立联机建立联机有2种方式:


        1.联机到单一服务器。
         

namespace Nop.Web.Components
{
    //----new 20210511

    [ViewComponent(Name = "BlogMoreLikeThis")]
    public class BlogMoreLikeThisViewComponent : ViewComponent
    {
        #region Fields
        readonly IConfiguration _configuration;

        #endregion

        public BlogMoreLikeThisViewComponent(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        public async Task<IViewComponentResult> InvokeAsync(string query)
        {
            SearchViewModel viewModel = new SearchViewModel();
            //如果查询字符串为空,则直接返回
            if (String.IsNullOrEmpty(query))
            {



                return View(viewModel);

            }

            try
            {

                // 1.设置

                var nodeUrl = _configuration["BlogMoreLikeThis:ConnectionString"];

                var indexName = _configuration["BlogMoreLikeThis:IndexName"];

                // var node = new Uri("http://localhost:9200"); //old
                var node = new Uri(nodeUrl);  //new

                var settings = new ConnectionSettings(node);
                // settings.DefaultIndex("wwwiaspnetcoreindex"); //old
                settings.DefaultIndex(indexName);   //new
                var client = new ElasticClient(settings);




                //获取分页参数
                int currentPageIndex = 0;
                int itemsPerPage = 10;

                string queryString = query;

                var preQueryString = client.Indices.Analyze(a => a.Index(indexName).Analyzer("ik_max_word").Text(queryString));

                if (!preQueryString.IsValid)
                    throw new ArgumentNullException("字符串分词失败");

                var queryStringLagerThanTwoHzHashSet = new HashSet<string>();

                string queryStringLagerThanTwoHz = "";
                foreach (var item in preQueryString.Tokens)
                {
                    int len = item.Token.Length;

                    if ((len >= 2) && !queryStringLagerThanTwoHz.Contains(item.Token)) //大于两个汉字且字符串中没有同样的
                    {
                        queryStringLagerThanTwoHz += item.Token + " ";
                    }
                }

                var searchResults421 = client.Search<BlogPostModel>(s => s
                  .Index(indexName)
                  .Query(q => q.QueryString(qs => qs.Query(queryString).DefaultOperator(Operator.Or)))
                  );

                var searchResults420 = client.Search<BlogPostModel>(s => s  //高亮成功,加标题,成功

             .From(currentPageIndex)
             .Size(itemsPerPage)
             .Query(q => q.QueryString(qs => qs.Query(queryString).DefaultOperator(Operator.Or)))
             .Sort(ss => ss.Descending(p => p.CreatedOn))// 加入时间排序
              .Highlight(h => h
              .PreTags("<b>")
              .PostTags("</b>")
              .Fields(f => f.Field(e => e.Body).PreTags("<font color =\"red\">").PostTags("</font>"),
                   f => f.Field(e => e.Title).PreTags("<font color =\"red\">").PostTags("</font>")))



    );





                //返回结构用户显示
                var returnsearchResults = new Tuple<IEnumerable<IHit<BlogPostModel>>, long>(searchResults421.Hits, searchResults421.Took);


                viewModel.Results = searchResults421.Hits;
                viewModel.Elapsed = searchResults421.Took;
                viewModel.Total = searchResults421.Total;
                viewModel.Query = query;

                viewModel.Paging.CurrentPage = currentPageIndex + 1;
                viewModel.Paging.ItemsPerPage = itemsPerPage;
                viewModel.Paging.TotalItems = (int)searchResults421.Total;

                return View(viewModel);
            }
            catch (Exception ex)
            {
                return View(viewModel);
            }



        }
    }


    2.建立服务器群,让NEST自己选择联机到运作正常的服务器。
        private ElasticClient ConnectToConnectionPool()
    {
        //建立服务器群
        var elasticNodes = new SniffingConnectionPool(new Uri[] { new Uri(@“http://elasticsearch01:9200”),new Uri(@“http://elasticsearch02:9200”),new Uri(@“http://elasticsearch03:9200”)});
        //产生联机设定,指定服务器群及预设的index名称。
        var connectionSetting = new ConnectionSettings(elasticNodes,“myindex0”);
        //建立Elasticsearch Client,请重覆使用。
        return new ElasticClient(connectionSetting);

     }
索引单笔document要索引一笔document其实很容易。
    private void IndexDocument()
    {
    //假设有一个
    TextItem的objectTextItem textItem = new TextItem()
        {Id = Guid.NewGuid(),Summary =“I'm summary.”,Content =“I'm content.”,AuthorId =“99999”,AuthorName =“Dotblogs”,CreatedTime = DateTime.Now,ModifiedTime = DateTime.Now};
    
    //直接呼叫Index将object给入即可。
    //官网建议自行指定document Id,不指定的话预设Elasticsearch会自己给。
    // type如果不指定,预设就是类别名称。
    this.myindexClient.Index(textItem,indexDescriptor => indexDescriptor.Id(textItem.Id.ToString()));}
IndexDescriptor是用来改变我们在索引数据时的参数,我们可藉由Index方法的重载给入Func<IndexDescriptor<T>,IndexDescriptor<T>>,像上述的例子我们自行将object的Id指定为document的Id,其他像index、type都可以自行指定。索引多笔document要索引多笔document我们要用另一个方法Bulk。
    private void IndexMultipleDocuments()
    {
    //假设我产生了多个TextItemList<TextItem> textItems = CreateTextItems();
    //呼叫Bulk方法,给入一个BulkRequest object,指定BulkRequest.Operations为List<IBulkOperation<TextItem>>。
    //this.myindexClient.Bulk(new BulkRequest(){Operations = textItems.Select(t => new BulkIndexOperation<TextItem>(t){ Id = t.Id.ToString()} as IBulkOperation).ToList()});

    }


    //要索引多笔数据我们可以跑循环一笔一笔用Index方法处理当然也是没问题的,不过这对于Elasticsearch来讲是不一样的,跑回圈用Index方法是「你一笔一笔来我一笔一笔做」,而用Bulk方法一次丢则是「你全部一起来我全部一起做」,在效率上用Bulk一次索引多笔数据绝对是占上风的。.