Elasticsearch簡介
Elasticsearch (ES)是一個基於Apache Lucene(TM)的開源搜索引擎,無論在開源還是專有領域,Lucene可以被認為是迄今為止最先進、性能最好的、功能最全的搜索引擎庫。
但是,Lucene只是一個庫。想要發揮其強大的作用,你需使用C#將其集成到你的應用中。Lucene非常復雜,你需要深入的了解檢索相關知識來理解它是如何工作的。
Elasticsearch是使用Java編寫並使用Lucene來建立索引並實現搜索功能,但是它的目的是通過簡單連貫的RESTful API讓全文搜索變得簡單並隱藏Lucene的復雜性。
不過,Elasticsearch不僅僅是Lucene和全文搜索引擎,它還提供:
而且,所有的這些功能被集成到一台服務器,你的應用可以通過簡單的RESTful API、各種語言的客戶端甚至命令行與之交互。上手Elasticsearch非常簡單,它提供了許多合理的缺省值,並對初學者隱藏了復雜的搜索引擎理論。它開箱即用(安裝即可使用),只需很少的學習既可在生產環境中使用。Elasticsearch在Apache 2 license下許可使用,可以免費下載、使用和修改。
隨著知識的積累,你可以根據不同的問題領域定制Elasticsearch的高級特性,這一切都是可配置的,並且配置非常靈活。
以上內容來自 [百度百科]
關於ES詳細概念見:http://88250.b3log.org/full-text-search-elasticsearch#b3_solo_h3_0
使用C#操作ES
NEST是一個高層的客戶端,可以映射所有請求和響應對象,擁有一個強類型查詢DSL(領域特定語言),並且可以使用.net的特性比如協變、Auto Mapping Of POCOs,NEST內部使用的依然是Elasticsearch.Net客戶端。elasticsearch.net(NEST)客戶端提供了強類型查詢DSL,方便用戶使用,源碼下載。
打開VS的工具菜單,通過NuGet包管理器控制台,輸入以下命令安裝NEST
Install-Package NEST
安裝後引用了以下三個DLL
Elasticsearch.Net.dll(2.4.4) Nest.dll(2.4.4) Newtonsoft.Json.dll(9.0版本)
你可以通過單個節點或者指定多個節點使用連接池鏈接到Elasticsearch集群,使用連接池要比單個節點鏈接到Elasticsearch更有優勢,比如支持負載均衡、故障轉移等。
通過單點鏈接:
1 var node = new Uri("http://myserver:9200"); 2 var settings = new ConnectionSettings(node); 3 var client = new ElasticClient(settings);
通過連接池鏈接:
1 var nodes = new Uri[] 2 { 3 new Uri("http://myserver1:9200"), 4 new Uri("http://myserver2:9200"), 5 new Uri("http://myserver3:9200") 6 }; 7 8 var pool = new StaticConnectionPool(nodes); 9 var settings = new ConnectionSettings(pool); 10 var client = new ElasticClient(settings);
為了知道請求需要操作哪個索引,Elasticsearch API期望收到一個或多個索引名稱作為請求的一部分。
1、可以通過ConnectionSettings使用.DefaultIndex(),來指定默認索引。當一個請求裡沒有指定具體索引時,NEST將請求默認索引。
1 var settings = new ConnectionSettings() 2 .DefaultIndex("defaultindex");
2、可以通過ConnectionSettings使用.MapDefaultTypeIndices(),來指定被映射為CLR類型的索引。
1 var settings = new ConnectionSettings() 2 .MapDefaultTypeIndices(m => m 3 .Add(typeof(Project), "projects") 4 );
注意:通過.MapDefaultTypeIndices()指定索引的優先級要高於通過.DefaultIndex()指定索引,並且更適合簡單對象(POCO)
3、另外還可以顯示的為請求指定索引名稱,例如:
1 var response = client.Index(student, s=>s.Index("db_test")); 2 var result = client.Search<Student>(s => s.Index("db_test")); 3 var result = client.Delete<Student>(null, s => s.Index("db_test")); 4 ……
注意:當現實的為請求指定索引名稱時,這個優先級是最高的,高於以上兩種方式指定的索引。
4、一些Elasticsearch API(比如query)可以采用一個、多個索引名稱或者使用_all特殊標志發送請求,請求NEST上的多個或者所有節點
1 //請求單一節點 2 var singleString = Nest.Indices.Index("db_studnet"); 3 var singleTyped = Nest.Indices.Index<Student>(); 4 5 ISearchRequest singleStringRequest = new SearchDescriptor<Student>().Index(singleString); 6 ISearchRequest singleTypedRequest = new SearchDescriptor<Student>().Index(singleTyped); 7 8 //請求多個節點 9 var manyStrings = Nest.Indices.Index("db_studnet", "db_other_student"); 10 var manyTypes = Nest.Indices.Index<Student>().And<OtherStudent>(); 11 12 ISearchRequest manyStringRequest = new SearchDescriptor<Student>().Index(manyStrings); 13 ISearchRequest manyTypedRequest = new SearchDescriptor<Student>().Index(manyTypes); 14 15 //請求所有節點 16 var indicesAll = Nest.Indices.All; 17 var allIndices = Nest.Indices.AllIndices; 18 19 ISearchRequest indicesAllRequest = new SearchDescriptor<Student>().Index(indicesAll); 20 ISearchRequest allIndicesRequest = new SearchDescriptor<Student>().Index(allIndices);
Elasticsearch API允許你創建索引的同時對索引進行配置,例如:
1 var descriptor = new CreateIndexDescriptor("db_student") 2 .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1)); 3 4 client.CreateIndex(descriptor);
這裡指定了該索引的分片數為5、副本數為1。
Elasticsearch API允許你刪除索引,例如:
1 var descriptor = new DeleteIndexDescriptor("db_student").Index("db_student"); 2 3 client.DeleteIndex(descriptor)
這裡制定了要刪除的索引名稱“db_student”,以下為更多刪除用例:
1 //刪除指定索引所在節點下的所有索引 2 var descriptor = new DeleteIndexDescriptor("db_student").AllIndices();
NEST提供了多種映射方法,這裡介紹下通過Attribute自定義映射。
1、定義業務需要的POCO,並指定需要的Attribute
1 [ElasticsearchType(Name = "student")] 2 public class Student 3 { 4 [Nest.String(Index = FieldIndexOption.NotAnalyzed)] 5 public string Id { get; set; } 6 7 [Nest.String(Analyzer = "standard")] 8 public string Name { get; set; } 9 10 [Nest.String(Analyzer = "standard")] 11 public string Description { get; set; } 12 13 public DateTime DateTime { get; set; } 14 }
2、接著我們通過.AutoMap()來實現映射
1 var descriptor = new CreateIndexDescriptor("db_student") 2 .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1)) 3 .Mappings(ms => ms 4 .Map<Student>(m => m.AutoMap()) 5 ); 6 7 client.CreateIndex(descriptor);
注意:通過.Properties()可以重寫通過Attribute定義的映射
1、StringAttribute
2、NumberAttribute
3、BooleanAttribute
4、DateAttribute
5、ObjectAttribute
NEST提供了支持Lambda鏈式query DLS(領域特定語言)方式,以下是簡單實現及各個query的簡述。
1、定義SearchDescriptor,方便項目中復雜業務的實現
1 var query = new Nest.SearchDescriptor<Models.ESObject>(); 2 3 var result = client.Search<Student>(x => query)
2、檢索title和content中包含key,並且作者不等於“俏佳人”的文檔
1 query.Query(q => 2 q.Bool(b => 3 b.Must(m => 4 m.MultiMatch(t => t.Fields(f => f.Field(obj => obj.Title).Field(obj => obj.Content)).Query(key)) 5 ) 6 .MustNot(m => 7 m.QueryString(t => t.Fields(f => f.Field(obj => obj.Author)).Query("wenli")) 8 ) 9 ) 10 );
注意:
如果Elasticsearch使用默認分詞,Title和Content的attribute為[Nest.String(Analyzer = "standard")]
如果Elasticsearch使用的是IK分詞,Title和Content的attribute為[Nest.String(Analyzer = "ikmaxword")]或者[Nest.String(Analyzer = "ik_smart")]
Author的attribute為[Nest.String(Index = FieldIndexOption.NotAnalyzed)],禁止使用分析器
3、過濾作者等於“歷史小河”的文檔
query.PostFilter(x => x.Term(t => t.Field(obj => obj.Author).Value("wenli")));
4、過濾作者等於“歷史小河”或者等於“友誼的小船”的文檔,匹配多個作者中間用空格隔開
1 query.PostFilter(x => x.QueryString(t => t.Fields(f => f.Field(obj => obj.Author)).Query("wenli yswenli")));
5、過濾數量在1~100之間的文檔
1 query.PostFilter(x => x.Range(t => t.Field(obj => obj.Number).GreaterThanOrEquals(1).LessThanOrEquals(100)));
6、排序,按照得分倒敘排列
1 query.Sort(x => x.Field("_score", Nest.SortOrder.Descending));
7、定義高亮樣式及字段
1 query.Highlight(h => h 2 .PreTags("<b>") 3 .PostTags("</b>") 4 .Fields( 5 f => f.Field(obj => obj.Title), 6 f => f.Field(obj => obj.Content), 7 f => f.Field("_all") 8 ) 9 );
8、拼裝查詢內容,整理數據,方便前段調用
1 var list = result.Hits.Select(c => new Models.ESObject() 2 { 3 Id = c.Source.Id, 4 Title = c.Highlights == null ? c.Source.Title : c.Highlights.Keys.Contains("title") ? string.Join("", c.Highlights["title"].Highlights) : c.Source.Title, //高亮顯示的內容,一條記錄中出現了幾次 5 Content = c.Highlights == null ? c.Source.Content : c.Highlights.Keys.Contains("content") ? string.Join("", c.Highlights["content"].Highlights) : c.Source.Content, //高亮顯示的內容,一條記錄中出現了幾次 6 Author = c.Source.Author, 7 Number = c.Source.Number, 8 IsDisplay = c.Source.IsDisplay, 9 Tags = c.Source.Tags, 10 Comments = c.Source.Comments, 11 DateTime = c.Source.DateTime, 12 })
待整理……
文檔操作包含添加/更新文檔、局部更新文檔、刪除文檔及對應的批量操作文檔方法。
添加/更新單一文檔
1 Client.Index(student);
批量添加/更新文檔
1 var list = new List<Student>(); 2 3 client.IndexMany<Student>(list);
局部更新單一文檔
1 client.Update<Student, object>("002", upt => upt.Doc(new { Name = "wenli" }));
局部更新批量文檔
var ids = new List<string>() { "002" }; var bulkQuest = new BulkRequest() { Operations = new List<IBulkOperation>() }; foreach (var v in ids) { var operation = new BulkUpdateOperation<Student, object>(v); operation.Doc = new { Name = "wenli" }; bulkQuest.Operations.Add(operation); } var result = client.Bulk(bulkQuest);
刪除單一文檔
1 client.Delete<Student>("001");
批量刪除文檔
1 var ids = new List<string>() { "001", "002" }; 2 3 var bulkQuest = new BulkRequest() { Operations = new List<IBulkOperation>() }; 4 5 foreach (var v in ids) 6 { 7 bulkQuest.Operations.Add(new BulkDeleteOperation<Student>(v)); 8 } 9 10 var result = client.Bulk(bulkQuest);
轉載請標明本文來源:http://www.cnblogs.com/yswenli/
更多內容歡迎我的的github:https://github.com/yswenli
如果發現本文有什麼問題和任何建議,也隨時歡迎交流~