公司的后续的功能需要使用到全文检索,所以需要提前调研下全文检索,所以整理了下springboot+es实现全文检索的步骤,只是能跑通和执行一些简单的查询的功能。本人从零开始学习的,有些问题还请担待。
1.es简介
全文搜索引擎 Elasticsearch 入门教程
Elasticsearch概述
因为springboot官方已经整合过es了,可以查看官方的文档
官方文档
jdk需要1.8
es下载地址
全文检索的时候中文分词器使用ik分词器,ik分词器的版本需要和es的版本一致,或者查看ik的github地址,查看对应关系。
ik分词器下载地址
kibana可视化操作es
kibana下载地址
es下载解压后,打开bin目录,windows执行elasticsearch.bat 开启es。在浏览器中输入http://localhost:9200/即可访问,出现下图所示即访问成功:
然后在es目录的plugins下新建文件夹ik,将下载好的ik分词器解压到其中。注意,解压后的ik分词器包含很多jar文件和一个config文件夹。如果发现解压后发现下载的是ik源码。。。。那就自己打包一个就好,打包过程如下:
1.安装maven
2.在ik源码目录中打开cmd
3.执行mvn clean compile
4.执行mvn clean package
5.在target/releases目录下会有一个压缩文件,解压后复制到es/plugins/ik目录下
最后,启动es后如果没有报错说明启动成功,如果报错了。。。。。。看日志解决吧(都是坑)。
在es安装目录,config下找到elasticsearch.yml文件,这个就是es配置文件。修改一下几个配置:
集群名称
cluster.name:
节点名称
node.name:
修改为0.0.0.0运行自己以为的主机访问
network.host: 0.0.0.0
允许跨域
http.cors.enabled: true
http.cors.allow-origin: "*"
org.springframework.boot
spring-boot-starter-data-elasticsearch
spring:
data:
elasticsearch:
cluster-nodes: localhost:9300 #节点地址
cluster-name: my-application #集群名称
repositories:
enabled: true
@Document(indexName = "test", type = "doc")
public class TestItem {
@Id
private int id;
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Text, searchAnalyzer = "ik_smart", analyzer = "ik_max_word")
private String content;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
实体注解说明:
@Document:说明当前实体为文档主要使用俩个属性indexName和type
indexName:声明索引名称
type:声明type
@Field:字段注解,配置字段属性,主要属性如下
type:声明字段属性
searchAnalyzer:指定搜索分词器
analyer:指定分词器
ik分词器参数:
ik_smart: 为最少切分
ik_max_word:为最细粒度划分
springboot提供了ElasticsearchCrudRepository 来执行基础的crud操作,如下所示:
public interface TestRespository extends ElasticsearchCrudRepository {
List findAll();
List findAllByTitleContains(String title);
TestItem findByTitleContains(String title);
TestItem findByTitle(String title);
}
@Autowired
private TestRespository testRespository;
@GetMapping("/addAll")
public String addAll(){
List all = achieventRepository.findAll();
for (AchieventItem achieventItem : all) {
TestItem testItem = new TestItem();
testItem.setId(achieventItem.getId());
testItem.setContent(achieventItem.getSubContent1());
testItem.setTitle(achieventItem.getTitle());
testRespository.save(testItem); //保存到es中
}
return "success";
}
@GetMapping("/findByContiansTitle")
public TestItem findByContiansTitle(@RequestParam(name = "k") String k){
TestItem byTitleContains = testRespository.findByTitleContains(k);
return byTitleContains;
}
@GetMapping("/findByTitle")
public TestItem findByTitle(@RequestParam(name = "k") String k){
TestItem byTitleContains = testRespository.findByTitle(k);
return byTitleContains;
}
如果有高亮需求需要使用到ElasticsearchTemplate这个类。
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@GetMapping("/full")
public List fullSearch(@RequestParam(name = "k") String k) {
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.requireFieldMatch(false);
//对所有找到的搜索词添加同一个标签
// highlightBuilder.field("title");
// highlightBuilder.field("content");
// highlightBuilder.preTags("");
// highlightBuilder.postTags("");
//对不同的关键词添加不同的标签
HighlightBuilder.Field titleField = new HighlightBuilder.Field("title"); //高亮标题
titleField.preTags(""); //标题的开始标签
titleField.postTags(" ");//标题的结束标签
HighlightBuilder.Field contentField = new HighlightBuilder.Field("content"); //高亮内容
contentField.preTags(""); //内容的开始标签
contentField.postTags(" "); //内容的结束标签
highlightBuilder.field(titleField);
highlightBuilder.field(contentField);
builder.withIndices("test"); //设置搜索的索引
builder.withQuery(QueryBuilders.multiMatchQuery(k, "title", "content")); //设置搜索的字段为title,content
builder.withHighlightBuilder(highlightBuilder); //添加高亮设置
NativeSearchQuery query = builder.build();
//带分页功能就使用queryForPage
// AggregatedPage testItems = elasticsearchTemplate.queryForPage(query, TestItem.class, new DefaultResultMapper() {
// @Override
// public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
// return super.mapResults(response, clazz, pageable);
// }
// });
List results = elasticsearchTemplate.query(query, new ResultsExtractor>() {
@Override
public List extract(SearchResponse searchResponse) {
List items = new ArrayList<>();
SearchHits hits = searchResponse.getHits();
if (hits.totalHits == 0) {
return items;
}
TestItem item;
for (SearchHit hit : hits) {
item = new TestItem();
Map source = hit.getSourceAsMap();
HighlightField hTitle = hit.getHighlightFields().get("title");
if (hTitle != null) { //如果不为空说明title中有高亮内容
item.setTitle(hTitle.getFragments()[0].toString());
} else { //如果为null说明title没有高亮内容,从source中那对于的值
item.setTitle((String) source.get("title"));
}
HighlightField content = hit.getHighlightFields().get("content");
if (content != null) {
item.setContent(content.getFragments()[0].toString());
} else {
item.setContent((String) source.get("content"));
}
item.setId((Integer) source.get("id"));
items.add(item);
}
return items;
}
});
return results;
}
全文搜索引擎 Elasticsearch 入门教程
Elasticsearch概述
官方文档
springboot整合Elasticsearch