前言
在使用ES的时候,一般常用IK
分词器作为中文的分词器使用。但是有一定使用经验的小伙伴都知道。使用中文分词器的时候,经常会遇到分词不准的情况。
在一般的情况下,大家都告诉你去维护分词字典,更新索引。但是呢,又在一般的情况下,中小公司根本没有人去特地维护小项目的搜索索引。在搜索一些短语,比如公司名称
的时候,需求方可能更想要类似mysql
中的like
实现的效果,完成模糊查询即可。
当然,在数据量不是很大的时候,直接使用ES中的wildcard
完成模糊搜索即可。但是,众所周知,wildcard
的搜索匹配的性能是非常低的,在有一定数据量的情况下,不建议在生产环境使用wildcard
。
下面介绍一种简易的代替方案:通过nGram
分词器实现like
需求,这种实现方案,特别适用于短句/短语搜索中。
分词器创建:
vbnet
curl -XPUT http://127.0.0.1:9200/test_index -H 'Content-Type: application/json' -d '{
"settings": {
"index": {
"number_of_shards": 3,
"number_of_replicas": 0
},
"analysis": {
"analyzer": {
"char_split": {
"filter": [
"lowercase"
],
"char_filter": [
"html_strip"
],
"type": "custom",
"tokenizer": "my_ngram_tokenizer"
}
},
"tokenizer": {
"my_ngram_tokenizer": {
"token_chars": [
"letter",
"digit",
"punctuation"
],
"min_gram": "1",
"type": "nGram",
"max_gram": "1",
"custom_token_chars" : ["+"]
}
}
}
}
}'
这段代码定义了一个自定义分词器,名为"char_split"。 自定义分词器的配置包含以下部分:
number_of_shards
:索引数据的分片数。number_of_replicas
:每个分片的备份数。analyzer
:定义了一个名为"char_split"的自定义分词器。filter
:指定了使用的过滤器,这里只使用了一个"lowercase"过滤器,将所有字符转换为小写。char_filter
:指定了使用的字符过滤器,这里只使用了一个"html_strip"字符过滤器,用于去除HTML标签。tokenizer
:定义了一个自定义的分词器,名为"my_ngram_tokenizer"。
token_chars
:指定了可以作为标记的字符类型,包括字母、数字和标点符号。min_gram
:指定标记的最小长度,这里设置为1。type
:指定使用的分词器类型,这里设置为nGram,表示按照给定长度切割文本。max_gram
:指定标记的最大长度,这里设置为1,表示不进行组合切割。custom_token_chars
:指定扩展的标记字符集合,这里包括"+"字符。
特别要注意的是对一些特殊字符的分词处理,虽然token_chars
中有punctuation
这个可选项,但是它不包含对 +
等常见符号的处理。如果你想要搜索 C++
,那么你需要 加上"custom_token_chars" : ["+"]
配置,使得分词器对+
号有效。具体参数设置根据自身的需要进行调整。
快速验证分词结果的方式:
bash
GET /_analyze
{
"tokenizer": {
"type" : "ngram",
"min_gram" : 1,
"max_gram" : 1,
"token_chars" : ["letter", "custom"],
"custom_token_chars" : ["+"]
},
"text": ["hello-go+odwewq "]
}
创建索引时,可以根据需要合理设置多种分词结果,例如:
json
{
"name": {
"type": "keyword",
"fields": {
"anlz_name": {
"type": "text",
"analyzer": "char_split",
"search_analyzer": "char_split"
}
}
}
}
最后分词器结合 match_phrase
方式使用即可实现类似like
的效果