1、DSL语句
elasticsearch提供了Completion Suggester查询来实现自动补全功能。这个查询会匹配以用户输入内容开头的词条并返回。
为了提高补全查询的效率,对于文档中字段的类型有一些约束:
-
参与补全查询的字段必须是completion类型。
-
字段的内容一般是用来补全的多个词条形成的数组。
查询的DSL语句如下:
// 自动补全查询
GET /test/_search
{
"suggest": {//表示是自动补全查询,固定写法
"title_suggest": {//给查询起的名字,自定义
"text": "s", // 关键字,查询s开头的数据
"completion": {
"field": "title", // 补全查询的字段,在哪个字段查询
"skip_duplicates": true, // 跳过重复的
"size": 10 // 获取前10条结果
}
}
}
}
2、java实现
步骤:
1.确认索引库结构和使用的分词器,建议:创建倒排索引时,使用ik和拼音分词器,查询时使用ik分词器
示例:
// 酒店数据索引库
PUT /hotel
{
"settings": {
"analysis": {
"analyzer": {
"text_anlyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
},
"completion_analyzer": {
"tokenizer": "keyword",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"id":{
"type": "keyword"
},
"name":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart",
"copy_to": "all"
},
"address":{
"type": "keyword",
"index": false
},
"price":{
"type": "integer"
},
"score":{
"type": "integer"
},
"brand":{
"type": "keyword",
"copy_to": "all"
},
"city":{
"type": "keyword"
},
"starName":{
"type": "keyword"
},
"business":{
"type": "keyword",
"copy_to": "all"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart"
},
"suggestion":{
"type": "completion",
"analyzer": "completion_analyzer",
"search_analyzer": "keyword"
}
}
}
}
2.索引库添加一个新字段suggestion,类型为completion类型
3.在对应的实体类中添加suggestion字段
4.代码实现
自动补全查询的DSL对应的JavaAPI
自动补全的结果的DSL对应的JavaAPI
根据前端的请求,完善controller层接口:
@GetMapping("suggestion")
public List<String> getSuggestions(@RequestParam("key") String prefix) {
return hotelService.getSuggestions(prefix);
}
service层:
List<String> getSuggestions(String prefix);
serviceimpl层:
@Autowired
private RestHighLevelClient client;
/**
* 自动补全查询
* @param prefix
* @return
*/
@Override
public List<String> suggestion(String prefix) {
try {
//创建请求
SearchRequest request = new SearchRequest("hotel");
//设置参数
request.source().suggest(
new SuggestBuilder().addSuggestion("suggest1", //查询名称(自定义)
SuggestBuilders.completionSuggestion("suggestion") //字段名称
.prefix(prefix) //查询prefix开头的词条
.size(10) //相当于mysql的 limit 10
.skipDuplicates(true) //重复词条只保留一份
)
);
//执行请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析结果
List<String> list = new ArrayList<>();
Suggest suggest = response.getSuggest();
CompletionSuggestion suggest1 = suggest.getSuggestion("suggest1");
List<CompletionSuggestion.Entry.Option> optionList = suggest1.getOptions();
for (CompletionSuggestion.Entry.Option option : optionList) {
String str = option.getText().string();
list.add(str);
}
return list;
} catch (IOException e) {
throw new RuntimeException(e);
}
}