[料理佳餚] C# NEST 操作 Elasticsearch 搜尋服務(建立連線、索引資料)

Elasticsearch 架設起來之後雖然已經有 RESTFUL Api 可以使用,GUI 方面也有像 kopf 之類的 Plugin 可以用,但是要寫程式來操作它除了自己接 RESTFUL Api 之外,其實我們還有其它套件可以選擇,像是連 Stack Overflow 都使用的 NEST

elastic 團隊開發了 2 個 Elasticsearch .NET 的套件,一個是 Elasticsearch.Net,一個是 NEST,而兩者的差異只在於 NEST 是 Elasticsearch.Net 的 Wrapper,NEST 還是 base on Elasticsearch.Net,只是 NEST 提供比較友善的使用方式,讓我們在 Coding 的時候踩的雷比較少,如果我們需要比較進階的操作是 NEST 沒有提供的,我們還是可以使用 Elasticsearch.Net。

建立連線

建立連線有 2 種方式:

1. 連線到單一伺服器。

private ElasticClient ConnectToSingleNode()
{
    // 產生單一伺服器的連線設定,指定伺服器群及預設的 index 名稱。
    var connectionSetting = new ConnectionSettings(new Uri(@"http://elasticsearch01:9200"), "myindex0");

    // 建立 Elasticsearch Client,請重覆使用。
    return new ElasticClient(connectionSetting);
}

2. 建立伺服器群,讓 NEST 自己選擇連線到運作正常的伺服器。

private ElasticClient ConnectToConnectionPool()
{
    // 建立伺服器群
    var elasticNodes = new SniffingConnectionPool(new Uri[] { new Uri(@"http://elasticsearch01:9200"), new Uri(@"http://elasticsearch02:9200"), new Uri(@"http://elasticsearch03:9200") });

    // 產生連線設定,指定伺服器群及預設的 index 名稱。
    var connectionSetting = new ConnectionSettings(elasticNodes, "myindex0");

    // 建立 Elasticsearch Client,請重覆使用。
    return new ElasticClient(connectionSetting);
}

索引單筆 document

要索引一筆 document 其實很容易。

private void IndexDocument()
{
    // 假設有一個 TextItem 的 object
    TextItem textItem = new TextItem()
    {
        Id = Guid.NewGuid(),
        Summary = "I'm summary.",
        Content = "I'm content.",
        AuthorId = "99999",
        AuthorName = "Dotblogs",
        CreatedTime = DateTime.Now,
        ModifiedTime = DateTime.Now
    };

    // 直接呼叫 Index 將 object 給入即可。
    // 官網建議自行指定 document Id,不指定的話預設 Elasticsearch 會自己給。
    // type 如果不指定,預設就是類別名稱。
    this.myindexClient.Index(textItem, indexDescriptor => indexDescriptor.Id(textItem.Id.ToString()));
}
IndexDescriptor 是用來改變我們在索引資料時的參數,我們可藉由 Index 方法的多載給入 Func<IndexDescriptor<T>, IndexDescriptor<T>>,像上述的例子我們自行將 object 的 Id 指定為 document 的 Id,其他像 index、type 都可以自行指定。

索引多筆 document

要索引多筆 document 我們要用另一個方法 Bulk。

private void IndexMultipleDocuments()
{
    // 假設我產生了多個 TextItem
    List<TextItem> textItems = CreateTextItems();

    // 呼叫 Bulk 方法,給入一個 BulkRequest object,指定 BulkRequest.Operations 為 List<IBulkOperation<TextItem>>。
    this.myindexClient.Bulk(new BulkRequest()
    {
        Operations = textItems.Select(t => new BulkIndexOperation<TextItem>(t) { Id = t.Id.ToString() } as IBulkOperation).ToList()
    });
}
要索引多筆資料我們可以跑迴圈一筆一筆用 Index 方法處理當然也是沒問題的,不過這對於 Elasticsearch 來講是不一樣的,跑迴圈用 Index 方法是「你一筆一筆來我一筆一筆做」,而用 Bulk 方法一次丟則是「你全部一起來我全部一起做」,在效率上用 Bulk 一次索引多筆資料絕對是佔上風的

參考資料

 < Source Code >

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學