.Net Core中使用ElasticSearch(二)

語言: CN / TW / HK

.Net的ElasticSearch 有兩個版本, Elasticsearch.Net (低階) 和  NEST (高階),推薦使用 NEST,低階版本的更靈活,水太深 把握不住。有個需要注意,使用的版本號必須要ElasticSearch服務端版本號一致。

一、 連線池

1.1 SingleNodeConnectionPool 單節點連線池

適合只有一個節點的情況。當沒有在ConnectionSettings 建構函式中顯式指定連線池型別的時候,預設此連線池。這種連線池不會標記節點是否存活

1.2 StaticConnectionPool 靜態連線池

適合多個節點,它維護一個靜態的節點hosts清單,使用前通過ping節點來確認節點是否存活。如果一個節點處理請求失敗,該節點會被標記為死節點,這個節點會被“關禁閉”,“關禁閉”出來後,會再次處理請求,如果還是失敗,“關禁閉”的時間會更長。

1.3 SniffingConnectionPool 嗅探連線池

它繼承至靜態連線池,有靜態連線池的Ping特性。區別在於是動態的,使用者提供hosts種子,而客戶端則會嗅探這些hosts並發現叢集的其他節點。當叢集中新增或刪除節點時,客戶端會相應更新。

1.4 StickyConnectionPool 黏性連線池

選擇一個可用節點作為請求主節點,支援ping 不支援嗅探

1.5 StickySniffingConnectionPool 黏性嗅探連線池

選擇一個可用節點作為請求主節點,支援ping 支援嗅探

二、注入

官方推薦使用單例注入ElasticClient。

            services.AddSingleton<IElasticClient>(provider =>
            {
                var connectionPool = new SingleNodeConnectionPool(new Uri("http://127.0.0.1:9200"));
                var connectionSetting = new ConnectionSettings(connectionPool).DisableDirectStreaming();
                return new ElasticClient(connectionSetting);
            });              

三、增刪改查

3.1 新增

3.1.1 單個新增

var user = new User()
{
    Id = 1,
    Age = 18,
    Name = "MicroHeart",
    Gender = true
};
//第一種
var resp = client.Index(user, s => s.Index(indexName));//指定操作索引名稱
//第二種
connectionSettings.DefaultIndex(indexName);//指定預設索引名稱
var client = new ElasticClient(connectionSettings);
resp = client.IndexDocument(user);//操作預設索引

3.1.2 批量新增

//第一種
var resp = client.IndexMany(new List<User>() { user }); //操作預設索引
resp = client.IndexMany(new List<User>() { user }, indexName); //操作指定索引
//第二種
resp = client.Bulk(b => b.Index(indexName).IndexMany(users, (desc, user) => desc.Index(user.Gender ? "boy" : "girl")));
//第三種
var bulkAllObservable = client.BulkAll(users, b => b
                            .Index("people")
                            .BackOffTime("30s") //重試間隔時間
                            .BackOffRetries(2)  //重試次數
                            .RefreshOnCompleted()
                            .MaxDegreeOfParallelism(Environment.ProcessorCount)
                            .Size(1000) //每次請求文件個數
                        );

IndexMany:是在單個 HTTP 請求所有文件,因此對於非常大的文件集合,這不是建議的方法。

Bulk:是在單個 HTTP 請求所有文件,如果需要對很多文件進行索引控制,可以使用此方法。例子中將男孩插入“boy”索引中,女孩新增到“girl”索引中

BulkAll:適合對多個大文件集合操作,在多個HTTP請求中,分批次操作文件,內建了重試機制。

上面所有的插入方法都是根據_id的值判斷文件是否存在(這裡因為user有個屬性為Id,預設Es將Id的屬性值作為_id的值),如果已經存在文件,就更新,否則就新增。

通過返回物件的IsValid屬性來判斷是否新增成功。

3.2 刪除

var resp = client.Delete<User>(1, d => d.Index(indexName));//單個刪除
var resp = client.DeleteByQuery<User>(x => x.Index(indexName).Query(q => q.Range(r => r.Field(f => f.Age).LessThan(18)))); //刪除年齡小於18的

返回的物件包含

deleted:表示刪除的數量。 

Failures:刪除失敗的集合。

3.3 查詢

3.3.1 根據Id獲取單個

var resp = client.Get<User>(3, d => d.Index(indexName));

返回的型別為 GetResponse<User>,包含下面幾個屬性。

index:表示索引,

type:值固定為“_doc”,

found:表示是否找到文件,

version:文件的版本號,

source:儲存的資料user

3.3.2 根據Id集合獲取多個

 var resp = client.GetMany<User>(new List<long>() { 19L, 20L, 21L }, indexName);

3.3.3 根據條件查詢

var resp = client.Search<User>(x => x.Index(indexName)
                                     .From(0)
                                     .Size(20)
                                     .Query(q => q.Range(r => r.Field(f => f.Age).GreaterThan(18)) &&
                                                 q.Range(r => r.Field(f => f.Age).LessThan(30)) &&
                                                 q.Term(t => t.Gender, true)));

返回的型別為 ISearchResponse<User>,包含下面幾個屬性。

TimedOut:查詢是否超時

Shards:完成這個搜尋查詢了多少個分片

Took:此次查詢消耗的時間

MaxScore:此次查詢中最符合查詢條件的文件的最大得分

Total:符合查詢條件的總數

Hits:儲存的資料user集合

例子只是簡單的查詢。ES專為查詢而生,所以它的查詢很靈活,後面單獨講。

3.4 更新

var user = new User()
{
    Age = 18,
    Gender = false,
    Name = "test"
};
var resp4 = client.Update<User>(20, u => u.Index(indexName).Doc(user));

返回的IsValid 表示是否更新成功。

封裝裝一個操作倉儲, 連結