推荐搜索
在搜索过程中,因为单词的拼写错误,没有得到任何的结果,希望ES能够给我们一个推荐搜索。
java
GET movies/_search
{
"suggest": {
# title_suggestion为我们自定义的名字
"title_suggestion": {
"text": "drema",
"term": {
"field": "title",
"suggest_mode": "popular"
}
}
}
}
suggest_mode,有三个值:popular、missing、always
-
popular 是推荐词频更高的一些搜索。
-
missing 是当没有要搜索的结果的时候才推荐。
-
always无论什么情况下都进行推荐。
自动补全
自动补全应该是我们在日常的开发过程中最常见的搜索方式了,如百度搜索和京东商品搜索。
自动补全的功能对性能的要求极高,用户每发送输入一个字符就要发送一个请求去查找匹配项。
ES采取了不同的数据结构来实现,并不是通过倒排索引来实现的;需要将对应的数据类型设置为
completion ; 所以在将数据索引进ES之前需要先定义 mapping 信息。
1.定义mapping
java
PUT /test-completion
{
"mappings": {
"properties": {
"name": {
"type": "completion",
"analyzer": "ik_smart"
}
}
}
}
添加数据
java
POST test-completion/_bulk
{"index": {}}
{"name": "刘德华"}
{"index": {}}
{"name": "张学友"}
{"index": {}}
{"name": "柳岩"}
{"index": {}}
{"name": "柳菲菲"}
{"index": {}}
{"name": "刘备"}
2.前缀搜索
java
GET test-completion/_search
{
"suggest": {
"prefix_suggestion": {
"prefix": "刘",
"completion": {
"field": "name",
"skip_duplicates": true,
"size": 10
}
}
}
}
java
GET test-completion/_search
{
"suggest": {
"prefix_suggestion": {
"prefix": "刘德",
"completion": {
"field": "name",
"skip_duplicates": true,
"size": 10
}
}
}
}
3.同一个字段可能既是搜索字段又是补全,则可以建立子字段
java
PUT /test-completion1
{
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"nameCompletion": {
"type": "completion"
}
}
}
}
}
}
查询
java
GET test-completion1/_search
{
"suggest": {
"prefix_suggestion": {
"prefix": "刘",
"completion": {
"field": "name.nameCompletion",
"skip_duplicates": true,
"size": 10
}
}
}
}
结果
springboot集成实现自动补全
java
@Autowired
private ElasticsearchClient client;
public List<String> suggest(String title) throws IOException {
List<String> result = new ArrayList<>();
//构建FiledSuggestMap
Map<String,FieldSuggester> filedSuggestMap = new HashMap<>();
FieldSuggester nameFiledSuggest = FieldSuggester.of(f -> f.prefix(title).completion(c -> c.field("name.nameCompletion")
.skipDuplicates(true).size(10)));
filedSuggestMap.put("pre_suggest",nameFiledSuggest);
//构建SearchRequest
SearchRequest searchRequest = SearchRequest.of(s -> s.index("suggest")
.suggest(s1 -> s1.suggesters(filedSuggestMap)));
SearchResponse<Object> search = client.search(searchRequest, Object.class);
Map<String, List<Suggestion<Object>>> suggest = search.suggest();
if (CollectionUtils.isEmpty(suggest)){
return result;
}
List<CompletionSuggestOption<Object>> preSuggest = search.suggest()
.get("pre_suggest").get(0)
.completion()
.options();
for (CompletionSuggestOption<Object> suggestOption : preSuggest) {
result.add(suggestOption.text());
}
return result;
}