C# 如何使用 Elasticsearch (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,方便用戶使用,源碼下載。(https://github.com/elastic/elasticsearch-net/releases/tag/2.4.4)

 

一、如何安裝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更有優勢,比如支持負載均衡、故障轉移等。

 

通過單點鏈接:

 

var node = new Uri("http://myserver:9200");

var settings = new ConnectionSettings(node);

var client = new ElasticClient(settings);

 

通過連接池鏈接:

 

var nodes = new Uri[]

{

    new Uri("http://myserver1:9200"),

    new Uri("http://myserver2:9200"),

    new Uri("http://myserver3:9200")

};

var pool = new StaticConnectionPool(nodes);

var settings = new ConnectionSettings(pool);

var client = new ElasticClient(settings);

 

NEST Index

 

為了知道請求需要操作哪個索引,Elasticsearch API期望收到一個或多個索引名稱作為請求的一部分。

 

一、指定索引

 

1、可以通過ConnectionSettings使用.DefaultIndex(),來指定默認索引。當一個請求里沒有指定具體索引時,NEST將請求默認索引。

 

var settings = new ConnectionSettings()

    .DefaultIndex("defaultindex");

 

2、可以通過ConnectionSettings使用.MapDefaultTypeIndices(),來指定被映射為CLR類型的索引。

 

var settings = new ConnectionSettings()

    .MapDefaultTypeIndices(m => m

        .Add(typeof(Project), "projects")

    );

 

注意:通過.MapDefaultTypeIndices()指定索引的優先級要高於通過.DefaultIndex()指定索引,並且更適合簡單對象(POCO)

 

3、另外還可以顯示的為請求指定索引名稱,例如:

 

var response = client.Index(student, s=>s.Index("db_test"));

var result = client.Search<Student>(s => s.Index("db_test"));

var result = client.Delete<Student>(null, s => s.Index("db_test"));

……

 

注意:當現實的為請求指定索引名稱時,這個優先級是最高的,高於以上兩種方式指定的索引。

 

4、一些Elasticsearch API(比如query)可以采用一個、多個索引名稱或者使用_all特殊標志發送請求,請求NEST上的多個或者所有節點

 

//請求單一節點

var singleString = Nest.Indices.Index("db_studnet");

var singleTyped = Nest.Indices.Index<Student>();

 

ISearchRequest singleStringRequest = new SearchDescriptor<Student>().Index(singleString);

ISearchRequest singleTypedRequest = new SearchDescriptor<Student>().Index(singleTyped);

 

//請求多個節點

var manyStrings = Nest.Indices.Index("db_studnet", "db_other_student");

var manyTypes = Nest.Indices.Index<Student>().And<OtherStudent>();

 

ISearchRequest manyStringRequest = new SearchDescriptor<Student>().Index(manyStrings);

ISearchRequest manyTypedRequest = new SearchDescriptor<Student>().Index(manyTypes);

 

//請求所有節點

var indicesAll = Nest.Indices.All;

var allIndices = Nest.Indices.AllIndices;

 

ISearchRequest indicesAllRequest = new SearchDescriptor<Student>().Index(indicesAll);

ISearchRequest allIndicesRequest = new SearchDescriptor<Student>().Index(allIndices);

 

二、創建索引

 

Elasticsearch API允許你創建索引的同時對索引進行配置,例如:

 

var descriptor = new CreateIndexDescriptor("db_student")

    .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1));

client.CreateIndex(descriptor);

 

這里指定了該索引的分片數為5、副本數為1。

 

三、刪除索引

 

Elasticsearch API允許你刪除索引,例如:

 

var descriptor = new DeleteIndexDescriptor("db_student").Index("db_student");

client.DeleteIndex(descriptor)

 

這里制定了要刪除的索引名稱“db_student”,以下為更多刪除用例:

 

 //刪除指定索引所在節點下的所有索引

 var descriptor = new DeleteIndexDescriptor("db_student").AllIndices();

 

NEST Mapping

 

NEST提供了多種映射方法,這里介紹下通過Attribute自定義映射。

 

一、簡單實現

 

1、定義業務需要的POCO,並指定需要的Attribute

 

[ElasticsearchType(Name = "student")]

public class Student

{

    [Nest.String(Index = FieldIndexOption.NotAnalyzed)]

    public string Id { get; set; }

    [Nest.String(Analyzer = "standard")]

    public string Name { get; set; }

    [Nest.String(Analyzer = "standard")]

    public string Description { get; set; }

    public DateTime DateTime { get; set; }

}

 

2、接着我們通過.AutoMap()來實現映射

 

var descriptor = new CreateIndexDescriptor("db_student")

    .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1))

    .Mappings(ms => ms

        .Map<Student>(m => m.AutoMap())

    );

client.CreateIndex(descriptor);

 

注意:通過.Properties()可以重寫通過Attribute定義的映射

 

二、Attribute介紹

 

1、StringAttribute

 

 

2、NumberAttribute

 

 

3、BooleanAttribute

 

屬性名 值類型 描述
Boost double 加權值,值越大得分越高
NullValue double 插入文檔時,如果數據為NULL時的默認值

 

4、DateAttribute

 

屬性名 值類型 描述
Boost double 加權值,值越大得分越高
NullValue string 插入文檔時,如果數據為NULL時的默認值
Format string  

 

5、ObjectAttribute

 

屬性名 值類型 描述
type string/Type 構造函數參數,指定當前屬性的類型T
Dynamic DynamicMapping  

 

NEST Search

 

NEST提供了支持Lambda鏈式query DLS(領域特定語言)方式,以下是簡單實現及各個query的簡述。

 

一、簡單實現

 

1、定義SearchDescriptor,方便項目中復雜業務的實現

 

var query = new Nest.SearchDescriptor<Models.ESObject>();

var result = client.Search<Student>(x => query)

 

2、檢索title和content中包含key,並且作者不等於“wenli”的文檔

 

query.Query(q =>

    q.Bool(b =>

        b.Must(m =>

            m.MultiMatch(t => t.Fields(f => f.Field(obj => obj.Title).Field(obj => obj.Content)).Query(key))

        )

        .MustNot(m =>

            m.QueryString(t => t.Fields(f => f.Field(obj => obj.Author)).Query("wenli"))

        )

    )

);

 

注意:

 

如果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”的文檔,匹配多個作者中間用空格隔開

 

query.PostFilter(x => x.QueryString(t => t.Fields(f => f.Field(obj => obj.Author)).Query("wenli yswenli")));

 

5、過濾數量在1~100之間的文檔

 

query.PostFilter(x => x.Range(t => t.Field(obj => obj.Number).GreaterThanOrEquals(1).LessThanOrEquals(100)));

 

6、排序,按照得分倒敘排列

 

query.Sort(x => x.Field("_score", Nest.SortOrder.Descending));

 

7、定義高亮樣式及字段

 

query.Highlight(h => h

    .PreTags("<b>")

    .PostTags("</b>")

    .Fields(

        f => f.Field(obj => obj.Title),

        f => f.Field(obj => obj.Content),

        f => f.Field("_all")

    )

);

 

8、拼裝查詢內容,整理數據,方便前段調用

 

var list = result.Hits.Select(c => new Models.ESObject()

{

    Id = c.Source.Id,

    Title = c.Highlights == null ? c.Source.Title : c.Highlights.Keys.Contains("title") ? string.Join("", c.Highlights["title"].Highlights) : c.Source.Title, //高亮顯示的內容,一條記錄中出現了幾次

    Content = c.Highlights == null ? c.Source.Content : c.Highlights.Keys.Contains("content") ? string.Join("", c.Highlights["content"].Highlights) : c.Source.Content, //高亮顯示的內容,一條記錄中出現了幾次

    Author = c.Source.Author,

    Number = c.Source.Number,

    IsDisplay = c.Source.IsDisplay,

    Tags = c.Source.Tags,

    Comments = c.Source.Comments,

    DateTime = c.Source.DateTime,

})

 

二、query DSL介紹 

 

elasticsearch.net Document

 

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

 

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

 

添加/更新單一文檔

 

Client.Index(student);

 

批量添加/更新文檔

 

var list = new List<Student>();

client.IndexMany<Student>(list);

 

二、局部更新單一文檔及批量操作

 

局部更新單一文檔

 

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

 

三、刪除文檔及批量操作

 

刪除單一文檔

 

client.Delete<Student>("001");

 

批量刪除文檔

 

var ids = new List<string>() { "001", "002" };

var bulkQuest = new BulkRequest() { Operations = new List<IBulkOperation>() };

foreach (var v in ids)

{

    bulkQuest.Operations.Add(new BulkDeleteOperation<Student>(v));

}

var result = client.Bulk(bulkQuest);

 

轉至: cnblogs.com/yswenli/p/6266569.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM