Elasticsearch 简介:
Elasticsearch 术语:
要想使用 es 搜索数据,前提是要在 es 中把数据再存一份。
使用SpringBoot2.6.x集成Elasticsearch7.17
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
# ElasticsearchProperties
elasticsearch.host=127.0.0.1
elasticsearch.port=9200
/**
* Es配置类
* @ConfigurationProperties(prefix = "elasticsearch")
* 自动读取关联application.properties中前缀为elasticsearch的属性
*/
@ConfigurationProperties(prefix = "elasticsearch")
@Configuration
@Data
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
private String host;
private Integer port;
// 重写父类方法
@Override
public RestHighLevelClient elasticsearchClient() {
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
return restHighLevelClient;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Document(indexName = "discusspost", shards = 6, replicas = 3)
public class DiscussPost {
@Id
private int id;
// 用户id
@Field(type = FieldType.Integer)
private int userId;
// 帖子的标题 eg.互联网校招
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String title;
// 帖子的内容
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String content;
// type为帖子类型,0--普通帖子,1--置顶帖子,2--精华帖子
@Field(type = FieldType.Integer)
private int type;
// 帖子的状态,0--正常,1--精华,2--拉黑
@Field(type = FieldType.Integer)
private int status;
// 帖子创建的时间
@Field(type = FieldType.Date)
private Date createTime;
// 帖子评论的数量
@Field(type = FieldType.Integer)
private int commentCount;
// 记录帖子的分数
@Field(type = FieldType.Double)
private double score;
}
@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {
}
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = CommunityApplication.class)
@SpringBootTest
public class ElasticsearchTests {
@Autowired
private DiscussPostMapper discussPostMapper;
// 实现crud等操作可以使用继承ElasticsearchRepository的接口,也可以使用ElasticsearchRestTemplate
// 注入ElasticsearchRepository
@Autowired
private DiscussPostRepository discussPostRepository;
// 注入ElasticsearchRestTemplate
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
// 插入一条数据
@Test
public void testInsert() {
discussPostRepository.save(discussPostMapper.selectDiscussPostById(241));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(242));
discussPostRepository.save(discussPostMapper.selectDiscussPostById(243));
elasticsearchRestTemplate.save();
}
// 插入多条数据
@Test
public void testInsertList() {
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(101, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(102, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(103, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(111, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(112, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(131, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(132, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(133, 0, 100));
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(134, 0, 100));
}
// 修改一条数据
@Test
public void testUpdate() {
DiscussPost post = discussPostMapper.selectDiscussPostById(231);
post.setContent("SpringBoot最新教程,快来围观!");
discussPostRepository.save(post);
}
// 删除一条(多条)数据
@Test
public void testDelete() {
discussPostRepository.delete(discussPostMapper.selectDiscussPostById(231));
//discussPostRepository.deleteAll();
}
// 查询数据
@Test
public void testSearchByRepository() {
// withQuery()用于构造搜索条件
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
.withSorts(SortBuilders.fieldSort("type").order(SortOrder.DESC),
SortBuilders.fieldSort("score").order(SortOrder.DESC),
SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.withPageable(PageRequest.of(0, 10))
.withHighlightFields(
new HighlightBuilder.Field("title").preTags("").postTags(""),
new HighlightBuilder.Field("content").preTags("").postTags("")
).build();
Iterable<DiscussPost> discussPosts = discussPostRepository.findAll();
for (DiscussPost post : discussPosts) {
System.out.println(post);
}
}
// 查询数据并将关键字高亮显示
@Test
public void testSearchByTemplate() {
// withQuery()用于构造搜索条件
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
.withSorts(SortBuilders.fieldSort("type").order(SortOrder.DESC),
SortBuilders.fieldSort("score").order(SortOrder.DESC),
SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
.withPageable(PageRequest.of(0, 10))
.withHighlightFields(
new HighlightBuilder.Field("title").preTags("").postTags(""),
new HighlightBuilder.Field("content").preTags("").postTags("")
).build();
//查询
SearchHits<DiscussPost> search = elasticsearchRestTemplate.search(searchQuery, DiscussPost.class);
long count = elasticsearchRestTemplate.count(searchQuery, DiscussPost.class);
System.out.println("共查询到: "+ count +"条数据");
//得到查询返回的内容
List<SearchHit<DiscussPost>> searchHits = search.getSearchHits();
// 设置一个最后需要返回的实体类集合
List<DiscussPost> discussPosts = new ArrayList<>();
// 遍历返回的内容,进行处理
for (SearchHit<DiscussPost> hit : searchHits) {
// 获取高亮的内容
Map<String, List<String>> highlightFields = hit.getHighlightFields();
// 将高亮的内容添加到content中(匹配到的如果是多段,就将第一段高亮显示)
// 没有匹配到关键字就显示原来的title和content
hit.getContent().setTitle(highlightFields.get("title")==null ? hit.getContent().getTitle():highlightFields.get("title").get(0));
hit.getContent().setContent(highlightFields.get("content")==null ? hit.getContent().getContent():highlightFields.get("content").get(0));
// 放到实体类中
discussPosts.add(hit.getContent());
}
for (DiscussPost post : discussPosts) {
System.out.println(post);
}
}
}