IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> springboot整合消息索引 -> 正文阅读

[大数据]springboot整合消息索引

ElasticSearch检索

1.1、初识ElasticSearch

我们的应用经常需要添加检索功能,开源的 ElasticSearch 是目前全文搜索引擎的首选。他可以快速的存储、搜索和分析海量数据。Spring Boot通过整合SpringData ElasticSearch为我们提供了非常便捷的检索功能支持。

Elasticsearch是一个分布式搜索服务,提供Restful API,底层基于Lucene,采用多shard(分片)的方式保证数据安全,并且提供自动resharding的功能,github等大型的站点也是采用了ElasticSearch作为其搜索服务。

官方原话:

Elasticsearch 是一个分布式的开源搜索和分析引擎,适用于所有类型的数据,包括文本、数字、地理空间、结构化和非结构化数据。Elasticsearch 在 Apache Lucene 的基础上开发而成,由 Elasticsearch N.V.(即现在的 Elastic)于 2010 年首次发布。Elasticsearch 以其简单的 REST 风格 API、分布式特性、速度和可扩展性而闻名,是 Elastic Stack 的核心组件;Elastic Stack 是适用于数据采集、充实、存储、分析和可视化的一组开源工具。人们通常将 Elastic Stack 称为 ELK Stack(代指 Elasticsearch、Logstash 和 Kibana),目前 Elastic Stack 包括一系列丰富的轻量型数据采集代理,这些代理统称为 Beats,可用来向 Elasticsearch 发送数据。

1.2、ElasticSearch基本概念

1、Index (索引)

动词:相当于MySQL中的insert
名词:相当于MySQL中的Database
2、Type (类型)

在 Index (索引) 中,可以定义一个或多个类型,类似于MySQL中的Table,每一种类型的数据放在一起。
3、Document (文档)

保存在某个索引 (index) 下,某种类型 (Type) 的一个数据 (Document)。文档是JSON格式的,Document就像是MySQL中的某个table里面的内容。
4、概念关系图一览

5、倒排索引机制

1.3、ElasticSearch与kibana安装

为了安装方便,我们还是以容器化技术Docker进行安装:

1、下载镜像文件

[howie@laizhenghua /]$ sudo docker search elasticsearch

docker pull elasticsearch:7.4.2 # 存储和检索数据
dicker pull kibana:7.4.2 # 可视化检索数据

[howie@laizhenghua /]$ sudo docker images
REPOSITORY      TAG       IMAGE ID       CREATED         SIZE
mysql           5.7       f07dfa83b528   3 weeks ago     448MB
redis           latest    ef47f3b6dc11   5 weeks ago     104MB
kibana          7.4.2     230d3ded1abc   14 months ago   1.1GB
elasticsearch   7.4.2     b1179d41a7b4   14 months ago   855MB

2、创建挂载目录

sudo mkdir -p /mydata/elasticsearch/config
sudo mkdir -p /mydata/elasticsearch/data
sudo chmod -R 777 /mydata/elasticsearch/
sudo echo "http.host: 0.0.0.0" >/mydata/elasticsearch/config/elasticsearch.yml

chmod:change mode -R(Recursion 递归)

3、启动elasticsearch

sudo docker run --name elasticsearch -p 9200:9200 -p 9300:9300 \
-e  "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v  /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.4.2

4、启动 kibana

sudo docker run --name kibana -e ELASTICSEARCH_HOSTS=http://https://es-0a8t6rzt.public.tencentelasticsearch.com:9200/lanlan/Article -p 5601:5601 -d kibana:7.4.2

[howie@laizhenghua /]$ sudo docker run --name kibana -e ELASTICSEARCH_HOSTS=https://es-0a8t6rzt.public.tencentelasticsearch.com:9200/lanlan/Article -p 5601:5601 -d kibana:7.4.2
9b88afc2f1c00891125eeb9610bb149a023b8044bb887568219f7f160059005d

访问服务器的5601端口!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpqstGM6-1644044896802)(C:\Users\86157\AppData\Local\Temp\1643814866889.png)]

由于我之前的阿里云服务器的内存不够,于是我申请了一个腾讯云的es。

这次我们用到的是简单的ES的整合。

2.1整合

1.导入依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.创建实体类
@Document(indexName = "lanlan")
@Data
public class Article {
    @Id
    private Integer id;
    @Field(type = FieldType.Text)
    private String author;
    @Field(type = FieldType.Text,analyzer = "ik_max_word")
    private String title;
}
3.实现ElasticsearchRepository
public interface ArticleRepository extends ElasticsearchRepository<Article,Integer> {
    List<Article> findArticleByTitle(String title);
    List<Article> findByTitle(String title);
    List<Article> findByTitleContaining(String title);
}
4.测试
@SpringBootTest
class Demo12ElasticsearchApplicationTests {


    @Autowired
    ArticleRepository articleRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Test
    public void test03(){
   /*     Iterable<Article> all = articleRepository.findAll();
        for (Article article : all) {
            System.out.println(article);
        }*/


        List<Article> Forest = articleRepository.findByTitleContaining("森林");
        for (Article article : Forest) {
            System.out.println(article);
        }
    }

    @Test
    public void test02(){
        Article article = new Article();
        article.setId(3);
        article.setTitle("挪威森林1");
        article.setAuthor("村上春树");
        articleRepository.save(article);
    }



}

ElasticsearchRepository中的方法名对应我在官网中找到了这样的依据,现在粘贴过来。

如表所示

关键词样本Elasticsearch 查询字符串
AndfindByNameAndPrice{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } }, { "query_string" : { "query" : "?", "fields" : [ "price" ] } } ] } }}
OrfindByNameOrPrice{ "query" : { "bool" : { "should" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } }, { "query_string" : { "query" : "?", "fields" : [ "price" ] } } ] } }}
IsfindByName{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }}
NotfindByNameNot{ "query" : { "bool" : { "must_not" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }}
BetweenfindByPriceBetween{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }}
LessThanfindByPriceLessThan{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : false } } } ] } }}
LessThanEqualfindByPriceLessThanEqual{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }}
GreaterThanfindByPriceGreaterThan{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : false, "include_upper" : true } } } ] } }}
GreaterThanEqualfindByPriceGreaterThan{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } } ] } }}
BeforefindByPriceBefore{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } } ] } }}
AfterfindByPriceAfter{ "query" : { "bool" : { "must" : [ {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } } ] } }}
LikefindByNameLike{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}
StartingWithfindByNameStartingWith{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}
EndingWithfindByNameEndingWith{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "*?", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}
Contains/ContainingfindByNameContaining{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "*?*", "fields" : [ "name" ] }, "analyze_wildcard": true } ] } }}
In(当注释为 FieldType.Keyword 时)findByNameIn(Collection<String>names){ "query" : { "bool" : { "must" : [ {"bool" : {"must" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }}
InfindByNameIn(Collection<String>names){ "query": {"bool": {"must": [{"query_string":{"query": "\"?\" \"?\"", "fields": ["name"]}}]}}}
NotIn(当注释为 FieldType.Keyword 时)findByNameNotIn(Collection<String>names){ "query" : { "bool" : { "must" : [ {"bool" : {"must_not" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }}
NotInfindByNameNotIn(Collection<String>names){"query": {"bool": {"must": [{"query_string": {"query": "NOT(\"?\" \"?\")", "fields": ["name"]}}]}}}
TruefindByAvailableTrue{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "true", "fields" : [ "available" ] } } ] } }}
FalsefindByAvailableFalse{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "false", "fields" : [ "available" ] } } ] } }}
OrderByfindByAvailableTrueOrderByNameDesc{ "query" : { "bool" : { "must" : [ { "query_string" : { "query" : "true", "fields" : [ "available" ] } } ] } }, "sort":[{"name":{"order":"desc"}}] }
ExistsfindByNameExists{"query":{"bool":{"must":[{"exists":{"field":"name"}}]}}}
IsNullfindByNameIsNull{"query":{"bool":{"must_not":[{"exists":{"field":"name"}}]}}}
IsNotNullfindByNameIsNotNull{"query":{"bool":{"must":[{"exists":{"field":"name"}}]}}}
IsEmptyfindByNameIsEmpty{"query":{"bool":{"must":[{"bool":{"must":[{"exists":{"field":"name"}}],"must_not":[{"wildcard":{"name":{"wildcard":"*"}}}]}}]}}}
IsNotEmptyfindByNameIsNotEmpty{"query":{"bool":{"must":[{"wildcard":{"name":{"wildcard":"*"}}}]}}}

消息

1.1、前言

在介绍RabbitMQ之前,我们先来看下面一个电商项目的场景:

  • 商品的原始数据保存在数据库中,增删改查都在数据库中完成。

  • 搜索服务数据来源是索引库(Elasticsearch),如果数据库商品发生变化,索引库数据不能及时更新。

  • 商品详情做了页面静态化处理,静态页面数据也不会随着数据库商品更新而变化。

如果我们在后台修改了商品的价格,搜索页面和商品详情页显示的依然是旧的价格,这样显然不对。该如何解决?

我们可能会想到这么做:

  • 方案1:每当后台对商品做增删改操作,同时修改索引库数据及更新静态页面。

  • 方案2:搜索服务和商品页面静态化服务对外提供操作接口,后台在商品增删改后,调用接口。

这两种方案都有个严重的问题:就是代码耦合,后台服务中需要嵌入搜索和商品页面服务,违背了微服务的独立原则。

这时,我们就会采用另外一种解决办法,那就是消息队列

商品服务对商品增删改以后,无需去操作索引库和静态页面,只需向MQ发送一条消息(比如包含商品id的消息),也不关心消息被谁接收。 搜索服务和静态页面服务监听MQ,接收消息,然后分别去处理索引库和静态页面(根据商品id去更新索引库和商品详情静态页面)。

什么是消息队列
MQ全称为Message Queue,即消息队列。“消息队列”是在消息的传输过程中保存消息的容器。它是典型的:生产者、消费者模型。生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。

开发中消息队列通常有如下应用场景:

1、任务异步处理:

高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。减少了应用程序的响应时间。

2、应用程序解耦合:

MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合。

1.2、AMQP和JMS

MQ是消息通信的模型,并发具体实现。现在实现MQ的有两种主流方式:AMQP、JMS。

两者间的区别和联系:

JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式

JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。

JMS规定了两种消息模型;而AMQP的消息模型更加丰富

1.3、常见MQ产品

  • ActiveMQ:基于JMS

  • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好

  • RocketMQ:基于JMS,阿里巴巴产品,目前交由Apache基金会-

  • Kafka:分布式消息系统,高吞吐量

2、RabbitMQ快速入门

RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue 高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开发中应用非常广泛。RabbitMQ官方地址:http://www.rabbitmq.com

2.1、安装

安装RabbitMQ

docker pull rabbitmq

这里是直接安装最新的,如果需要安装其他版本在rabbitmq后面跟上版本号即可

启动RabbitMQ

docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq

这是我们的转换器
请添加图片描述
Data\Local\Temp\1644044635591.png)]

这是我们的队列
请添加图片描述

2.2、springboot整合

使用也是非常简单

首先导入amqp的坐标
<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
    <version>2.4.2</version>
</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
配置文件配置
spring:
  rabbitmq:
    host: 8.142.109.15
    username: guest
    password: guest
启动类
@EnableRabbit
@SpringBootApplication
public class Demo10RabbitMqApplication {

    public static void main(String[] args) {
        SpringApplication.run(Demo10RabbitMqApplication.class, args);
    }

}
序列化配置

有了这个bean才能在消息队列中添加类

@Configuration
public class MyAMQPConfig {

    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}
bean类
@Data
public class Book {
    private String bookName;
    private String author;
}
监听的service
@Service
public class BookService {

    /**
     * 监听队列
     * @param book
     */
    @RabbitListener(queues = "atguigu.news")
    public void receive(Book book){
        System.out.println("收到消息"+book);
    }
}
测试添加消息的类
@Test
void boottest(){
    Book book = new Book();
    book.setBookName("挪威的森林");
    book.setAuthor("村上春书");
    rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",book);
}
控制消息队列测试
    @Test
    public void createEchange(){
//        amqpAdmin.declareExchange(new DirectExchange("xiaolan.direct"));
//        amqpAdmin.declareQueue(new Queue("amqpadmin.queue"));
        amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"xiaolan.direct","amqp.haha",null));
        System.out.println("创建完成");
    }

控制消息队列测试
    @Test
    public void createEchange(){
//        amqpAdmin.declareExchange(new DirectExchange("xiaolan.direct"));
//        amqpAdmin.declareQueue(new Queue("amqpadmin.queue"));
        amqpAdmin.declareBinding(new Binding("amqpadmin.queue",Binding.DestinationType.QUEUE,"xiaolan.direct","amqp.haha",null));
        System.out.println("创建完成");
    }
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章           查看所有文章
加:2022-02-06 13:53:32  更:2022-02-06 13:56:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:34:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码