需求背景
项目搜索引擎用到全文检索,之前因为需求是多词空格分隔查询,而且中文查询的需求不大,所以索引是用的事elasticsearch内置的分词器(whitespace analyzer)。
需求描述
后面功能上线一段时间后,发现用户反馈检索功能不支持大小写匹配,对大小写敏感,后来发现whitespace是区分大小写的,所以需要调整。
功能实现
查询es官方文档后发现,es支持使用tokenizer和filter进行自定义分词器的开发(custom analyzer),所以研究一番,得到以下DSL:
PUT test
{
"settings": {
"index":{
"number_of_replicas":0
},
"analysis": {
"analyzer": {
"test":{
"tokenizer":"whitespace",
"filter":["lowercase"]
}
}
}
}
}
指定索引的analyzer为test,同时指定tokenizer和filter(tokenizer和filter支持的类型有多种,具体可参照官方文档Text anaylsis一章)
问题重现
然后按照这个设置,重新处理了全文检索用到的所有索引,发现搜索结果与之前内置whitespace分词器的结果不一致(test-title的搜索会得到test,title的分词,与之前的分词效果(test-title)不一致)
使用_analyze分析得到结果也跟使用whitespace一致,
GET test/_analyze
{
"tokenizer": "whitespace",
"filter" : ["lowercase"],
"text": "How does this work?"
}
#结果
{
"tokens" : [
{
"token" : "Test-title",
"start_offset" : 0,
"end_offset" : 10,
"type" : "word",
"position" : 0
}
]
}
GET test/_analyze
{
"tokenizer": "whitespace",
"filter" : ["lowercase"],
"text": "Test-title"
}
#结果
{
"tokens" : [
{
"token" : "test-title",
"start_offset" : 0,
"end_offset" : 10,
"type" : "word",
"position" : 0
}
]
}
问题分析
后来通过查阅文档得知,es索引存储数据的时候需要指定分词器,检索数据的时候也需要指定,如果是自定义分词器,在setting设置分词器的时候,设置的是数据存储的分词器,而在检索的时候,也需要单独指定字段的分词器。(注:es内置的分词器,只需存储的时候设置,检索数据的时候会默认使用设置的分词器)
因为我们的索引的数据写入默认使用的是自动映射字段(即每个字段都映射为text和keyword类型),所以要想针对字段进行分词器的指定,需要使用到动态模板(Dynamic templates)
问题解决
PUT test
{
"settings": {
"index":{
"number_of_replicas":0
},
"analysis": {
"analyzer": {
"test":{//自定义的test analyzer
"tokenizer":"whitespace",
"filter":["lowercase"]
}
}
}
},
"mappings": {
"dynamic_templates": [{
"string_as_keyword": {
"match":"*",//匹配所有字段
"match_mapping_type":"string",
"mapping":{
"type": "text",
"analyzer": "test",//引用自定义test analyzer
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}]
}
}
至此,一个支持whitespace分词,同时支持大小写匹配的功能就完成了。