1) 概念
查询建议,能够为用户提供良好的使用体验。主要包括:
拼写检查(纠错)
自动建议查询词(自动补全)
2) Suggest种类及参数
2.1 Term Suggester
Term Suggester: 对给入的文本进行分词,为每个词进行模糊查询提供词项建议。(建议对搜索词进行长度控制,超过长度则不会进行TermSuggest,原因也是一般Term Suggester适用于单个词使用 把得分最高的推荐词进行返回代表纠错)
参数 | 描述 |
---|---|
text | 建议文本,即要进行推荐建议的文本(推荐控制长度 使用单个词进行搜索推荐)。 |
field | 从哪个字段中获取建议结果,智搜词库中指定的keyword字段 |
analyzer | 分析器 |
size | 建议返回的更正词的最大数量。 |
sort | 排序方式 1.score(默认):首先是按分数进行排序,分数相同按词频(freq)进行排序 2.frequency: 首先按词频进行排序,然后按分数进行排序 |
suggest_mode | 建议模式控制 1.missing(默认): 搜索的词如果本身就存在词库中,则不进行推荐搜索 2.popular:推荐词的词频大于搜索的词的时候才会推荐出来 3.always:根据建议文本中的术语提出任何匹配的建议。 |
max_edits | 允许推荐的词的最大编辑距离 默认为2 |
prefix_length | 必须满足搜索词的前端的多少个字符 |
max_term_freq | 搜索词可以出现在文档中的最大阈值(一般设置为百分比如0.4) 用于过滤高频词 |
min_doc_freq | 最少出现在多少个文档中 |
string_distance | 指定算法进行推荐计算 1.internal: 默认基于 damerau_levenshtein,但高度优化用于比较索引内术语的字符串距离 2.damerau_levenshtein 3.levenshtein 4.jaro_winkler 5. ngram |
2.2 Phrase Suggester
Phrase Suggester:在term的基础上,会考量多个term之间的关系,比如是否同时出现在索引的原文里,相邻程度,以及词频等。
如果说term suggester建议处理单个词的纠错 那么Phrase Suggester就建议作为一整句话的纠错(返回值的suggest列表中返回的也是一整句话)
参数 | 描述 |
---|---|
max_errors | 该句子中拼写错误的术语的最大百分比 如果给定[0,1)的浮点数则为百分比!! 如果>1 则为可拼写错误词的个数!! |
separator | 短语中各个术语的分隔符 默认为空格 可以手动指定 |
highlight | 可以指定高亮 |
2.3 Completion Suggester
Completion Suggester:自动补全的建议器,此场景下用户每输入一个字符的时候,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高的情况下对后端响应速度要求比较苛刻。因此实现上它和前面两个Suggester采用了不同的数据结构。为了使用Completion Suggester,字段的类型需要专门定义如下(当然可以通过fields来指定):
这里比较有意思的一点是:completion并非使用倒排索引,而是将analyze过的数据编码成FST和索引一起存放。也就是直接编码放入内存,这样会导致他是连续的(非倒排的连续索引),这样就可以保证自动补全(利用前缀)的查询速度极快,但是由于他不是倒排索引仅仅只能用于前缀搜索了
接下来我们put数据进行测试
利用completion suggester进行查找
得到结果应该为 Elastic is the company behind...那一条
但是此处如果我们更换analyzer为English
此时我们在此插入并搜索 elastic i 将搜索不到,这是因为 我们前面提过了 它是通过分词器进行分词 并且把连续的词放入内存中以便快速搜索,但是english analyzer会剥离高频词 比如is 所以我们输入 elastic i的时候 输入被分解成"elastic"和"i",FST没有编码这个“i” , 匹配失败。
但是如果查询 elastic is 则会查询到 因为:经过english analyzer的时候is也被剥离了,只需在FST里查询"elastic"这个前缀,自然就可以匹配到了。
2.4 参数
刨析参数之前,值得一提的是:它不仅仅包含前缀查询 还包含以下几种
* prefix前缀:一般就是用于搜索推荐自动补全的 最常用
* fuzzy模糊: 对输入的词进行模糊查询并自动补全
* Regex正则:满足正则表达式的搜索....
prefix参数 | 描述 |
---|---|
field | 推荐结果选取字段 |
size | 最大返回推荐数量 |
skip_duplicates | 是否去重(默认false) |
fuzzy参数 | 描述 |
---|---|
fuzziness | 模糊音字 参考上方的Fuzzy Query中的详解 |
transpositions | 是否允许术语之间的位置交换,默认为ture |
min_length | 输入的最小长度 默认为3 |
prefix_length | 前多少个字符必须完全满足 |
3) 查询语句及返回结果解析
# 通用格式
{
"suggest" : {
"my-suggestion" : { #一个查询建议名称
"text" : "tring out Elasticsearch", #查询文本
"term" : { #种类 可以替换为phrase(phrase suggester)/prefix(complite suggester)/fuzzy.....
"field" : "message" #指定在哪个字段上获取建议词
}
}
}
}
# term
{
"suggest": {
"my-suggestion": {
"text": "lucne rock",
"term": {
"suggest_mode": "missing",
"field": "body"
}
}
}
}
# Phrase
{
"suggest": {
"my-suggestion": {
"text": "lucne and elasticsear rock",
"phrase": {
"field": "body",
"highlight": {
"pre_tag": "<em>",
"post_tag": "</em>"
}
}
}
}
}
# completion
POST blogs_completion/_search?pretty
{ "size": 0,
"suggest": {
"blog-suggest": {
"prefix": "elastic i",
"completion": {
"field": "body"
}
}
}
}
# 返回结果格式及解析
# 需要注意term suggester返回的结果为术语,而phrase返回的为一段话
# term返回结果解析
# 可以看到在options中返回结果集,text即为推荐的结果 score即为得分 frep为推荐词出现的词频
{
"suggest":{
"my_suggest1":[
{
"text":"curr",
"offset":0,
"length":4,
"options":[
{
"text":"curry",
"score":0.75,
"freq":6
},
{
"text":"court",
"score":0.5,
"freq":1
}
]
}
]
}
}
# phrase返回结果解析
# 可以看到根据我们的文本进行短语的模糊搜索并给出一整句话!!这是需要注意的和term的区别
{
"suggest":{
"my_suggest1":[
{
"text":"curr is good",
"offset":0,
"length":12,
"options":[
{
"text":"curry is good",
"score":0.007225802
},
{
"text":"court is good",
"score":0.0033184804
}
]
}
]
}
}
4) Java SDK
SearchRequest request = new SearchRequest("test_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 内层的term以及参数 还有text给定
TermSuggestionBuilder termSug = SuggestBuilders.termSuggestion("content").text("查询文本").suggestMode(TermSuggestionBuilder.SuggestMode.ALWAYS).size(10);
// 外层suggest
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("my_suggest", termSug);
// 给入suggest到整个查询中
searchSourceBuilder.suggest(suggestBuilder);
request.source(searchSourceBuilder);