问题描述
电商网站的搜索是最基础最重要的功能之一,搜索框上面的良好体验能为电商带来更高的收益,我们先来看看淘宝、京东、亚马逊网站的搜索建议。
在淘宝的搜索框输入【卫衣】时,下方的搜索建议包括建议词以及相关的标签:
在京东的搜索框输入【卫衣】时,下方搜索建议右方显示建议词关联的商品数量:
在亚马逊的搜索框输入【卫衣】时,搜索建议上部分能支持在特定的分类下进行搜索:
通过上述对比可以看出,不同的电商对于搜索建议的侧重点略有不同,但核心的问题包括:
- 建议词的来源可以是商品的分类名称、品牌名称、商品属性、商品名称的高频词、热搜词,也可以是一些组合词,比如“分类 + 性别”和“分类 + 属性”,还可以是一些自定义添加的词;
- 建议词维护的时候需要考虑去重,比如“Nike”和“nike”应该是相同的;
关键词索引映射:
curl -XPUT http://192.168.138.210:9200/keyword/ -d'
{
"settings" : {
"analysis" : {
"analyzer" : {
"first_py_letter_analyzer" : {
"tokenizer" : "first_py_letter",
"filter":"edgeNGram_filter"
},
"full_pinyin_letter_analyzer" : {
"tokenizer" : "full_pinyin_letter",
"filter":"edgeNGram_filter"
},
"edgeNGram_analyzer":{
"tokenizer" : "edgeNGram_tokenizer"
}
},
"tokenizer" : {
"first_py_letter" : {
"type" : "pinyin",
"keep_first_letter" : true,
"keep_full_pinyin" : false,
"keep_original" : false,
"limit_first_letter_length" : 16,
"lowercase" : true,
"trim_whitespace" : true,
"keep_none_chinese_in_first_letter": false,
"none_chinese_pinyin_tokenize": false,
"keep_none_chinese": true,
"keep_none_chinese_in_joined_full_pinyin": true
},
"full_pinyin_letter" : {
"type": "pinyin",
"keep_separate_first_letter": false,
"keep_full_pinyin": false,
"keep_original": false,
"limit_first_letter_length": 16,
"lowercase": true,
"keep_first_letter": false,
"keep_none_chinese_in_first_letter": false,
"none_chinese_pinyin_tokenize": false,
"keep_none_chinese": true,
"keep_joined_full_pinyin": true,
"keep_none_chinese_in_joined_full_pinyin": true
},
"edgeNGram_tokenizer":{
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 15,
"token_chars": ["letter", "digit"]
}
},
"filter":{
"edgeNGram_filter":{
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 50,
"token_chars": ["letter", "digit"]
}
}
},
"number_of_shards": 5,
"number_of_replicas": 1
},
"mappings":{
"suggestion":{
"properties": {
"keyword": {
"type": "keyword",
"fields": {
"keyword_ik": {
"type": "text",
"analyzer": "edgeNGram_analyzer"
},
"keyword_pinyin": {
"type": "text",
"analyzer": "full_pinyin_letter_analyzer"
},
"keyword_first_py": {
"type": "text",
"analyzer": "first_py_letter_analyzer"
}
}
},
"count": {
"type": "long",
"index": "not_analyzed"
},
"weight": {
"type": "integer",
"index": "not_analyzed"
}
}
}
}
}'
搜索语句:
{
"sort": [
{
"weight": "desc"
},
{
"count": "desc"
},
{
"_score": "desc"
}
],
"query": {
"dis_max": {
"queries": [
{
"match_phrase": {
"keyword.keyword_ik": {
"query": "卫衣"
}
}
},
{
"match_phrase": {
"keyword.keyword_pinyin": {
"query": "卫衣",
"boost": 2
}
}
}
],
"tie_breaker": 1
}
}
}
如果Elasticsearch返回的是空结果,此时应该需要增加拼写纠错的处理(拼写纠错也可以在调用Elasticsearch搜索的时候带上,但是通常情况下用户并没有拼写错误,所以建议还是在后面单独调用suggester);如果返回的suggest不为空,则根据新的词调用建议词服务;比如用户输入了【adidss】,调用Elasticsearch的suggester获取到的结果是【adidas】,则再根据adidas进行搜索建议词处理。
{
"suggest": {
"keyword_suggestion": {
"text": "adidss",
"phrase": {
"field": "keyword.keyword_pinyin",
"size": 1,
"analyzer":"standard"
}
}
}
}
关于排序:在我们的实现里面是通过weight和count进行排序的,weight目前只考虑了建议词的类型(比如分类 > 品牌 > 属性);
下面为测试数据:
下面输入错误的关键词“adidss”,获得的结果是:
到此搜索建议基本上完成,但我估计大家会有个疑惑,因为针对自动补全,elasticsearch
提供了 completion suggestion
来解决,但为什么我没用呢?主要是 completion suggestion
不支持按字段来排序,比如我这需求就是要按关键词权重(weight)和搜索次数(count)来排序的