Elasticsearch,分布式搜索引擎

一:Elasticsearch简介

在这里插入图片描述
官网:https://www.elastic.co/cn/

Elasticsearch是目前性能最好、最流行的搜索引擎,像FaceBook、百度、维基百科、GitHub,很多知名的大厂都在使用Elasticsearch搜索引擎。

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

所谓搜索引擎,其实会有以下两个步骤:
1、提交数据:我们首先是要把数据先存一份到搜索引擎中,按照这个角度,我们其实可以把搜索引擎看成是一个特殊的数据库。

2、分词、建立索引:在存数据时,搜索引擎会进行分词,建立索引,从而提供搜索功能。

但是有些搜索引擎在提交数据阶段就会很慢,有的搜索引擎在分词、建立索引阶段会很慢,从而使他们并不能做到提供实时的搜索服务
而Elasticsearch可以,这足以体现出Elasticsearch的强大之处

二:Elasticsearch术语

既然我们可以把搜索引擎看成是一个特殊的数据库
那么我们就可以类比数据库中的一些术语。

  • 索引、类型、文档、字段。
    1、索引—> 与数据库中的database数据库相对应;一个索引就相当于一个库
    2、类型—> 与数据库中的table表相对应;一个类型就相当于一张表
    3、文档—> 相当于table表中的一条数据。JSON结构
    4、字段—> 就相当于table中的一个字段,一列数据

注意: 在6.0版本之后,类型的概念逐渐的被废弃,之后索引就代表的是一张表,文档代表的还是一条数据,字段还是相当于一个字段。

  • 集群、节点、分片、副本。

1、分片—> 对索引的进一步划分,一个索引在进行存储的时候可以划分成多个分片进行存储,大大提高并发能力。

2、副本—> 对各个分片进行备份数据,大大提高可用性。

三:SpringBoot整合Elasticsearch

由于SpringBoot中的父pom.xml文件中适配的Elasticsearch版本为6.4.3
在这里插入图片描述
所以建议采用6.4.3版本,而不要使用最新的7.0版本,因为从6.0版本到7.0版本变化还是很大的,会造成兼容性问题。

1、导入依赖

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2、配置Elasticsearch

# ElasticsearchProperties
spring.data.elasticsearch.cluster-name=nowcoder   #自己随意起的名字
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300  

3、解决冲突

因为Elasticsearch和Redis的底层都是基于Netty的,所以他们两个在同时使用时就会产生冲突。
详情见源码:
在这里插入图片描述
在这里插入图片描述
在启动类上设置System.setProperty(“es.set.netty.runtime.available.processors”, “false”);

@PostConstruct
public void init() {
	// 解决netty启动冲突问题
    // see Netty4Utils.setAvailableProcessors()
	System.setProperty("es.set.netty.runtime.available.processors", "false");
}

4、向Elasticsearch提交数据

我们只需要在要搜索数据的数据表的实体类上加上一些说明的注解,让他能够进行对应的存储。

例如:查询讨论区的贴子

shards —>分片数量
replicas —>副本数量

analyzer —> 存储时的解析器。
例如:我们要往Elasticsearch存入"互联网校招",那么采用ik_max_word这个解析器那么在存数据时,就会尽可能多的对数据进行分词,建立尽可能多的词条以便于之后的搜索服务,可能"互联网校招"就会被拆分成"互联"、“联网”、“互联网”、“网校”、"校招"这么多分词。

ik代表是中文的分词器。

searchAnalyzer—> 搜索时的解析器。
例如:我们在搜索"互联网校招"时,我们没有必要再把它拆分出很多的词条,我们应该希望Elasticsearch能够智能的理解它的意思,进行智能的分词,那么可能只会拆分出"互联网"、"校招"这两个词条,这样就会便于查找相应的内容,所以采用ik_smart分词器。

@Document(indexName = "discusspost", type = "_doc", shards = 6, replicas = 3)
public class DiscussPost {

    @Id
    private int id;

    @Field(type = FieldType.Integer)
    private int userId;

    @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;

    @Field(type = FieldType.Integer)
    private int type;

    @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;

5、创建Elasticsearch的API接口

1、ElasticsearchTemplate
需要这个接口来补充ElasticsearchRepository接口不能进行的操作。

2、ElasticsearchRepository
这个接口操作起来比较简单。

@Repository
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {

}

6、CURD、搜索操作测试代码

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTests {
    @Autowired
    private DiscussPostMapper discussMapper;

    @Autowired
    private DiscussPostRepository discussRepository;

    @Autowired
    private ElasticsearchTemplate elasticTemplate;

    @Test
    public void testInsert() {
        discussRepository.save(discussMapper.selectDiscussPostById(241));
        discussRepository.save(discussMapper.selectDiscussPostById(242));
        discussRepository.save(discussMapper.selectDiscussPostById(243));
    }

    @Test
    public void testInsertList() {
        discussRepository.saveAll(discussMapper.selectDiscussPosts(101, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(102, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(103, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(111, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(112, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(131, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(132, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(133, 0, 100));
        discussRepository.saveAll(discussMapper.selectDiscussPosts(134, 0, 100));
    }

    @Test
    public void testUpdate() {
        DiscussPost post = discussMapper.selectDiscussPostById(231);
        post.setContent("我是新人,使劲灌水.");
        discussRepository.save(post);
    }

    @Test
    public void testDelete() {
         discussRepository.deleteById(231);
//        discussRepository.deleteAll();
    }

    @Test
    public void testSearchByRepository() {
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(0, 10))
                .withHighlightFields(
                        new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
                        new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                ).build();

        // ElasticsearchRepository底层使用的方法,高亮的样式没有返回,这是一个缺点,我们可以采用ElasticsearchTemplate来解决
        // elasticTemplate.queryForPage(searchQuery, class, SearchResultMapper)
        // 底层获取得到了高亮显示的值, 但是没有返回.

        Page<DiscussPost> page = discussRepository.search(searchQuery);
        System.out.println(page.getTotalElements());
        System.out.println(page.getTotalPages());
        System.out.println(page.getNumber());
        System.out.println(page.getSize());
        for (DiscussPost post : page) {
            System.out.println(post);
        }
    }

    @Test
    public void testSearchByTemplate() {
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(0, 10))
                .withHighlightFields(
                        new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
                        new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                ).build();

        Page<DiscussPost> page = elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
                SearchHits hits = response.getHits();
                if (hits.getTotalHits() <= 0) {
                    return null;
                }

                List<DiscussPost> list = new ArrayList<>();
                for (SearchHit hit : hits) {
                    DiscussPost post = new DiscussPost();

                    String id = hit.getSourceAsMap().get("id").toString();
                    post.setId(Integer.valueOf(id));

                    String userId = hit.getSourceAsMap().get("userId").toString();
                    post.setUserId(Integer.valueOf(userId));

                    String title = hit.getSourceAsMap().get("title").toString();
                    post.setTitle(title);

                    String content = hit.getSourceAsMap().get("content").toString();
                    post.setContent(content);

                    String status = hit.getSourceAsMap().get("status").toString();
                    post.setStatus(Integer.valueOf(status));

                    String createTime = hit.getSourceAsMap().get("createTime").toString();
                    post.setCreateTime(new Date(Long.valueOf(createTime)));

                    String commentCount = hit.getSourceAsMap().get("commentCount").toString();
                    post.setCommentCount(Integer.valueOf(commentCount));

                    // 处理高亮显示的结果
                    HighlightField titleField = hit.getHighlightFields().get("title");
                    if (titleField != null) {
                        post.setTitle(titleField.getFragments()[0].toString());
                    }

                    HighlightField contentField = hit.getHighlightFields().get("content");
                    if (contentField != null) {
                        post.setContent(contentField.getFragments()[0].toString());
                    }

                    list.add(post);
                }

                return new AggregatedPageImpl(list, pageable,
                        hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());
            }
        });

        System.out.println(page.getTotalElements());
        System.out.println(page.getTotalPages());
        System.out.println(page.getNumber());
        System.out.println(page.getSize());
        for (DiscussPost post : page) {
            System.out.println(post);
        }
    }
}

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Elasticsearch是一个基于开源的分布式搜索和分析引擎,主要用于处理大规模数据的实时搜索、分析和存储。它利用了分布式架构的优势,可以快速地搜索和处理海量数据。 Elasticsearch具有高度的可伸缩性,可以水平扩展以适应不断增长的数据量。它使用了分片和复制机制,将索引数据划分为多个分片,并在集群中的多个节点上进行复制,从而实现了数据的分布式存储和冗余备份。 对于搜索功能,Elasticsearch采用了倒排索引的概念,它通过建立字典来映射每个词项到包含该词项的文档,以实现快速的全文搜索。同时,它还支持各种查询类型和过滤器,可以根据不同的需求进行高级搜索和过滤。 此外,Elasticsearch还提供了灵活的数据分析功能,可以进行聚合、统计和数据可视化等操作。它内置了强大的聚合框架,可以对数据进行复杂的分组、求和、平均等操作,以便更好地理解和分析数据。 另外,Elasticsearch还支持实时索引和搜索,可以实时地从更新的数据中搜索和获取结果。它采用了近乎实时的索引策略,可以保证数据的低延迟和高吞吐量。 总结来说,Elasticsearch作为一款分布式搜索和分析引擎,具有高可伸缩性、快速的搜索和分析能力,可以帮助用户高效地处理大规模数据,并从中获取有用的信息和洞察。它广泛应用于各个领域,如企业搜索、日志分析、数据挖掘等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小本科生debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值