前言:近期在研究elasticsearch,開發語言c#,一個“簡單”的功能研究了一天,好費神(可能第一次使用es的原因)。這個功能就是:c#語言中String的Contains功能。
例如:文本內容是:4G時代,網絡標准有FDD、TDD之分
1.搜索“有FDD”,可以搜索出來;
2.搜索“有FDDD”,不可以搜索出來。
這個功能看似簡單,像c#里面Contains,SQL里面Like都可以很容易的完成搜索要求,elasticsearch就稍微有點復雜了,因為分詞的原因,導致第2種情況也可以搜索出來。網上看了很多文章,大多都千篇一律,可用價值不大,今天把我所得分享一下,希望有需求的同學少走些彎路。
要實現這個功能的思想是:
1.創建索引的時候要設置字段的type為keyword(不分詞);
2.使用query_string查詢的時候,搜索內容前后加上*。
開發環境
開發語言c#
Elasticsearch.Net版本:7.X
Nest版本:7.X
具體步驟和代碼實現如下:
第一步:定義實體(文檔內容)
public class StudentEntity
{
public string eid { get; set; }
[Text(Name = "title")]
public string title { get; set; }
[Keyword(Name = "content")]
public string content { get; set; }
public DateTime time { get; set; }
}
Content上面定義Keyword屬性,為下面創建索引使用。
第二步:創建索引,索引名稱為“news”
var nodes = new Uri[] { new Uri("http://localhost:9200") };
var pool = new StaticConnectionPool(nodes);
var settings = new ConnectionSettings(pool).DefaultIndex("news");
client = new ElasticClient(settings);
client.Indices.Create("news", c => c.Settings(s =>
s.NumberOfShards(5).NumberOfReplicas(1)).Map<StudentEntity>(m => m.AutoMap()));
創建好索引后,我們查看索引信息:
我們看到content的type為“keyword”,title的type為text。
第三步:插入數據
StudentEntity se = new StudentEntity()
{
eid = "1000",
title = "4G時代,網絡標准有FDD、TDD之分",
content = "4G時代,網絡標准有FDD、TDD之分",
time = Convert.ToDateTime("2020-06-19 19:28:32")
};
client.Index<StudentEntity>(se, s => s.Index("news"));
第四步:查詢
查詢語句1:輸入“*有FDD*”,查詢字段content
結果搜索出來,符合條件:
查詢語句2:輸入“*有FDDD*”,查詢字段content
結果搜索不出來,符合條件:
我們再來看看title搜索結果:
查詢語句:(1)輸入“*有FDD*”,查詢字段title
結果搜索不出來,不符合條件:
(2)輸入“有FDD”,查詢字段title,結果搜索出來,符合條件。
(3)輸入“有FDDD”,查詢字段title,結果搜索出來,不符合條件。
C#代碼為:
var response = client.Search<StudentEntity>(s => s.From(0).Size(10).Index("news").Query(q => q.QueryString(r => r.DefaultField("content").Query("*有FDD*"))));
Console.WriteLine(JsonConvert.SerializeObject(response.Documents));
特殊情況:
如果要搜索的內容中含有*,則在其前面加上\\即可,例如:*\\*有FDD*
至此,類似Contains或者Like的功能就實現了,有需求的同學可以將上面思想或者代碼重新整合一下用到自己的項目中。
在此要感謝QQ群中幫助過我的同學:@無相,@臭小子,@快樂的小帥哥。