在springboot中集成Elasticsearch,以我开发的博客系统项目为例,这是一篇文章内容。
准备
本次Elasticsearch使用的是单机版,版本为6.7.8,并且装好中文分词器。
Springboot集成Elasticsearch
- 首先在pom文件中引入Elasticsearch依赖。
<!--elasticsearch--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>
- 创建一个对象,与数据库存储结构字段对应,使用@Data是导入了lombok,
@Document(indexName = “article_document”, type = “docs”, shards = 1, replicas = 0),这个注解会在elasticsearch里面创建一个article_document的索引。@Id 注解为elasticsearch的id字段。
类型(type)
每个文档都有与之对应的类型(type)定义。这允许用户在一个索引中存储多种文档类型,并为不同文档提供类型提供不同的映射。
分片(shards)#
代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。5.X默认不能通过配置文件定义分片
副本(replicas)#
代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当个某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
@Data
@Document(indexName = "article_document", type = "docs", shards = 1, replicas = 0)
public class ArticleDocument implements Serializable {@Idprivate Long id;@Field(type = FieldType.Text, analyzer = "ik_max_word")private String title; //标题@Field(type = FieldType.Text, analyzer = "ik_max_word")private String summary;// 概述@Field(type = FieldType.Text, analyzer = "ik_max_word")private String content; // 内容@Field(type = FieldType.Boolean)private Boolean published;//是否已发布@Field(type = FieldType.Integer)private Integer status;//审核状态public interface Table {String ID = "id";String TITLE = "title";String SUMMARY = "summary";String CONTENT = "content";String PUBLISHED = "published";String STATUS = "status";}
}
- 写一个接口ArticleDocumentRepository继承ElasticsearchRepository,ElasticsearchRepository包含了基本的增删改查的能力,并在接口类上加上@Repository注解,注入到spring 容器中.
@Repository
public interface ArticleDocumentRepository extends ElasticsearchCrudRepository<ArticleDocument, Long> {List<ArticleDocument> findDistinctByTitleLikeOrSummaryLikeOrContentLike(String title, String summary, String content);
}
- ArticleDocumentServiceImpl类自动注入ArticleDocumentRepository的接口,去操作Elasticsearch。
@Autowiredprivate ArticleDocumentRepository articleDocumentRepository;
- 接着就对Elasticsearch进行增删改查的操作。
保存
我是用了mybatis-plus,可以根据自己修改,在保存文章的时候,调用这个方法,Article是我的文章对象。
public void saveToElasticSearch(Article article) {ArticleDocument articleDocument = new ArticleDocument();BeanUtils.copyProperties(article, articleDocument);if (articleDocument.getPublished() == null) {QueryWrapper<Article> wrapper = new QueryWrapper<>();wrapper.select(Article.Table.PUBLISHED).eq(Article.Table.ID, article.getId());Article temp = articleMapper.selectOne(wrapper);articleDocument.setPublished(temp.getPublished());}if (articleDocument.getStatus() == null) {QueryWrapper<Article> wrapper = new QueryWrapper<>();wrapper.select(Article.Table.STATUS).eq(Article.Table.ID, article.getId());Article temp = articleMapper.selectOne(wrapper);articleDocument.setStatus(temp.getStatus());}articleDocumentRepository.save(articleDocument);}
更新
先将原来的索引删除掉
//从ElasticSearch中删除articleDocumentRepository.deleteById(article.getId());
再保存新的索引
saveToElasticSearch(article);
删除
articleDocumentRepository.deleteById(article.getId());
查询
将查询的结果用List返回。
public List<ArticleDocument> listByKeyword(String keyword) throws IOException {SearchRequest searchRequest = new SearchRequest(TableConstant.ARTICLE_DOCUMENT);//匹配查询SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, ArticleDocument.Table.TITLE, ArticleDocument.Table.SUMMARY, ArticleDocument.Table.CONTENT);TermQueryBuilder termQueryBuilder1 = QueryBuilders.termQuery(ArticleDocument.Table.PUBLISHED, true);TermQueryBuilder termQueryBuilder2 = QueryBuilders.termQuery(ArticleDocument.Table.STATUS, Constant.AUDIT_PASS);BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(multiMatchQueryBuilder).must(termQueryBuilder1).must(termQueryBuilder2);sourceBuilder.query(boolQueryBuilder);//高亮HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field(ArticleDocument.Table.TITLE).field(ArticleDocument.Table.SUMMARY).field(ArticleDocument.Table.CONTENT);highlightBuilder.preTags(Constant.HIGH_LIGHT_PRE_TAGS);highlightBuilder.postTags(Constant.HIGH_LIGHT_POST_TAGS);sourceBuilder.highlighter(highlightBuilder);//执行搜索searchRequest.source(sourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);//解析结果List<ArticleDocument> articleDocuments = new ArrayList<>();for (SearchHit hit : searchResponse.getHits().getHits()) {Map<String, Object> map = hit.getSourceAsMap();//原来的结果//解析高亮的字段HighLightUtil.parseField(hit, ArticleDocument.Table.TITLE);HighLightUtil.parseField(hit, ArticleDocument.Table.SUMMARY);HighLightUtil.parseField(hit, ArticleDocument.Table.CONTENT);ArticleDocument articleDocument = new ArticleDocument();articleDocument.setId(Long.valueOf((Integer) map.get(ArticleDocument.Table.ID)));articleDocument.setTitle((String) map.get(ArticleDocument.Table.TITLE));articleDocument.setSummary((String) map.get(ArticleDocument.Table.SUMMARY));articleDocument.setContent((String) map.get(ArticleDocument.Table.CONTENT));articleDocuments.add(articleDocument);}return articleDocuments;}
elasticsearch有一个高亮配置HighLightUtil,可以使关键词高亮显示。
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;import java.util.Map;public class HighLightUtil {public static void parseField(SearchHit hit, String field) {Map<String, Object> map = hit.getSourceAsMap();//原来的结果HighlightField title = hit.getHighlightFields().get(field);//解析高亮的字段if (title != null) {Text[] fragments = title.fragments();StringBuilder newTitle = new StringBuilder();for (Text fragment : fragments) {newTitle.append(fragment);}//高亮文本替换掉原来的内容map.put(field, newTitle.toString());}}
我们可以看到,这里我使用的是谷歌商城的ElasticSearch Heap这个插件,非常方便。
有什么问题可以再评论区评论,我会尽快回复。
参考文章:https://blog.csdn.net/forezp/article/details/106839262