ElasticSearch-.net平台下c#操作ElasticSearch详解
ElasticSearch系列學習
ElasticSearch第一步-環境配置
ElasticSearch第二步-CRUD之Sense?
ElasticSearch第三步-中文分詞
ElasticSearch第四步-查詢詳解
ElasticSearch第五步-.net平臺下c#操作ElasticSearch詳解
前面我們講解了關于ElasticSearch的安裝配置,以及CRUD
本章我將講解怎么使用c#操作ElasticSearch。
首先你需要一定的技術儲備,比如:asp.net webapi,mvc,jsonp,knockout。這些知識在這里不再講解,請自行Google。
項目DEMO介紹
搜索和索引功能我是以服務(webapi項目)方式提供的,在客戶端(mvc項目)中的view視圖中,直接使用ajax(jsonp格式)方式調用webapi,然后使用knockout綁定到table上的。
項目結構如圖:
引入驅動
工欲善其事必先利其器,首先我們需要在Supernova.Webapi層中引入操作ElasticSearch的驅動dll?PlainElastic.Net。
如圖:
封裝操作ElasticSearch的ElasticSearchHelper
View Codedemo中涉及的實體對象模型
/// <summary>/// ik分詞結果對象/// </summary>public class ik{public List<tokens> tokens { get; set; }}public class tokens{public string token { get; set; }public int start_offset { get; set; }public int end_offset { get; set; }public string type { get; set; }public int position { get; set; }}/// <summary>/// 測試數據對象/// </summary>public class personList{public personList(){this.list = new List<person>();}public int hits { get; set; }public int took { get; set; }public List<person> list { get; set; }}public class person{public string id { get; set; }public string name { get; set; }public int age { get; set; }public bool sex { get; set; }public DateTime birthday { get; set; }public string intro { get; set; }}詳細介紹ElasticSearchHelper里面的方法
1.索引文檔(注意:索引文檔之前先用配置filed對應的ik分詞):
public IndexResult Index(string indexName, string indexType, string id, string jsonDocument){var serializer = new JsonNetSerializer();string cmd = new IndexCommand(indexName, indexType, id);OperationResult result = Client.Put(cmd, jsonDocument);var indexResult = serializer.ToIndexResult(result.Result);return indexResult;}public IndexResult Index(string indexName, string indexType, string id, object document){var serializer = new JsonNetSerializer();var jsonDocument = serializer.Serialize(document);return Index(indexName, indexType, id, jsonDocument);}2.對單個字段的全文檢索,字段intro 包含詞組key中的任意一個單詞。例如:詞組(中國美好),只要每條數據的intro字段包含"中國"或者"美好"就返回。
public personList Search<person>(string indexName, string indexType, string key,int from ,int size){string cmd = new SearchCommand(indexName, indexType);string query = new QueryBuilder<person>()//1 查詢.Query(b =>b.Bool(m =>//并且關系m.Must(t =>//分詞的最小單位或關系查詢t.QueryString(t1=>t1.DefaultField("intro").Query(key))//.QueryString(t1 => t1.DefaultField("name").Query(key))// t .Terms(t2=>t2.Field("intro").Values("研究","方鴻漸"))//范圍查詢// .Range(r => r.Field("age").From("100").To("200") ) )))//分頁.From(from).Size(size)//排序// .Sort(c => c.Field("age", SortDirection.desc))//添加高亮.Highlight(h => h.PreTags("<b>").PostTags("</b>").Fields(f => f.FieldName("intro").Order(HighlightOrder.score),f => f.FieldName("_all"))).Build();string result = Client.Post(cmd, query);var serializer = new JsonNetSerializer();var list = serializer.ToSearchResult<Supernova.Webapi.DbHelper.person>(result);personList datalist = new personList();datalist.hits = list.hits.total;datalist.took = list.took;var personList= list.hits.hits.Select(c => new Supernova.Webapi.DbHelper.person() {id=c._source.id, age=c._source.age,birthday =c._source.birthday, intro=string.Join("",c.highlight["intro"]), //高亮顯示的內容,一條記錄中出現了幾次name=c._source.name,sex=c._source.sex,});datalist.list.AddRange(personList);return datalist;}3.字段intro 或者name 包含詞組key中的所有單詞。例如:詞組(中國美好),只要每條數據的intro或者name字段包含"中國"并且包含"美好"就返回。
public personList SearchFullFileds<person>(string indexName, string indexType, string key, int from, int size){MustQuery<person> mustNameQueryKeys = new MustQuery<person>();MustQuery<person> mustIntroQueryKeys = new MustQuery<person>();var arrKeys = GetIKTokenFromStr(key);foreach (var item in arrKeys){mustNameQueryKeys = mustNameQueryKeys.Term(t3 => t3.Field("name").Value(item)) as MustQuery<person>;mustIntroQueryKeys = mustIntroQueryKeys.Term(t3 => t3.Field("intro").Value(item)) as MustQuery<person>;}string cmd = new SearchCommand(indexName, indexType);string query = new QueryBuilder<person>()//1 查詢.Query(b =>b.Bool(m =>m.Should(t => t.Bool(m1 =>m1.Must(t2 =>//t2.Term(t3=>t3.Field("name").Value("研究"))// .Term(t3=>t3.Field("name").Value("方鴻漸")) mustNameQueryKeys))).Should(t =>t.Bool(m1 =>m1.Must(t2 => //t2.Term(t3 => t3.Field("intro").Value("研究"))//.Term(t3 => t3.Field("intro").Value("方鴻漸")) mustIntroQueryKeys)))))//分頁.From(from).Size(size)//排序// .Sort(c => c.Field("age", SortDirection.desc))//添加高亮.Highlight(h => h.PreTags("<b>").PostTags("</b>").Fields(f => f.FieldName("intro").Order(HighlightOrder.score),f => f.FieldName("name").Order(HighlightOrder.score))).Build();string result = Client.Post(cmd, query);var serializer = new JsonNetSerializer();var list = serializer.ToSearchResult<Supernova.Webapi.DbHelper.person>(result);personList datalist = new personList();datalist.hits = list.hits.total;datalist.took = list.took;var personList = list.hits.hits.Select(c => new Supernova.Webapi.DbHelper.person(){id = c._source.id,age = c._source.age,birthday = c._source.birthday,intro = c.highlight==null||!c.highlight.Keys.Contains("intro") ? c._source.intro : string.Join("", c.highlight["intro"]), //高亮顯示的內容,一條記錄中出現了幾次name = c.highlight==null||!c.highlight.Keys.Contains("name") ? c._source.name : string.Join("", c.highlight["name"]),sex = c._source.sex});datalist.list.AddRange(personList);return datalist;}3.搜索age在1到500之間,并且字段intro 或者name 包含詞組key中的所有單詞。
public personList SearchFullFiledss<person>(string indexName, string indexType, string key, int from, int size){MustQuery<person> mustNameQueryKeys = new MustQuery<person>();MustQuery<person> mustIntroQueryKeys = new MustQuery<person>();var arrKeys = GetIKTokenFromStr(key);foreach (var item in arrKeys){mustNameQueryKeys = mustNameQueryKeys.Term(t3 => t3.Field("name").Value(item)) as MustQuery<person>;mustIntroQueryKeys = mustIntroQueryKeys.Term(t3 => t3.Field("intro").Value(item)) as MustQuery<person>;}string cmd = new SearchCommand(indexName, indexType);string query = new QueryBuilder<person>()//1 查詢.Query(b =>b.Bool(m =>m.Must(t =>t.Range(r => r.Field("age").From("1").To("500")).Bool(ms =>ms.Should(ts => ts.Bool(m1 =>m1.Must(t2 =>//t2.Term(t3=>t3.Field("name").Value("研究"))// .Term(t3=>t3.Field("name").Value("方鴻漸")) //mustNameQueryKeys))).Should(ts =>ts.Bool(m1 =>m1.Must(t2 => //t2.Term(t3 => t3.Field("intro").Value("研究"))//.Term(t3 => t3.Field("intro").Value("方鴻漸")) //mustIntroQueryKeys))))) ))//分頁.From(from).Size(size)//排序// .Sort(c => c.Field("age", SortDirection.desc))//添加高亮.Highlight(h => h.PreTags("<b>").PostTags("</b>").Fields(f => f.FieldName("intro").Order(HighlightOrder.score),f => f.FieldName("name").Order(HighlightOrder.score))).Build();string result = Client.Post(cmd, query);var serializer = new JsonNetSerializer();var list = serializer.ToSearchResult<Supernova.Webapi.DbHelper.person>(result);personList datalist = new personList();datalist.hits = list.hits.total;datalist.took = list.took;var personList = list.hits.hits.Select(c => new Supernova.Webapi.DbHelper.person(){id = c._source.id,age = c._source.age,birthday = c._source.birthday,intro = c.highlight==null||!c.highlight.Keys.Contains("intro") ? c._source.intro : string.Join("", c.highlight["intro"]), //高亮顯示的內容,一條記錄中出現了幾次name = c.highlight==null||!c.highlight.Keys.Contains("name") ? c._source.name : string.Join("", c.highlight["name"]),sex = c._source.sex});datalist.list.AddRange(personList);return datalist;}需要用到的方法:將語句用ik分詞,返回分詞結果的集合
private List<string> GetIKTokenFromStr(string key){string s = "/db_test/_analyze?analyzer=ik";var result = Client.Post(s, "{"+key+"}");var serializer = new JsonNetSerializer();var list = serializer.Deserialize(result, typeof(ik)) as ik; return list.tokens.Select(c=>c.token).ToList();}ASP.NET WebApi 調用ElasticSearchHelper
1.首先我們添加一個基類ApiController
public class BaseApiController : ApiController{public MongoDatabase db;public MongoCollection col = null;//用于直接返回查詢的json public BaseApiController() { }public BaseApiController(string collectionName){db = DbHelper.MongodbHelper.Instance.DB;col = db.GetCollection(collectionName);}public string GetStringRequest(string paramter){return HttpContext.Current.Request.QueryString[paramter] ?? "";}public int? GetIntRequest(string paramter){string tmp = HttpContext.Current.Request.QueryString[paramter] ?? "";int tag = 0;if (!int.TryParse(tmp, out tag)){return null;}return tag;}}2.操作ElasticSearch的apicontroller如下:
View Code3.索引數據的api如下:
/// <summary>/// 索引數據/// </summary>/// <returns></returns>[Route("estest/index")][HttpGet]public object index(){ int length = S.test.Length;Random rd = new Random();Random rdName = new Random();ParallelOptions _po = new ParallelOptions();_po.MaxDegreeOfParallelism = 4;Parallel.For(0, 10000000, _po, c =>{var start = rd.Next(0, S.test.Length - 700);var startName = rd.Next(0, S.test.Length - 30);person p = new person() { age = DateTime.Now.Millisecond, birthday = DateTime.Now, id = Guid.NewGuid().ToString(), intro = S.test.Substring(start, 629) + c, name = S.test.Substring(startName, 29) + c, sex = true };ElasticSearchHelper.Intance.Index("db_test", "person", Guid.NewGuid().ToString(), p);});return 1;}索引使用的測試數據如下:
View Code4.搜索api如下:
[Route("estest")][HttpGet]public object Search(){//1 搜索數據string key = GetStringRequest("Key");int? from = GetIntRequest("from");int? size = GetIntRequest("size");return ElasticSearchHelper.Intance.Search<person>("db_test", "person", key ?? "方鴻漸", from == null ? 0 : from.Value, size == null ? 20 : size.Value);}[Route("estest/SearchFullFileds")][HttpGet]public object SearchFullFileds(){//1 搜索數據string key = GetStringRequest("Key");int? from = GetIntRequest("from");int? size = GetIntRequest("size"); return ElasticSearchHelper.Intance.SearchFullFileds<person>("db_test", "person", key ?? "方鴻漸", from == null ? 0 : from.Value, size == null ? 20 : size.Value);}[Route("estest/SearchFullFiledss")][HttpGet]public object SearchFullFiledss(){//1 搜索數據string key = GetStringRequest("Key");int? from = GetIntRequest("from");int? size = GetIntRequest("size"); return ElasticSearchHelper.Intance.SearchFullFiledss<person>("db_test", "person", key ?? "方鴻漸", from == null ? 0 : from.Value, size == null ? 20 : size.Value);}WebSite中的view視圖調用webapi
說明:我是直接使用ajax(jsop格式)調用webapi,返回的數據直接用knockout綁定到table中的。
視圖代碼如下:
@{ViewBag.Title = "ElasticSearch測試";Layout = null; } <link href="~/Content/bootstrap.css" rel="stylesheet" /> <script src="~/Scripts/jquery-2.1.3.min.js"></script> <script src="~/Scripts/knockout-3.3.0.js"></script> <style>b{color:red;} </style> <script>$(function () {function ViewModel() {self = this;self.getData = ko.observableArray();//定義加載數據方法self.loadData = function () {$.get("http://192.168.0.230/api/estest//SearchFullFiledss", { key: "@Request.QueryString["key"]", from: "@Request.QueryString["from"]", size: "@Request.QueryString["size"]" }, function (data) {// alert(data.hits);// alert(data.list.length);$("#count").text("符合條件的數據供:" + data.hits + " 共花費了:" + data.took + "毫秒");$.each(data.list, function (i) {var date=data.list[i].birthday;});self.getData(data.list);}, "jsonp");};//調用定義方法self.loadData();}ko.applyBindings(new ViewModel());});</script> <div id="count"></div><div class="row"><table class="table-bordered table-condensed table-hover table-striped"><tbody data-bind="foreach: getData"><tr><td data-bind="text: id" /><td data-bind="html: name" /><td data-bind="text: sex" /><td data-bind="text: age" /> <td data-bind="text: birthday" /><td data-bind="html: intro" /></tr></tbody></table> </div> <script></script>搜索結果測試如下(我是用"api/estest//SearchFullFiledss"這個api測試的,搜索age在1到500之間,并且字段intro 或者name 包含詞組key中的所有單詞。):
1.首先我們看一看測試數據總共有多少:
我們可以看到總共db_test中總共有兩千多萬條數據。
搜索測試1
測試條件:key=上海方鴻漸&from=0&size=100,key指搜索關鍵短語,0是從第0條開始區數據,100是指取一百條數據,隱藏條件是age大于1小于500
我們可以看到,首次搜索時,兩千多萬條數據大約耗時3.5秒,這里還包括取100條數據的時間,如果把數據改為20條則會更快。這里的硬件配置還只限于我的本機測試(內存8G,處理器Intel i5-4590 3.3GHZ)。
搜索測試2
測試條件同測試1:key=上海方鴻漸&from=0&size=100,key指搜索關鍵短語,0是從第0條開始區數據,100是指取一百條數據,隱藏條件是age大于1小于500
我們可以看到,搜索耗時降到了大約1.5秒。這說明同一個關鍵詞搜索越頻繁,搜索速度越快,這是因為ElasticSearch會自動將搜索的內容緩存到內存中。
搜索測試3
測試條件:key=香煙德國&from=0&size=20,key指搜索關鍵短語,0是從第0條開始區數據,20是指取一百條數據,隱藏條件是age大于1小于500
搜索測試4
測試條件同測試3,二次相同條件搜索:key=香煙德國&from=0&size=20,key指搜索關鍵短語,0是從第0條開始區數據,20是指取一百條數據,隱藏條件是age大于1小于500
我們可以看到,在二次搜索條件相同,搜索數據降低到20條的時候,只耗時不到0.5秒。
本章完……
ElasticSearch系列學習?
ElasticSearch第一步-環境配置
ElasticSearch第二步-CRUD之Sense?
ElasticSearch第三步-中文分詞
ElasticSearch第四步-查詢詳解
ElasticSearch第五步-.net平臺下c#操作ElasticSearch詳解
http://www.cnblogs.com/eggTwo/p/4425269.html
總結
以上是生活随笔為你收集整理的ElasticSearch-.net平台下c#操作ElasticSearch详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 莱荣高铁文登南站在什么位置
- 下一篇: 除非另外还指定了 TOP 或 FOR X