Asp.Net Core 中使用Nest:6.5.1框架查询ElasticSearch数据,使用小结。

模型类:

public class Computer
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public string OtherInfo { get; set;}
    }

插入数据:

数据太多,插入时可能有些不成功,多试几次就好了。但我也不知道原因是什么。

索引要全为小写

var nodes = "http://192.168.50.233:9200/".Split(';').Select(t => new Uri(t));
            var pool = new StaticConnectionPool(nodes);
            var connectionSettings = new ConnectionSettings(pool);
            var es = new ElasticClient(connectionSettings);

            Computer cp1 = new Computer { Id = 5, Name = "神州笔记本1", OtherInfo = "5" };
            Computer cp2 = new Computer { Id = 2, Name = "联想笔记本1", OtherInfo = "2" };
            Computer cp3 = new Computer { Id = 3, Name = "戴尔笔记本1", OtherInfo = "3" };
            Computer cp4 = new Computer { Id = 4, Name = "惠普笔记本1", OtherInfo = "4" };
            List<Computer> cps = new List<Computer> { cp1, cp2, cp3, cp4 };

            //http://192.168.50.233:9200/realyuseit/computer/_search?typed_keys=true
            Result result = Result.NotFound;
            int n = 0;
            cps.ForEach(cp =>
            {
                result = es.Index(cp, t =>
                               t.Index("realyuseit")
                               .Type(TypeName.Create<Computer>())
                               .Id(cp.Id)
                ).Result;
                if (result == Result.Created || result == Result.Updated) n++;
            });
            Console.WriteLine(n);

查询:

var nodes = "http://192.168.50.233:9200/".Split(';').Select(t => new Uri(t));
            var pool = new StaticConnectionPool(nodes);
            var connectionSettings = new ConnectionSettings(pool);
            var es = new ElasticClient(connectionSettings);
            bool eb = es.IndexExists("realyuseit").Exists;
            var result = es.Search<Computer>(x =>
                                    x.Index("realyuseit")
                                    //.Query(q => q.Match(m => m.Field(f => f.Name).Query("其他笔记本6"))) //单字段全文关键字检索 只要Name中包含值即可,且自带分词 4条数据符合
                                    //.Query(q => q.MultiMatch(m => m.Fields(fd=>fd.Fields(f=>f.Name,f=>f.OtherInfo)).Query("1神23456789"))) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词 4条数据符合
                                    //.Analyzer("") // 该分词方法可不需要,因为上面的查询自带分词
                                    //.Query(q => q.Bool(b=>b.Must(m=>m.Term(p=>p.Field(f=>f.Id).Value(4)))))  //条件必须符合,无分词,有一些数据类型可能查询失败
                                    //.Query(q => q.Range(c => c.Field(f => f.Id).LessThanOrEquals(5).GreaterThanOrEquals(3))) //范围查询
                                    .Sort(t => t.Ascending(p=>p.Id)) //id升序
                                    //.From(0) //分页
                                    //.Size(3)
            );
            //以第二次为准,es的特点大家也都知道,我一个小菜鸟还不知道怎么解决,不过查2次够我用了
            if (result.Documents.Count == 0)
            {
                result = es.Search<Computer>(x =>
                                    x.Index("realyuseit")
                                    //.Query(q => q.Match(m => m.Field(f=>f.Name).Query("其他笔记5本6"))) //单字段全文关键字检索 只要Name中包含该值即可,且自带分词
                                    //.Query(q => q.MultiMatch(m => m.Fields(fd => fd.Fields(f => f.Name, f => f.OtherInfo)).Query("1神23456789"))) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词
                                    //.Analyzer("")  // 该分词方法可不需要,因为上面的查询自带分词
                                    //.Query(q => q.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Id).Value(4))))) //条件必须符合的查询,无分词,有一些数据类型可能查询失败
                                    //.Query(q=>q.Range(c=>c.Field(f=>f.Id).LessThanOrEquals(5).GreaterThanOrEquals(3))) //范围查询
                                    .Sort(t => t.Ascending(p => p.Id))
                                    //.From(0) //分页
                                    //.Size(3)
                         );

                //多个条件一起搜索,例子如下
                //var matchQuery = new List<Func<QueryContainerDescriptor<Computer>, QueryContainer>>
                //{
                //    must => must.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Id).Value(5)),
                //                                    m => m.Term(p => p.Field(f => f.Name).Value("神州笔记本1"))
                //                                 )
                //                     ),
                //    range => range.Range(c => c.Field(p => p.Id).LessThanOrEquals(5).GreaterThanOrEquals(3))
                //};
                //var tr = es.Search<Computer>(x=>x.Index("realyuseit").Query(q=>q.Bool(b=>b.Must(matchQuery))));

            }
            var res = result.Documents.ToList();
            var rb = true;

删除数据

偶尔会出现删除不成功的情况,多试几次就好了,但原因是什么我也不知道。

//删除指定/index/type/id数据
//var result  = es.Delete(new DeleteRequest("realyuseit",TypeName.Create<Computer>(),5)).Result;

删除索引

好像还没成功过。

var resultindex = es.DeleteIndex("realyuseit");

不过可以通过发起一个 Delete 方式的http请求将索引直接删除

再次查询就会发现索引不存在了,里面的数据也不存在了。

string indexurl = "http://192.168.50.233:9200/realyuseit";
            var request = WebRequest.Create(indexurl);
            request.Method = "Delete";
            string s = "";
            try
            {
                s = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
            }
            catch {
                Console.WriteLine("ok");
                return;
            }
            DeleteIndexResult res = JsonConvert.DeserializeObject<DeleteIndexResult>(s);
            if (res.acknowledged)
            {
                Console.WriteLine("ok");
            }
            else {
                if (res.status == 404)
                {
                    Console.WriteLine("ok");
                }
                else {
                    Console.WriteLine("false");
                }
            }

封装Nest:6.5.1框架辅助类

/// <summary>
    /// nuget包: nest:6.5.1
    /// </summary>
    public class ElasticSearchHelper
    {
        private readonly ElasticClient _Es;
        //以下划线 _ 结尾
        private readonly string KeyPrefix = string.Empty;
        //以斜杆 / 结尾
        private readonly string FirstConnectUri = string.Empty;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="connection">需以 / 结尾</param>
        /// <param name="prifeix">默认为空</param>
        /// <param name="version">默认为0</param>
        /// 例如:var es = new ElasticSearchHelper("http://192.168.50.233:9200/");
        public ElasticSearchHelper(string connection, string prifeix = "", int version = 0)
        {
            var uris = connection.Split(';').Select(t => new Uri(t));
            var pool = new StaticConnectionPool(uris);
            var connectionSettings = new ConnectionSettings(pool);
            _Es = new ElasticClient(connectionSettings);
            FirstConnectUri = uris.First().AbsoluteUri;
            if (!string.IsNullOrWhiteSpace(prifeix) && !prifeix.Equals("test", StringComparison.CurrentCultureIgnoreCase) && version > 0)
            {
                KeyPrefix = (prifeix + "_" + version + "_").ToLower();
            }
        }

        /// <summary>
        /// 添加或修改Es数据
        /// </summary>
        /// <param name="key">键值</param>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="id">主键</param>
        /// <param name="data">数据</param>
        /// <returns>结果</returns>
        public bool AddOrUpdateEs<T>(string key, long id, T data) where T : class
        {
            //索引小写
            string Key = (KeyPrefix + key).ToLower();
            Result result = _Es.Index(data, t => t.Index(Key).Type(TypeName.Create<T>()).Id(id)).Result;
            if (result == Result.Created || result == Result.Updated)
            {
                return true;
            }
            else
            {
                result = _Es.Index(data, t => t.Index(Key).Type(TypeName.Create<T>()).Id(id)).Result;
                return result == Result.Created || result == Result.Updated;
            }
        }

        /// <summary>
        /// 根据分好词的词语用短语匹配搜索,用这种第三方分词加短语匹配的用法替代没有ik分词的Es环境。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">索引</param>
        /// <param name="phrases">已经分好的词语</param>
        /// <param name="fieldName">对指定字段搜索,字段名使用nameof()获取</param>
        public List<T> PhraseSearch<T>(string key, string fieldName, string[] phrases) where T : class
        {
            //索引小写
            string Key = (KeyPrefix + key).ToLower();
            List<Func<QueryContainerDescriptor<T>, QueryContainer>> shoulds = new List<Func<QueryContainerDescriptor<T>, QueryContainer>>();
            foreach (string p in phrases)
            {
                shoulds.Add(a => a.MatchPhrase(m => m.Field(fieldName.First().ToString().ToLower() + fieldName.Substring(1)).Query(p)));
            }
            var res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
            if (res.Count == 0)
            {
                res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
            }
            return res;
        }

        /// <summary>
        /// 用这种第三方分词加短语匹配的用法替代没有ik分词的Es环境。
        /// 第三方分词采用 nuget包:JIEba.Lucene.Net:1.0.16
        /// github:https://github.com/SilentCC/JIEba-netcore2.0
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="fieldName"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        public List<T> PhraseSearchByJieBa<T>(string key, string fieldName, string str) where T : class
        {
            var segmenter = new JiebaSegmenter();
            string[] phrases = segmenter.CutForSearch(str).ToArray();
            //索引小写
            string Key = (KeyPrefix + key).ToLower();
            List<Func<QueryContainerDescriptor<T>, QueryContainer>> shoulds = new List<Func<QueryContainerDescriptor<T>, QueryContainer>>();
            foreach (string p in phrases)
            {
                shoulds.Add(a => a.MatchPhrase(m => m.Field(fieldName.First().ToString().ToLower() + fieldName.Substring(1)).Query(p)));
            }
            var res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
            if (res.Count == 0)
            {
                res = _Es.Search<T>(x => x.Index(Key).Query(a => a.Bool(b => b.Should(shoulds)))).Documents.ToList();
            }
            return res;
        }

        /// <summary>
        /// 删除指定Id的Es数据
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">键值</param>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public bool DeleteEs<T>(string key, long id) where T : class
        {
            //索引小写
            string Key = (KeyPrefix + key).ToLower();
            var result = _Es.Delete(new DeleteRequest(Key, TypeName.Create<T>(), id)).Result;
            if (result == Result.Deleted || result == Result.NotFound)
            {
                return true;
            }
            else
            {
                result = _Es.Delete(new DeleteRequest(Key, TypeName.Create<T>(), id)).Result;
                return result == Result.Deleted || result == Result.NotFound;
            }
        }

        /// <summary>
        /// 删除索引的所有的数据,http方式,支持模糊匹配索引。
        /// 例如:以user开头的有user1,user2,则传入key值为user*
        /// </summary>
        /// <param name="key">索引</param>
        /// <returns></returns>
        public bool DeleteIndexHttp(string key)
        {
            try
            {
                //索引小写
                string Key = key.ToLower();
                var request = WebRequest.Create(FirstConnectUri + Key);
                request.Method = "Delete";
                string s = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
                IndexResult res = JsonObject.Json2Object<IndexResult>(s);
                if (res.acknowledged)
                {
                    return true;
                }
                else
                {
                    if (res.status == 404)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            catch (Exception ex)
            {
                return true;
            }
        }

        /// <summary>
        /// 删除Es索引,且删除索引对应的所有数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool DeleteIndex(string key)
        {
            //索引小写
            string Key = (KeyPrefix + key).ToLower();

            if (!_Es.IndexExists(Key).Exists)
            {
                return true;
            }

            var result = _Es.DeleteIndex(Key).Acknowledged;
            if (!result)
            {
                result = _Es.DeleteIndex(Key).Acknowledged;
            }
            return result;
        }


        /// <summary>
        /// 分页检索Es数据(同步)
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">键值</param>
        /// <param name="lastRow">跳过的数据个数</param>
        /// <param name="takeCnt">返回数据个数</param>
        /// <param name="matchQuery">例子如下:
        /// var matchQuery = new List<Func<QueryContainerDescriptor<Computer>, QueryContainer>>
        ///           {
        ///                must => must.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Filed).Value(value)))),//条件必须符合的查询,无分词,有一些数据类型可能查询失败
        ///                range => range.Range(c => c.Field(p => p.Id).LessThanOrEquals(5).GreaterThanOrEquals(3)),//范围查询
        ///                match => match.Match(m => m.Field(f=>f.Name).Query("string(自动分词)")), //单字段全文关键字检索 只要Name中包含该值即可,且自带分词
        ///                multimatch => multimatch.MultiMatch(m => m.Fields(fd => fd.Fields(f => f.Name, f => f.OtherInfo)).Query("string(自动分词)")) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词
        ///            };
        /// </param>
        /// <param name="sort">new Func<SortDescriptor<ResFacechatTableInfo>, IPromise<IList<ISort>>>(p => p.Descending(o => o.Field));o为模型类,Field为指定的排序属性名</param>
        /// <param name="analyzer">分词器(ik_smart:最粗粒度的拆分,ik_max_word:最细粒度的拆分)</param>
        /// <returns></returns>
        public List<T> SearchEs<T>(string key, int lastRow = 0, int takeCnt = 100,
            List<Func<QueryContainerDescriptor<T>, QueryContainer>> matchQuery = null,
            Func<SortDescriptor<T>, IPromise<IList<ISort>>> sort = null) where T : class
        {
            //索引小写
            string Key = (KeyPrefix + key).ToLower();

            var result = matchQuery != null ?
                 _Es.Search<T>(x => x
                .Index(Key)
                .Query(q => q.Bool(b => b.Must(matchQuery)))
                .From(lastRow)
                .Size(takeCnt)
                .Sort(sort)) :
                _Es.Search<T>(x => x
                .Index(Key)
                .From(lastRow)
                .Size(takeCnt)
                .Sort(sort))
            ;
            if (result.Documents.Count == 0)
            {
                result = matchQuery != null ?
                 _Es.Search<T>(x => x
                .Index(Key)
                .Query(q => q.Bool(b => b.Must(matchQuery)))
                .From(lastRow)
                .Size(takeCnt)
                .Sort(sort)) :
                _Es.Search<T>(x => x
                .Index(Key)
                .From(lastRow)
                .Size(takeCnt)
                .Sort(sort));
            }

            return result.Documents.ToList();
        }

        /// <summary>
        /// 分页检索Es数据(异步)
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="key">键值</param>
        /// <param name="lastRow">跳过的数据个数</param>
        /// <param name="takeCnt">返回数据个数</param>
        /// <param name="matchQuery">例子如下:
        /// var matchQuery = new List<Func<QueryContainerDescriptor<Computer>, QueryContainer>>
        ///           {
        ///                must => must.Bool(b => b.Must(m => m.Term(p => p.Field(f => f.Filed).Value(value)))),//条件必须符合的查询,无分词,有一些数据类型可能查询失败
        ///                range => range.Range(c => c.Field(p => p.Id).LessThanOrEquals(5).GreaterThanOrEquals(3)),//范围查询
        ///                match => match.Match(m => m.Field(f=>f.Name).Query("string(自动分词)")), //单字段全文关键字检索 只要Name中包含该值即可,且自带分词
        ///                multimatch => multimatch.MultiMatch(m => m.Fields(fd => fd.Fields(f => f.Name, f => f.OtherInfo)).Query("string(自动分词)")) //多字段全文关键字检索 Name或OtherInfo包含该值即可,且自带分词
        ///            };
        /// </param>
        /// <param name="sort">new Func<SortDescriptor<ResFacechatTableInfo>, IPromise<IList<ISort>>>(p => p.Descending(o => o.Field));o为模型类,Field为指定的排序属性名</param>
        /// <param name="analyzer">分词器(ik_smart:最粗粒度的拆分,ik_max_word:最细粒度的拆分)</param>
        /// <returns></returns>
        public async Task<List<T>> SearchEsAsync<T>(string key, int lastRow = 0, int takeCnt = 100,
                List<Func<QueryContainerDescriptor<T>, QueryContainer>> matchQuery = null,
                Func<SortDescriptor<T>, IPromise<IList<ISort>>> sort = null) where T : class
        {
            //索引小写
            string Key = (KeyPrefix + key).ToLower();

            var result = matchQuery != null ?
                await _Es.SearchAsync<T>(x => x
               .Index(Key)
               .Query(q => q.Bool(b => b.Must(matchQuery)))
               .From(lastRow)
               .Size(takeCnt)
               .Sort(sort)) :
               await _Es.SearchAsync<T>(x => x
               .Index(Key)
               .From(lastRow)
               .Size(takeCnt)
               .Sort(sort))
           ;
            if (result.Documents.Count == 0)
            {
                result = matchQuery != null ?
                await _Es.SearchAsync<T>(x => x
               .Index(Key)
               .Query(q => q.Bool(b => b.Must(matchQuery)))
               .From(lastRow)
               .Size(takeCnt)
               .Sort(sort)) :
               await _Es.SearchAsync<T>(x => x
               .Index(Key)
               .From(lastRow)
               .Size(takeCnt)
               .Sort(sort));
            }
            return result.Documents.ToList();
        }

        /// <summary>
        /// 自定义复杂查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public List<T> SearchFunc<T>(Func<ElasticClient, List<T>> func)
        {
            var result = func(_Es);
            if (result.Count == 0)
            {
                return func(_Es);
            }
            return result;
        }

        /// <summary>
        /// 自定义操作_Es
        /// </summary>
        /// <param name="func"></param>
        public void Func(Action<ElasticClient> func)
        {
            func(_Es);
        }

        /// <summary>
        /// 给指定的index/type设置对应字段的分词器
        /// </summary>
        /// <param name="key"></param>
        /// <param name="typename">type名称,全小写</param>
        /// <param name="analyzer">分词器名称</param>
        /// <param name="filedsname">字段名,使用nameof()获取</param>
        /// <returns></returns>
        public bool SetAnalyzer(string key, string typename, string analyzer = null, params string[] filedsname)
        {
            if (string.IsNullOrWhiteSpace(analyzer) || filedsname.Length == 0)
            {
                //默认分词
                return true;
            }
            //type全小写
            typename = typename.ToLower();
            //filed首字母小写
            filedsname = filedsname.Select(p => p.First().ToString().ToLower() + p.Substring(1)).ToArray();
            //索引小写
            string Key = (KeyPrefix + key).ToLower();
            //创建索引
            bool resb = _Es.CreateIndex(Key).Acknowledged == false ? _Es.CreateIndex(Key).Acknowledged : true;
            //映射
            string mappingstringStart = "{\"properties\":{";
            string mappingstringEnd = "}}";
            for (int i = 0; i < filedsname.Length; i++)
            {
                string item = string.Empty;
                if (i == 0)
                {
                    item = "\"" + filedsname[i] + "\":{\"type\":\"string\",\"analyzer\":\"" + analyzer + "\"}";
                }
                else
                {
                    item = ",\"" + filedsname[i] + "\":{\"type\":\"string\",\"analyzer\":\"" + analyzer + "\"}";
                }
                mappingstringStart += item;
            }
            mappingstringStart += mappingstringEnd;
            try
            {
                var request = WebRequest.Create(FirstConnectUri + Key + "/_mapping/" + typename);
                request.Method = "put";
                Stream requestStream = request.GetRequestStream();
                requestStream.Write(Encoding.UTF8.GetBytes(mappingstringStart));
                requestStream.Close();
                string s = new StreamReader(request.GetResponse().GetResponseStream()).ReadToEnd();
                IndexResult res = JsonObject.Json2Object<IndexResult>(s);
                if (res.acknowledged)
                {
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        private class IndexResult
        {
            /// <summary>
            /// 为true,代表删除Index成功。为false,代表删除失败,不正常。默认false
            /// </summary>
            public bool acknowledged { get; set; }
            /// <summary>
            /// 为404,代表Index不存在,已删除
            /// </summary>
            public int status { get; set; }
        }


    }

猜你喜欢

转载自blog.csdn.net/qq_38261174/article/details/97911363