搭建环境

根据官方文档创建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
2
3
4
5
name = data.get('name')
# 将名称转化为拼音列表
suggest_values = word_2_pinyin(name)
data['suggest'] = suggest_values + [name]
requests.post(url + '/_doc', json=data)

搜索数据

我们使用 completion_suggest 对数据进行检索

1
2
3
4
5
6
7
8
9
10
11
requests.post(url + '/_search', json={
'suggest': {
'completion_suggest': {
'prefix': word,
'completion': {
'field': 'suggest',
'size': 10
}
}
}
})

我们设置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 算法

参考

Elasticsearch Suggester详解
Completion Suggester
模糊性