使用Elasticsearch的Suggester实现搜索提示
搭建环境
根据官方文档创建Elasticsearch的运行环境,之后安装中文分词插件。启动Elasticsearch进程后根据如下的配置创建索引 products
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 0
}
},
"mappings": {
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword",
"fields": {
"analyzed": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
}
],
"properties": {
"suggest": {
"type": "completion"
}
}
}
}
在上面的mapping中我们把 suggest
字段设置成了 completion
类型,该类型支持 completion_suggest
的搜索。
索引数据
在创建了索引之后,我们向索引中写入的数据格式如下
{
"updateTime": "2016-09-01T10:59:22+0800",
"proxy": false,
"addTime": "2016-09-01T10:59:22+0800",
"name": "PCMS星巴克随手杯"
}
完整的数据在这里。
我们使用 python-pinyin 库把 name
字段转化为相应的拼音,例如 咖啡龙角散
被转为
[
"kflls",
"kafeilongjuesan",
"kflgs",
"kafeilonglusan",
"kafeilonggusan",
"kafeilongjiaosan",
"kfljs"
]
我们在原始数据中新增一个 suggest
字段用于存储上面的拼音数据,之后把这个文档保存到 products 索引中。具体的逻辑如下
1 | name = data.get('name') |
搜索数据
我们使用 completion_suggest 对数据进行检索
1 | requests.post(url + '/_search', json={ |
我们设置word为 ka 或者 kf 都可以获取到 咖啡龙角散 这个字段,如此一来便可以实现用户搜索时的提示功能了。用户输入 kafeil、kafeilong、kfl、咖啡龙 等等都可以获取到提示词“咖啡龙角散”。考虑到用户输入时参数会频繁的变化,所以completion_suggester针对速度进行了额外的优化,特别适合用于搜索提示的场景。
完整的搜索提示代码在此。
其它的suggester
除了completion_suggester,ES还提供了 Term Suggester 和 Phrase Suggester。和completion_suggester的前缀搜索不一样,它们使用了莱文斯坦距离来计算词之间的相关性(ES中类似的还有Fuzzy搜索),它们一般可以用于提示词纠错或拼写检查。不过因为中文的词和英文的词它们的构成原理完全不一样,而且ES中莱文斯坦距离的 max_edits 选项的值最大不能超过2,所以这几个搜索选项在中文环境中的使用场景十分有限。
你也可以使用 string_distance 选项来切换其它的编辑距离算法:
选项参数 | 使用的算法 |
---|---|
internal | 优化过的 damerau_levenshtein 算法 |
damerau_levenshtein | damerau_levenshtein 算法 |
levenshtein | Levenshtein edit distance algorithm |
jaro_winkler | Jaro-Winkler algorithm |
ngram | character n-grams 算法 |