目录
我们都知道一般在百度的搜索框中搜索的时候,输入框中输的时候下面就会出现一些提示词,比如输入"老",就会出现"老师","老人"之类的词,这就是自动补全,搜索出来的文本有一些是高亮的,特别提示的,这就是高亮功能,本文着重介绍一些这两个功能!(Elasticsearch具体如何实现自动补全,可以参考下博主的这篇文章:elasticsearch的自动补全)
一、创建索引
javascript
PUT /news
{
"settings": {
"number_of_shards": 5,
"number_of_replicas": 1,
"analysis": {
"analyzer": {
"ik_pinyin": {
"tokenizer": "ik_smart",
"filter": "pinyin_filter"
},
"tag_pinyin": {
"tokenizer": "keyword",
"filter": "pinyin_filter"
}
},
"filter": {
"pinyin_filter": {
"type": "pinyin",
"keep_joined_full_pinyin": true,
"keep_original": true,
"remove_duplicated_term": true
}
}
}
},
"mappings": {
"properties": {
"id": {
"type": "integer",
"index": true
},
"title": {
"type": "text",
"index": true,
"analyzer": "ik_pinyin",
"search_analyzer": "ik_smart"
},
"content": {
"type": "text",
"index": true,
"analyzer": "ik_pinyin",
"search_analyzer": "ik_smart"
},
"url": {
"type": "keyword",
"index": true
},
"tags": {
"type": "completion",
"analyzer": "tag_pinyin",
"search_analyzer": "tag_pinyin"
}
}
}
}
二、准备数据
将MySQL中的数据同步到elasticsearch中,我使用的是logstash,注意版本一定要和elasticsearch一致!压缩包我放到我的主页资源列表了!
在logstash解压路径下的/config中创建mysql.conf文件,文件写入以下脚本内容:
javascript
input {
jdbc {
jdbc_driver_library => "C:\案例\mysql-connector-java-5.1.37-bin.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_connection_string => "jdbc:mysql:///news"
jdbc_user => "root"
jdbc_password => "root"
schedule => "* * * * *"
jdbc_default_timezone => "Asia/Shanghai"
statement => "SELECT * FROM news;"
}
}
filter {
mutate {
split => {"tags" => ","}
}
}
output {
elasticsearch {
hosts => ["http://192.168.66.147:9200","http://192.168.66.147:9201","http://192.168.66.147:9202"]
index => "news"
document_id => "%{id}"
}
}
在解压路径下打开cmd黑窗口,运行命令:
javascript
bin\logstash -f config\mysql.conf
测试自动补齐
javascript
GET /news/_search
{
"suggest": {
"my_suggest": {
"prefix": "li",
"completion": {
"field": "tags",
"skip_duplicates": true,
"size": 10
}
}
}
}
三、环境搭建
(1)环境搭建
创建一个springboot项目,引入以下依赖
javascript
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
编写配置文件
javascript
# 连接elasticsearch
spring:
elasticsearch:
uris: 192.168.0.187:9200,192.168.0.187:9201,192.168.0.187:9202
# 日志格式
logging:
pattern:
console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
(2)创建实体类
java
@Document(indexName = "news")
@Data
public class News {
@Id
@Field
private Integer id;
@Field
private String title;
@Field
private String content;
@Field
private String url;
@CompletionField
@Transient
private Completion tags;
}
(3)实现Repository接口
java
@Repository
public interface NewsRepository extends ElasticsearchRepository<News, Integer> {
}
四、实现自动补全功能
java
@Service
public class NewsService {
@Autowired
private ElasticsearchClient client;
// 自动补齐
public List<String> autoSuggest(String keyword) throws IOException {
// 1.自动补齐查询条件
Suggester suggester = Suggester.of(
s -> s.suggesters("prefix_suggestion", FieldSuggester.of(
fs -> fs.completion(
cs -> cs.skipDuplicates(true)
.size(10)
.field("tags")
)
)).text(keyword)
);
// 2.自动补齐查询
SearchResponse<Map> response = client.search(s -> s.index("news")
.suggest(suggester), Map.class);
// 3.处理查询结果
Map resultMap = response.suggest();
List<Suggestion> suggestionList = (List) resultMap.get("prefix_suggestion");
Suggestion suggestion = suggestionList.get(0);
List<CompletionSuggestOption> resultList = suggestion.completion().options();
List<String> result = new ArrayList<>();
for (CompletionSuggestOption completionSuggestOption : resultList) {
String text = completionSuggestOption.text();
result.add(text);
}
return result;
}
}
五、实现高亮搜索关键字功能
(1)在repository接口中添加高亮搜索关键字方法
java
// 高亮搜索关键字
@Highlight(fields = {@HighlightField(name = "title"), @HighlightField(name = "content")})
List<SearchHit<News>> findByTitleMatchesOrContentMatches(String title, String content);
(2)service类中调用该方法
java
// 查询关键字
public List<News> highLightSearch(String keyword){
List<SearchHit<News>> result = repository.findByTitleMatchesOrContentMatches(keyword, keyword);
// 处理结果,封装为News类型的集合
List<News> newsList = new ArrayList();
for (SearchHit<News> newsSearchHit : result) {
News news = newsSearchHit.getContent();
// 高亮字段
Map<String, List<String>> highlightFields = newsSearchHit.getHighlightFields();
if (highlightFields.get("title") != null){
news.setTitle(highlightFields.get("title").get(0));
}
if (highlightFields.get("content") != null){
news.setContent(highlightFields.get("content").get(0));
}
newsList.add(news);
}
return newsList;
}
六、编写Controller
java
@RestController
public class NewsController {
@Autowired
private NewsService newsService;
@GetMapping("/autoSuggest")
public List<String> autoSuggest(String term){ // 前端使用jqueryUI,发送的参数默认名为term
return newsService.autoSuggest(term);
}
@GetMapping("/highLightSearch")
public List<News> highLightSearch(String term){
return newsService.highLightSearch(term);
}
}
因为本项目是前后端分离,所以测试的话直接调用接口看他是不是返回对应的数据即可!