ElasticSearch NEST筆記 html
1. 什麼是ElasticSearch?java
ElasticSearch is a powerful open source search and analytics engine that makes data easy to explore. node
能夠簡單理解成索引加檢索的工具,固然它功能多於此。
ElasticSearch分爲服務端與客戶端,服務端提供REST API,客戶端使用REST API。 git
2.怎麼安裝Elastic? github
文檔中有詳細說明 web
完成後,在以下圖的地方找到一個html json
3. 如何使用NEST客戶端(文檔:http://nest.azurewebsites.net/nest/quick-start.html) 瀏覽器
上面這句代碼是能夠不用寫的,由於在調用下面的index方法的時候,若是沒有指定使用哪一個index,ElasticSearch會直接使用咱們在setting中的defaultIndex,若是沒有,則會自動建立。 oracle
可是如何你須要使用Mapping來調整索引結構,就會須要CreateIndex這個方法。具體的會在下面的Mapping中提到 app
正常來講,搜索的需求通常是咱們傳入一個keyword(和須要搜索的field name),返回符合條件的列表,那麼搜索就分爲全文搜索和單屬性搜索。顧名思義,全文搜索就是用keyword去匹配全部的屬性,單屬性搜索就是隻匹配指定的屬性。
另外因爲ES是分詞搜索,因此當咱們要用"One"來搜索完整的單詞"JustOne"的時候,就必須在"One"外面添加**,相似於SQL裏面的%keyword%,可是這樣的作法會致使在用完整的單詞來搜索的時候搜索不到結果,因此咱們須要使用下面的方式(若是有更好的方法請不吝賜教):
指定屬性的搜索有兩種:
Term是一個被索引的精確值,也就是說Foo, foo, FOO是不相等的,所以
在使用term query的時候要注意,term query在搜索的Field已經被索引的時候,是不支持大寫的。下面爲elasticSearch - header測試
全部數據:
大寫搜索:
小寫搜索:
NEST的使用:
或者(效果同樣):
PS:term query的Field是必須的,若是Field爲空,會產生下面的錯誤
QueryString query通常用於全文搜索,可是也能夠用於單個屬性的搜索(設置DefaultField屬性),queryString query能夠不區分大小寫。QueryString還有一個好處就是咱們能夠搜索一個term中的一部分,例如lastname爲"t Boterhuis 1",那麼咱們能夠用"terhuis"搜索到這個數據(雖然須要在外面包上**),在term query裏面就作不到,由於ES把每個屬性的值都分析成一個個單獨的term,提升了搜索的效率。
下面爲elasticSearch - header測試:
完整term搜索(大寫):
完整term搜索(小寫):
部分搜索(大寫,不帶**):
部分搜索(大寫,帶**):
部分搜索(小寫,帶**):
多詞語搜索:當咱們想搜索相似於:"t Boterhuis 2"這樣的多個單詞構成的keyword(用空格分開),term query是沒法查詢的,term query顧名思義就是單詞查詢。不能支持多單詞查詢
QueryString query:
你們能夠看到,第三條也被搜索進來了,這是由於ES把"t Boterhuis 2"解析成了三個詞彙"t"" Boterhuis""2"。而後分開搜索,把結果集合並,因此ID爲4的記錄也被搜索出來了。那麼咱們如何讓合起來搜索呢?
QueryString query有一個DefaultOperator的屬性,咱們能夠將其設置爲And,這樣搜索的時候,ES會將幾個term的search結果作and運算。
可是有一個比較大的問題是若是個人keyword是"Aberdeen Boterhuis",
這樣也能夠搜索出結果來:
咱們搜索出了ID爲7的數據,由於這條數據firstname裏面有Aberdeen ,last name裏面有Boterhuis。
目前尚未找到比較好的方法來解決這個問題,若是各位有好的方法請不吝賜教。
搜索須要咱們從新構建索引,這樣才能發現錯誤而且解決他們。
首先咱們把原先的索引先刪除了
而後從新建立索引
Person的類:
好了,讓咱們來測試下排序~
1).ID排序
正常!
.Index("zhixiao-application")
.Sort(sort => sort.OnField(f => f.Id).Order(SortOrder.Ascending))
);
咦,奇怪,數據哪裏去了呢?剛纔ID的排序正常,爲啥這裏就不正常了呢?
咱們先斷點看下:
能夠看到,ConnnectionStatus的status code是200,說明鏈接成功,可是咱們又沒有查詢出數據來,接下來就須要咱們的header工具了
在最後一個tab中,header工具容許咱們將ConnectionStatus.Request中的json用於查詢,以此來驗證對錯。咱們能夠看到,查詢的時候報了一個錯誤
Can't sort on string types with more than one value per doc, or more than one token per field
由於咱們的數據是
這樣的,在解析的時候,firstname會被analyse成多個term,因此在排序的時候,就會出錯。
那麼咱們要怎麼辦呢?
在這裏我找到了一些答案,咱們須要將一個咱們須要排序的字段mapping成兩個不一樣的字段,一個通過分析(e.g. firstname),一個沒有通過分析(e.g. firtname.sort ).
在NEST中,有一個簡便的方法,就是在你須要排序的屬性上面加一個Attribute
因此咱們先將原先的索引刪除,而後從新添加索引。
client.Map<Person>(m => m.MapFromAttributes());
這句代碼很重要(在調用它以前須要先CreateIndex),它根據ElasticProperty對對象進行了mapping,使得firstname變成了一個multi fields,這點咱們能夠從 Request的Json中紅色部分看出
{ "person": { "properties": { "id": { "type": "string" }, "firstname": { "type": "multi_field", "fields": { "firstname": { "type": "string" }, "sort": { "index": "not_analyzed", "type": "string" } } }, "lastname": { "type": "string" }, "chains": { "type": "string" } } } }
另外在header中能夠發現,屬性中多了一個person.firstname.sort
因此咱們如今可使用這個屬性來進行排序了
代碼以下:
var searchResults = client.Search<Person>(s => s
.Index("zhixiao-application")
.Sort(sort => sort.OnField(f => f.Firstname.Suffix("sort")).Ascending())
);
PS:注意上面紅色部分的代碼
排序結果以下:
成功!
3.距離排序
Elastic Search 自帶了距離的排序和距離的篩選。因此咱們只須要將索引建好,就可使用。
好了,下面咱們就一步步來進行:
public class Location { public string Name { get; set; } [ElasticProperty(Type = FieldType.GeoPoint)] public Coordinate Coordinate { get; set; } } public class Coordinate { public double Lat { get; set; } public double Lon { get; set; } }
PS:[ElasticProperty(Type = FieldType.GeoPoint)]這個attribute是爲了下面mapping的時候,ES會將其識別爲GeoPoint
client.CreateIndex("geopoint-tests", s => s .AddMapping<Location>(f => f .MapFromAttributes() .Properties(p => p .GeoPoint(g => g.Name(n => n.Coordinate).IndexLatLon()) ) ) );
下面是建立索引而且mapping的request json:
{ "settings": { "index": { } }, "mappings": { "location": { "properties": { "name": { "type": "string" }, "coordinate": { "type": "geo_point", "lat_lon": true } } } } }
client.IndexMany(new[] { createLocation("1", 52.310551, 5.07039), createLocation("2", 52.310551, 10.761176), createLocation("3", 52.310551, 8.07039), createLocation("4", 52.310551, 6.07039), }); private static Location createLocation(string name, double latitude, double longitude) { return new Location { Name = name, Coordinate = new Coordinate { Lat = latitude, Lon = longitude } }; }
(4)排序的使用:
結果:
成功!
代碼以下:
結果以下:
因爲比較簡單,我就不解釋啥了,直接上代碼
Person newperson = new Person() { Id = "7", Firstname = "Aberdeen #110", Lastname = "Update", Chains = new string[] { "a", "b", "c" }, }; UpdateRequest<Person> updateRequest = new UpdateRequest<Person>(7) { Doc = newperson }; IUpdateResponse updateResponse = updateClient.Update<Person, Person>(updateRequest); if (updateResponse.ConnectionStatus.HttpStatusCode != 200) { updateClient.Index(newperson); } client.ClearCache(); var searchResults = updateClient.Search<Person>(s => s .Index("zhixiao-application") .Query(q => q.Term(t => t.OnField(f => f.Id).Value(7))) ); Console.WriteLine(searchResults.Documents.Count()); foreach (var person in searchResults.Documents) { Console.WriteLine(person.Id + "," + person.Lastname); }
PS:須要注意的是,若是你須要清除一個屬性的值,傳入null會致使ES認爲你不須要更新這個屬性,因此清除一個屬性的值咱們須要傳入一個""。
updateClient.Delete<Person>(d => d.Id(7));
//delete one by object
updateClient.Delete<Person>(new Person() { });
//delete the Indices
updateClient.DeleteIndex(new DeleteIndexRequest(new IndexNameMarker() { Name = "zhixiao-application", Type = typeof(Person) }));