天天看點

C#如何使用ES

Elasticsearch簡介 Elasticsearch (ES)

是一個基于Apache Lucene(TM)的開源搜尋引擎,無論在開源還是專有領域,Lucene可以被認為是迄今為止最先進、性能最好的、功能最全的搜尋引擎庫。 

但是,Lucene隻是一個庫。想要發揮其強大的作用,你需使用C#将其內建到你的應用中。Lucene非常複雜,你需要深入的了解檢索相關知識來了解它是如何工作的。 

Elasticsearch是使用Java編寫并使用Lucene來建立索引并實作搜尋功能,但是它的目的是通過簡單連貫的RESTful API讓全文搜尋變得簡單并隐藏Lucene的複雜性。 

不過,Elasticsearch不僅僅是Lucene和全文搜尋引擎,它還提供:

  • 分布式的實時檔案存儲,每個字段都被索引并可被搜尋
  • 實時分析的分布式搜尋引擎
  • 可以擴充到上百台伺服器,處理PB級結構化或非結構化資料

而且,所有的這些功能被內建到一台伺服器,你的應用可以通過簡單的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,友善使用者使用,

源碼下載下傳

一、如何安裝NEST

打開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叢集,使用連接配接池要比單個節點連結到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);      

 NEST Index

為了知道請求需要操作哪個索引,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 Mapping

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定義的映射

二、Attribute介紹

1、StringAttribute

屬性名 值類型 描述
Analyzer string 分析器名稱,值包含standard、simple、whitespace、stop、keyward、pattern、language、snowball、custom等,檢視分析器更多資訊請點選 Elasticsearch Analyzers
Boost double 權重值,值越大得分越高
NullValue 插入文檔時,如果資料為NULL時的預設值
Index FieldIndexOption 是否使用分析器,預設使用FieldIndexOption.Analyzed,禁止使用分析器FieldIndexOption.NotAnalyzed

2、NumberAttribute

type NumberType 構造函數參數,指定目前屬性的類型,NumberType.Default、Float、Double、Integer、Long、Short、Byte

3、BooleanAttribute

4、DateAttribute

Format

5、ObjectAttribute

string/Type 構造函數參數,指定目前屬性的類型T
Dynamic DynamicMapping

 NEST Search

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,并且作者不等于“wenli”的文檔

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、過濾作者等于“wenli”的文檔

query.PostFilter(x => x.Term(t => t.Field(obj => obj.Author).Value("wenli")));      

4、過濾作者等于“wenli”或者等于“yswenli”的文檔,比對多個作者中間用空格隔開

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 })      

二、query DSL介紹 

 elasticsearch.net Document

文檔操作包含添加/更新文檔、局部更新文檔、删除文檔及對應的批量操作文檔方法。

一、添加/更新文檔及批量操作

添加/更新單一文檔

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 如果發現本文有什麼問題和任何建議,也随時歡迎交流~

感謝您的閱讀,如果您對我的部落格所講述的内容有興趣,請繼續關注我的後續部落格,我是yswenli 。