现代的搜索引擎一般都会提供Suggest as you type的功能,即搜索建议。本篇就主要记录下ES提供的相关能力
什么是搜索建议
现代的搜索引擎,一般都会提供SUggest as you type的功能。帮助用户在输入搜索的过程中,进行自动补全或者纠错。通过协助用户输入更加精准的关键词,提高后续搜索阶段文档匹配程度
在google上搜索,一开始会自动补全。当输入到一定长度,如因为单词拼写错误无法补全,就会开始提示相似的词或者句子
Elasticsearch Suggester API
ES通过Suggester API来实现的搜索建议
原理是,将输入的文本分解为Token,然后在索引的字典里查找相似的Term并返回
根据不同的使用场景,ES设计了四种类别的Suggester
- Term & Phrase Suggester
- Complete & Context Suggester
Term Suggester
Suggester其实就是一种特殊类型的搜索,”text”里是调用时候提供的文本,通常来自用户输入的内容
示例
创建示例数据
1 | DELETE articles |
搜索
- 用户输入的”lucen”是一个错误的拼写
- 会到指定的字段”body”上搜索,当无法搜索到结果时(missing),返回建议的词
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18POST /articles/_search
{
"size": 1,
"query": {
"match": {
"body": "lucen rock"
}
},
"suggest": {
"term-suggestion": {
"text": "lucen rock",
"term": {
"suggest_mode": "missing",
"field": "body"
}
}
}
}
Suggestion Mode
- Missing 如索引中已经存在,就不提供建议
- Popular 推荐出现词频更加高的词
- Always 无论是否存在,都提供建议
实现原理
相似性是通过Levenshtein Edit Distance的算法实现的。核心思想就是一个词改动多少字符就可以和另外一个词一致。提供了很多可选参数来控制相似度的模糊程度。例如”max_edits”
每个建议都包含了一个算分,下面例子中响应信息可以看出
示例
搜索”lucen rock”1
2
3
4
5
6
7
8
9
10
11
12
13POST /articles/_search
{
"suggest": {
"term-suggestion": {
"text": "lucen rock",
"term": {
"suggest_mode": "popular",
"field": "body"
}
}
}
}
响应信息如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28"suggest" : {
"term-suggestion" : [
{
"text" : "lucen",
"offset" : 0,
"length" : 5,
"options" : [
{
"text" : "lucene",
"score" : 0.8,
"freq" : 2
}
]
},
{
"text" : "rock",
"offset" : 6,
"length" : 4,
"options" : [
{
"text" : "rocks",
"score" : 0.75,
"freq" : 2
}
]
}
]
}
将查询条件”rock”修改为”hock”,增加了”prefix_length”来进行控制,结果返回也是会推荐”rock”相关推荐1
2
3
4
5
6
7
8
9
10
11
12
13
14
15POST /articles/_search
{
"suggest": {
"term-suggestion": {
"text": "lucen hocks",
"term": {
"suggest_mode": "always",
"field": "body",
"prefix_length":0,
"sort": "frequency"
}
}
}
}
Phrase Suggester
Phrase Suggester在Term Suggester上增加了一些额外的逻辑。
增加了如下参数
- Suggest Mode: missing, popular, always
- Max Errors: 最多可拼错的Terms数
- Confidence: 限制返回结果数,默认为1
示例
1 | POST /articles/_search |
The Completion Suggester
Completion Suggester提供了自动补全(Auto Complete)的功能。用户每输入一个字符,就需要即时发送一个查询请求到后端查找匹配项
对性能要求比较苛刻。ES采用了不同的数据结构,并非通过倒排索引完成。
而是将Analyze的数据编码成FST和索引一起存放。FST会被ES加载进内存,访问速度很快
- 缺点:FST只能用于前缀查找
使用Completion Suggester的步骤
- 定义Mapping,type使用completion
- 创建索引数据后,使用suggest查询来获取搜索建议
示例
创建mapping,创建示例数据。
- suggest查询使用article-suggester
- prefix 需要补全内容的前缀,即用户输入内容
- completion field指定补全字段
1 | PUT articles |
Context Suggester
Completion Suggester的扩展功能
在很多情况下用户输入信息需要根据上下文进行提示,例如用户输入”star”
- 咖啡相关 建议”Starbucks”
- 电影相关 建议”StarWars”
实现Context Suggester
可以定义两种类型的Context
- Category 任意字符串
- Geo 地理位置信息
实现Context Suggester的步骤
- 定义Mapping
- 创建索引数据,并且为每个文档加入Context信息
- 结合Context进行Suggestion查询
示例
同样创建一个type为completion的字段,并且指定contexts,type为category,且为其命名
查询时在completion下增加contexts,使用定义mapping时候contexts的命名comment_category来进行查询1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49PUT comments/_mapping
{
"properties": {
"comment_autocomplete":{
"type": "completion",
"contexts":[{
"type":"category",
"name":"comment_category"
}]
}
}
}
POST comments/_doc
{
"comment":"I love the star war movies",
"comment_autocomplete":{
"input":["star wars"],
"contexts":{
"comment_category":"movies"
}
}
}
POST comments/_doc
{
"comment":"Where can I find a Starbucks",
"comment_autocomplete":{
"input":["starbucks"],
"contexts":{
"comment_category":"coffee"
}
}
}
POST comments/_search
{
"suggest": {
"MY_SUGGESTION": {
"prefix": "sta",
"completion":{
"field":"comment_autocomplete",
"contexts":{
"comment_category":"coffee"
}
}
}
}
}
Suggester精准度和召回率比较
精准度
Completion > Phrase > Term
召回率
Term > Phrase > Completion
性能
Completion > Phrase > Term