前言:近期在研究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群中帮助过我的同学:@无相,@臭小子,@快乐的小帅哥。