[Java]
文章目录
- 查询建议API
- 单个建议查询词
- 多个建议查询词
- Suggester
- Term suggester
- 参数
- phrase suggester
- completion suggester
- 搜索框实现
查询建议(suggest)是为用户提供良好的使用体验。主要包括: 拼写检查; 自动建议查询词(自动补全)。
官方文档:.7/search-suggesters.html#。
查询建议API
查询建议也是使用_search端点地址。在DSL中suggest节点来定义需要的建议查询。
单个建议查询词
POST _search
{"query" : {"match": {"message": "tring out Elasticsearch"}},"suggest" : { <!-- 定义建议查询 -->"my-suggestion" : { <!-- 一个建议查询名 -->"text" : "tring out Elasticsearch", <!-- 查询文本 -->"term" : { <!-- 使用词项建议器 -->"field" : "message" <!-- 指定在哪个字段上获取建议词 -->}}}
}
多个建议查询词
可以多个建议词一起查询:
POST _search
{"suggest": {"my-suggest-1" : {"text" : "tring out Elasticsearch","term" : {"suggest_mode": "missing", "field" : "message"}},"my-suggest-2" : {"text" : "kmichy","term" : {"field" : "user"}}}
}
也可以多个查询使用同一个查询文本:
POST _search
{"suggest": {"text" : "tring out Elasticsearch","my-suggest-1" : {"term" : {"field" : "message"}},"my-suggest-2" : {"term" : {"field" : "user"}}}
}
Suggester
Suggesters基本的运作原理是将输入的文本分解为token,然后在索引的字典里查找相似的term并返回。 根据使用场景的不同,Elasticsearch里设计了4种类别的Suggester,分别是:
- Term Suggester
- Phrase Suggester
- Completion Suggester
- Context Suggester
Term suggester
对输入的文本进行分词,为每个词进行模糊匹配查询提供词项建议。对于在索引中存在词默认不提供建议词,不存在的词则根据模糊查询结果进行排序后取一定数量的建议词。
项名 | 说明 |
---|---|
text | 输入文本(用户的输入),根据此文本查找建议 |
field | 要查询的字段 |
analyzer | 指定分词器 |
size | 每个词返回的最大建议词数量 |
sort | 建议词的排序方式: 1. score:先按评分排序,再按文档频率、term顺序排; 2. frequency:先按文档频率排序,再按评分、term顺序排 |
suggest_mode | 建议模式(控制提供建议词的方式): 1. missing:默认方式,仅在‘要搜索词项’不在索引中存在时,才提供建议词; 2. popular:仅提供频率比‘要搜索词项’高的建议词; 3. always:总是提供建议词; |
public void termSuggestSearch(String index, String field, String keyword) {try (RestHighLevelClient rhlClient = ESClient.getClient()) {TermSuggestionBuilder termSuggestion = SuggestBuilders.termSuggestion(field);termSuggestion.text(keyword);termSuggestion.size(5);termSuggestion.suggestMode(TermSuggestionBuilder.SuggestMode.ALWAYS);SuggestBuilder suggestBuilder = new SuggestBuilder();String suggestName = "sugName";suggestBuilder.addSuggestion(suggestName, termSuggestion);SearchRequest searchRequest = new SearchRequest(index);SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.suggest(suggestBuilder);searchRequest.source(sourceBuilder);SearchResponse response = rhlClient.search(searchRequest, RequestOptions.DEFAULT);Suggest suggest = response.getSuggest();if (suggest != null) {Suggest.Suggestion result = suggest.getSuggestion(suggestName);for (Object term : result.getEntries()) {if(term instanceof TermSuggestion.Entry) {TermSuggestion.Entry entry = (TermSuggestion.Entry)term;entry.getOptions().forEach(z->{System.out.println("Text: " + z.getText() + ", freq: " + z.getFreq() + ", score: " + z.getScore());});}else {System.out.println("It is not termSuggestion.Entry: " + term);}}}} catch (Exception ex) {System.out.println(index + " query fail: " + ex);}
}
参数
字段名称 | 说明 |
---|---|
max_edits | 表示被选为建议的edit distance 的最大值,只能是1,2之间的数(可以是小数),默认是2 |
prefix_length | 表示被选为建议的最小前缀字符的长度,默认为1 ,增加这个长度可以提高拼写检查的性能,通常拼写错误不会发生在术语的最前面 |
min_word_length | 表示推荐文本的最小长度,默认为4 |
shard_size | 设置从每个分片检索的建议的最大数量。在reduce阶段,根据size选项只返回前N个建议。默认是和size选项一样 |
max_inspections | 表示一个因子,这个参数和shard_size参数相乘以便在分片级别检查更多的候选者的拼写错误,参数默认为5 |
min_doc_freq | 表示一个建议中应包含文档数目的最小限制,可以指定为一个确切的数或文档数的相对百分比,默认是0(即不开启此功能) |
max_term_freq | 表示推荐文本可以包含的文档数目的最大限制,可以是一个代表文档频率的确切值,也可以是一个相对百分数(比如0.4),默认是0.01f。这个参数可以用来排除高频术语的拼写检查 |
string_distance | 表示一个字符串距离用于和推荐内容相比它们之间的相似性,这个参数可能的值有5个:internal :表示默认的基于damerau_levenshtein 算法,但在比较字符串距离内的索引已经做过高度优化damerau_levenshtein :是一种基于Damerau-Levenshtein 算法的字符串距离算法levenshtein :是一种基于Levenshtein edit distance算法的字符串距离算法jaro_winkler :是一种基于Jaro-Winkler 算法的字符串距离算法ngram :是一种基于字符连词的字符串距离算法 |
phrase suggester
短语建议,在term的基础上,考量多个term间的关系(是否同时出现在索引的原文里,相邻程度,以及词频等):
public void phraseSuggestSearch(String index, String field, String keyword) {try (RestHighLevelClient rhlClient = ESClient.getClient()) {PhraseSuggestionBuilder phraseSuggestion = SuggestBuilders.phraseSuggestion(field);phraseSuggestion.text(keyword);phraseSuggestion.size(5);SuggestBuilder suggestBuilder = new SuggestBuilder();String suggestName = "sugName";suggestBuilder.addSuggestion(suggestName, phraseSuggestion);SearchRequest searchRequest = new SearchRequest(index);SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.suggest(suggestBuilder);searchRequest.source(sourceBuilder);SearchResponse response = rhlClient.search(searchRequest, RequestOptions.DEFAULT);Suggest suggest = response.getSuggest();if (suggest != null) {Suggest.Suggestion result = suggest.getSuggestion(suggestName);for (Object term : result.getEntries()) {if(term instanceof PhraseSuggestion.Entry) {PhraseSuggestion.Entry entry = (PhraseSuggestion.Entry)term;entry.getOptions().forEach(z->{System.out.println("Text: " + z.getText() + ", score: " + z.getScore());});}else {System.out.println("It is not phraseSuggestion.Entry: " + term);}}}} catch (Exception ex) {System.out.println(index + " query fail: " + ex);}
}
completion suggester
Completion Suggester提供自动完成/随类型搜索的功能;这是一种导航特性,可以在用户键入时引导他们找到相关结果,提高搜索精度。因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。对于一个open状态的索引,FST会被ES整个装载到内存里的,进行前缀查找速度极快。但是FST只能用于前缀查找,这也是Completion Suggester的局限所在。
为了使用自动补全,索引中用来提供补全建议的字段需特殊设计,字段类型为 completion。
搜索框实现
要实现搜索框的补全/纠错功能:
- 在用户刚开始输入的过程中,使用Completion Suggester进行关键词前缀匹配,刚开始匹配项会比较多,随着用户输入字符增多,匹配项越来越少。
- 如果用户输入比较精准,可能Completion Suggester的结果已经够好,用户已经可以看到理想的备选项了。 如果Completion Suggester已经到了零匹配,那么可以猜测是否用户有输入错误,这时候可以尝试一下Phrase Suggester。如果Phrase Suggester没有找到任何option,开始尝试term Suggester。
- 精准程度上(Precision)看: Completion > Phrase > term, 而召回率上(Recall)则反之。从性能上看,Completion Suggester是最快的,如果能满足业务需求,只用Completion Suggester做前缀匹配是最理想的。Phrase和Term由于是做倒排索引的搜索,相比较而言性能应该要低不少,应尽量控制suggester用到的索引的数据量,最理想的状况是经过一定时间预热后,索引可以全量map到内存。
[Java]
文章目录
- 查询建议API
- 单个建议查询词
- 多个建议查询词
- Suggester
- Term suggester
- 参数
- phrase suggester
- completion suggester
- 搜索框实现
查询建议(suggest)是为用户提供良好的使用体验。主要包括: 拼写检查; 自动建议查询词(自动补全)。
官方文档:.7/search-suggesters.html#。
查询建议API
查询建议也是使用_search端点地址。在DSL中suggest节点来定义需要的建议查询。
单个建议查询词
POST _search
{"query" : {"match": {"message": "tring out Elasticsearch"}},"suggest" : { <!-- 定义建议查询 -->"my-suggestion" : { <!-- 一个建议查询名 -->"text" : "tring out Elasticsearch", <!-- 查询文本 -->"term" : { <!-- 使用词项建议器 -->"field" : "message" <!-- 指定在哪个字段上获取建议词 -->}}}
}
多个建议查询词
可以多个建议词一起查询:
POST _search
{"suggest": {"my-suggest-1" : {"text" : "tring out Elasticsearch","term" : {"suggest_mode": "missing", "field" : "message"}},"my-suggest-2" : {"text" : "kmichy","term" : {"field" : "user"}}}
}
也可以多个查询使用同一个查询文本:
POST _search
{"suggest": {"text" : "tring out Elasticsearch","my-suggest-1" : {"term" : {"field" : "message"}},"my-suggest-2" : {"term" : {"field" : "user"}}}
}
Suggester
Suggesters基本的运作原理是将输入的文本分解为token,然后在索引的字典里查找相似的term并返回。 根据使用场景的不同,Elasticsearch里设计了4种类别的Suggester,分别是:
- Term Suggester
- Phrase Suggester
- Completion Suggester
- Context Suggester
Term suggester
对输入的文本进行分词,为每个词进行模糊匹配查询提供词项建议。对于在索引中存在词默认不提供建议词,不存在的词则根据模糊查询结果进行排序后取一定数量的建议词。
项名 | 说明 |
---|---|
text | 输入文本(用户的输入),根据此文本查找建议 |
field | 要查询的字段 |
analyzer | 指定分词器 |
size | 每个词返回的最大建议词数量 |
sort | 建议词的排序方式: 1. score:先按评分排序,再按文档频率、term顺序排; 2. frequency:先按文档频率排序,再按评分、term顺序排 |
suggest_mode | 建议模式(控制提供建议词的方式): 1. missing:默认方式,仅在‘要搜索词项’不在索引中存在时,才提供建议词; 2. popular:仅提供频率比‘要搜索词项’高的建议词; 3. always:总是提供建议词; |
public void termSuggestSearch(String index, String field, String keyword) {try (RestHighLevelClient rhlClient = ESClient.getClient()) {TermSuggestionBuilder termSuggestion = SuggestBuilders.termSuggestion(field);termSuggestion.text(keyword);termSuggestion.size(5);termSuggestion.suggestMode(TermSuggestionBuilder.SuggestMode.ALWAYS);SuggestBuilder suggestBuilder = new SuggestBuilder();String suggestName = "sugName";suggestBuilder.addSuggestion(suggestName, termSuggestion);SearchRequest searchRequest = new SearchRequest(index);SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.suggest(suggestBuilder);searchRequest.source(sourceBuilder);SearchResponse response = rhlClient.search(searchRequest, RequestOptions.DEFAULT);Suggest suggest = response.getSuggest();if (suggest != null) {Suggest.Suggestion result = suggest.getSuggestion(suggestName);for (Object term : result.getEntries()) {if(term instanceof TermSuggestion.Entry) {TermSuggestion.Entry entry = (TermSuggestion.Entry)term;entry.getOptions().forEach(z->{System.out.println("Text: " + z.getText() + ", freq: " + z.getFreq() + ", score: " + z.getScore());});}else {System.out.println("It is not termSuggestion.Entry: " + term);}}}} catch (Exception ex) {System.out.println(index + " query fail: " + ex);}
}
参数
字段名称 | 说明 |
---|---|
max_edits | 表示被选为建议的edit distance 的最大值,只能是1,2之间的数(可以是小数),默认是2 |
prefix_length | 表示被选为建议的最小前缀字符的长度,默认为1 ,增加这个长度可以提高拼写检查的性能,通常拼写错误不会发生在术语的最前面 |
min_word_length | 表示推荐文本的最小长度,默认为4 |
shard_size | 设置从每个分片检索的建议的最大数量。在reduce阶段,根据size选项只返回前N个建议。默认是和size选项一样 |
max_inspections | 表示一个因子,这个参数和shard_size参数相乘以便在分片级别检查更多的候选者的拼写错误,参数默认为5 |
min_doc_freq | 表示一个建议中应包含文档数目的最小限制,可以指定为一个确切的数或文档数的相对百分比,默认是0(即不开启此功能) |
max_term_freq | 表示推荐文本可以包含的文档数目的最大限制,可以是一个代表文档频率的确切值,也可以是一个相对百分数(比如0.4),默认是0.01f。这个参数可以用来排除高频术语的拼写检查 |
string_distance | 表示一个字符串距离用于和推荐内容相比它们之间的相似性,这个参数可能的值有5个:internal :表示默认的基于damerau_levenshtein 算法,但在比较字符串距离内的索引已经做过高度优化damerau_levenshtein :是一种基于Damerau-Levenshtein 算法的字符串距离算法levenshtein :是一种基于Levenshtein edit distance算法的字符串距离算法jaro_winkler :是一种基于Jaro-Winkler 算法的字符串距离算法ngram :是一种基于字符连词的字符串距离算法 |
phrase suggester
短语建议,在term的基础上,考量多个term间的关系(是否同时出现在索引的原文里,相邻程度,以及词频等):
public void phraseSuggestSearch(String index, String field, String keyword) {try (RestHighLevelClient rhlClient = ESClient.getClient()) {PhraseSuggestionBuilder phraseSuggestion = SuggestBuilders.phraseSuggestion(field);phraseSuggestion.text(keyword);phraseSuggestion.size(5);SuggestBuilder suggestBuilder = new SuggestBuilder();String suggestName = "sugName";suggestBuilder.addSuggestion(suggestName, phraseSuggestion);SearchRequest searchRequest = new SearchRequest(index);SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.suggest(suggestBuilder);searchRequest.source(sourceBuilder);SearchResponse response = rhlClient.search(searchRequest, RequestOptions.DEFAULT);Suggest suggest = response.getSuggest();if (suggest != null) {Suggest.Suggestion result = suggest.getSuggestion(suggestName);for (Object term : result.getEntries()) {if(term instanceof PhraseSuggestion.Entry) {PhraseSuggestion.Entry entry = (PhraseSuggestion.Entry)term;entry.getOptions().forEach(z->{System.out.println("Text: " + z.getText() + ", score: " + z.getScore());});}else {System.out.println("It is not phraseSuggestion.Entry: " + term);}}}} catch (Exception ex) {System.out.println(index + " query fail: " + ex);}
}
completion suggester
Completion Suggester提供自动完成/随类型搜索的功能;这是一种导航特性,可以在用户键入时引导他们找到相关结果,提高搜索精度。因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。对于一个open状态的索引,FST会被ES整个装载到内存里的,进行前缀查找速度极快。但是FST只能用于前缀查找,这也是Completion Suggester的局限所在。
为了使用自动补全,索引中用来提供补全建议的字段需特殊设计,字段类型为 completion。
搜索框实现
要实现搜索框的补全/纠错功能:
- 在用户刚开始输入的过程中,使用Completion Suggester进行关键词前缀匹配,刚开始匹配项会比较多,随着用户输入字符增多,匹配项越来越少。
- 如果用户输入比较精准,可能Completion Suggester的结果已经够好,用户已经可以看到理想的备选项了。 如果Completion Suggester已经到了零匹配,那么可以猜测是否用户有输入错误,这时候可以尝试一下Phrase Suggester。如果Phrase Suggester没有找到任何option,开始尝试term Suggester。
- 精准程度上(Precision)看: Completion > Phrase > term, 而召回率上(Recall)则反之。从性能上看,Completion Suggester是最快的,如果能满足业务需求,只用Completion Suggester做前缀匹配是最理想的。Phrase和Term由于是做倒排索引的搜索,相比较而言性能应该要低不少,应尽量控制suggester用到的索引的数据量,最理想的状况是经过一定时间预热后,索引可以全量map到内存。