SpringBoot2.6.x整合Elasticsearch7.17

SpringBoot2.6.x整合Elasticsearch7.17

Elasticsearch 简介:

  • 一个分布式的,Restful 风格的搜索引擎。
  • 支持对各种类型的数据的检索。
  • 搜索速度快,可以提供实时的搜索服务。
  • 便于水平扩展,每秒可以处理 PB 级的海量数据。

Elasticsearch 术语:

  • 索引,类型,文档,字段
  • 集群,节点,分片,副本

要想使用 es 搜索数据,前提是要在 es 中把数据再存一份。

  • 索引(index):一个索引就是一个拥有几分相似特征的文档的集合(可以类比MySQL中的一个数据库)。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。 在一个集群中,如果你想,可以定义任意多的索引。
  • 类型(type):在一个索引中,你可以定义一种或多种类型(可以类比为MySQL数据库中的一张表,不过在新版本中type已经被废弃)。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。
  • 文档(document): 一个文档是一个可被索引的基础信息单元(可以类比MySQL表中的一条数据)。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
  • 字段(field): JSON 风格的每一个属性叫做字段,对应与表中的列名。
  • 集群(cluster):一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。他们协同工作,共享数据并提供故障转移和扩展功能,当然一个节点也可以组成一个集群。
  • 节点(node):节点,一个运行的 ES 实例就是一个节点(也就是你集群中的一个服务器),作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。 在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。
  • 分片(shards): 一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。所以一个索引在存储的时候就可以拆成多个分片,每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。这样就大大提高了并发能力。
  • 副本(replicas):副本是对分片的备份(拷贝),一个分片可以包含多个副本。万一哪份备份数据出现了问题,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的,这就可以创建分片的一份或多份拷贝,提高了系统的可用性。

使用SpringBoot2.6.x集成Elasticsearch7.17

  1. pom 文件
<dependency>
   <groupId>org.springframework.bootgroupId>
   <artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
  1. application.properties配置
# ElasticsearchProperties
elasticsearch.host=127.0.0.1
elasticsearch.port=9200
  1. Elasticsearch配置类
/**
 * 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;
    }
}
  1. 实体类
@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;
}
  1. 创建继承Elasticsearch的接口
@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {

}
  1. 创建测试类
@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);
        }
    }
}

你可能感兴趣的:(中间件,elasticsearch)