利于seo优化的网站,人才网站 建设好 窗口,一级a做爰网站免费,订阅号 小程序一、常见的NoSQL解决方案
1、redis
Redis是一个基于内存的 key-value 结构数据库。Redis是一款采用key-value数据存储格式的内存级NoSQL数据库#xff0c;重点关注数据存储格式#xff0c;是key-value格式#xff0c;也就是键值对的存储形式。与MySQL数据库不同#xff0…一、常见的NoSQL解决方案
1、redis
Redis是一个基于内存的 key-value 结构数据库。Redis是一款采用key-value数据存储格式的内存级NoSQL数据库重点关注数据存储格式是key-value格式也就是键值对的存储形式。与MySQL数据库不同MySQL数据库有表、有字段、有记录Redis没有这些东西就是一个名称对应一个值并且数据以存储在内存中使用为主。redis的基本使用
2、mongodb
MongoDB可以在内存中存储类似对象的数据并实现数据的快速访问。使用Redis技术可以有效的提高数据访问速度但是由于Redis的数据格式单一性无法操作结构化数据当操作对象型的数据时Redis就显得捉襟见肘。在保障访问速度的情况下如果想操作结构化数据看来Redis无法满足要求了此时需要使用全新的数据存储结束来解决此问题即MongoDB技术。mongodb的基本使用
3、ESElasticsearch
ESElasticsearch是一个分布式全文搜索引擎重点是全文搜索。
二、ES的使用
ES简介
es是由Apache开源的一个兼有搜索引擎和NoSQL数据库功能的系统其特点主要如下。 基于Java/Lucene构建支持全文搜索、结构化搜索应用于加速数据的查询 低延迟支持实时搜索 分布式部署可横向集群扩展 支持百万级数据 支持多条件复杂查询如聚合查询 高可用性数据可以进行切片备份 支持Restful风格的api调用
全文搜索 全文搜索的理解 比如用户要在淘宝上买一本书Java开发那么他就可以以Java为关键字进行搜索不管是书名中还是书的介绍中甚至是书的作者名字只要包含java就作为查询结果返回给用户查看。这就可以理解为全文搜索。 搜索的条件不再是仅用于对某一个字段进行比对而是在一条数据中使用搜索条件去比对更多的字段只要能匹配上就列入查询结果这就是全文搜索的目的。而ES技术就是一种可以实现上述效果的技术。 全文搜索的实现 要实现全文搜索的效果不可能使用数据库中like操作去进行比对这种效率太低了。ES设计了一种全新的思想来实现全文搜索。具体操作过程如下 将被查询的字段的数据全部文本信息进行拆分分成若干个词 例如“中华人民共和国”就会被拆分成三个词分别是“中华”、“人民”、“共和国”此过程有专业术语叫做分词。分词的策略不同分出的效果不一样不同的分词策略称为分词器。 将分词得到的结果存储起来对应每条数据的id 例如id为1的数据中名称这一项的值是“中华人民共和国”那么分词结束后就会出现“中华”对应id为1“人民”对应id为1“共和国”对应id为1例如id为2的数据中名称这一项的值是“人民代表大会“那么分词结束后就会出现“人民”对应id为2“代表”对应id为2“大会”对应id为2此时就会出现如下对应结果按照上述形式可以对所有文档进行分词。需要注意分词的过程不是仅对一个字段进行而是对每一个参与查询的字段都执行最终结果汇总到一个表格中 分词结果关键字对应id中华1人民1,2共和国1代表2大会2 当进行查询时如果输入“人民”作为查询条件可以通过上述表格数据进行比对得到id值1,2然后根据id值就可以得到查询的结果数据了。 上述过程中分词结果关键字内容每一个都不相同作用有点类似于数据库中的索引是用来加速数据查询的。 但是数据库中的索引是对某一个字段进行添加索引而这里的分词结果关键字不是一个完整的字段值只是一个字段中的其中的一部分内容。并且索引使用时是根据索引内容查找整条数据全文搜索中的分词结果关键字查询后得到的并不是整条的数据而是数据的id要想获得具体数据还要再次查询因此这里为这种分词结果关键字起了一个全新的名称叫做倒排索引。
ES的应用场景
ES作为全文检索的搜索引擎在以下几个方面都存在着相应的应用 监控。针对日志类数据进行存储、分析、可视化。针对日志数据ES给出了ELK的解决方案。其中logstash采集日志ES进行复杂的数据分析kibana进行可视化展示。 电商网站。用于商品信息检索。 Json文档数据库。用于存放json格式的文档 维基百科。提供全文搜索并高亮关键字
Es的windows版安装 windows版安装包下载地址https://www.elastic.co/cn/downloads/elasticsearch 下载zip文件然后直接解压即可解压完的目录如下data目录是使用了数据库后自己给你创建的里面的存放的就是你ES数据库的文件 ES的运行在bin目录下双击elasticserach.bat文件。默认端口号9200 然后访问http://localhost:9200/看到下面的json数据后表示es已经启动成功。
ES的基础操作
ES的基础操作-----索引操作
对于mysql数据库我们一般需要创建数据库之后才能继续操作而ES则需要创建索引之后才能继续操作。 对于es的操作我们只需要发web请求就可以了。要操作ES可以通过Rest风格的请求来进行因为它支持rest风格可以使用postman进行操作也就是说发送一个请求就可以执行一个操作。比如新建索引删除索引这些操作都可以使用发送请求的形式来进行。 ES中保存的数据只是格式和数据库存储的数据格式 与我们的mysql等数据库不同而已。 在ES中我们要先创建倒排索引这个索引的功能又有点类似于数据库的表。然后将数据添加到倒排索引中添加的数据称为文档。所以要进行ES的操作要先创建索引再添加文档这样才能进行后续的查询操作。
不具备分词效果的索引的创建没有指定分词器
创建索引注意这里使用的请求方式是put而不是post 获取索引 获取无分词器的索引返回的信息
{book: {aliases: {},mappings: {},settings: {index: {routing: {allocation: {include: {_tier_preference: data_content}}},number_of_shards: 1,provided_name: book,creation_date: 1704103713618,number_of_replicas: 1,uuid: 1mabgD9eR7WvHVZeCBfVqw,version: {created: 7160299}}}}
}删除索引
利用分词器进行创建索引创建索引并指定分词器
我们在创建索引时可以添加请求参数设置分词器。ik分词器的下载https://github.com/medcl/elasticsearch-analysis-ik/releases分词器下载后解压到ES安装目录的plugins目录中即可安装分词器后需要重新启动ES服务器。使用IK分词器创建索引格式
创建带分词器的索引创建索引并指定规则
参数数据如下
{mappings:{ //mapping表示定义mappings属性替换创建索引时对应的mappings属性properties:{ // properties表示定义索引中包含的属性设置属性是自定义的id:{ // 设置索引中包含id属性相当于数据库表中创建一个id字段type:keyword //设置当前属性为关键字可以被直接搜索},name:{ // 设置索引中包含name属性type:text, //设置当前属性是文本信息参与分词 analyzer:ik_max_word, //选择当前属性的分词策略这里表示使用IK分词器进行分词 copy_to:all // 表示把分词结果拷贝到all属性中即all属性中也有name属性同样的作用},type:{type:keyword},description:{type:text,analyzer:ik_max_word,copy_to:all},all:{ //all是一个定义属性虚拟的属性数据库中不存在的属性用来描述多个字段的分词结果集合当前属性可以参与查询type:text,analyzer:ik_max_word}}}
}查询带分词器的索引 返回值与前面的查询不带分词器的相比会发现mappings里面多了很多数据信息
{books: {aliases: {},mappings: { //mappings属性已经被替换properties: {all: {type: text,analyzer: ik_max_word},description: {type: text,copy_to: [all],analyzer: ik_max_word},id: {type: keyword},name: {type: text,copy_to: [all],analyzer: ik_max_word},type: {type: keyword}}},settings: {index: {routing: {allocation: {include: {_tier_preference: data_content}}},number_of_shards: 1,provided_name: books,creation_date: 1704103876876,number_of_replicas: 1,uuid: nQ2Jmml6QSOGwOI2cswwJw,version: {created: 7160299}}}}
}ES的基础操作-----文档操作
前面我们已经创建了索引了但是索引中还没有数据所以要先添加数据ES中称数据为文档下面进行文档操作。
添加文档
添加文档有三种方式创建books索引下的文档
POST请求 http://localhost:9200/books/_doc #使用系统生成id自动帮你创建
POST请求 http://localhost:9200/books/_doc/1 #使用指定id不存在创建存在更新版本递增POST请求 http://localhost:9200/books/_create/1 #使用指定id必须指定id传参数据一般不使用id属性因为指定了也不会生效要么默认帮你创建要么在请求路径上进行指定 参数的使用
{id: 1, //一般不使用这一行name: springboot1,type: book,desctiption: an book
}第一种请求方式 返回结果
{_index: books,_type: _doc,_id: MgeZxIwB35gR6M6IUssu,_version: 1,result: created,_shards: {total: 2,successful: 1,failed: 0},_seq_no: 1,_primary_term: 1
}第二种请求方式 返回结果
{_index: books,_type: _doc,_id: 55,_version: 1,result: created,_shards: {total: 2,successful: 1,failed: 0},_seq_no: 2,_primary_term: 1
}
第三种请求方式 返回结果
{_index: books,_type: _doc,_id: 1,_version: 1,result: created,_shards: {total: 2,successful: 1,failed: 0},_seq_no: 0,_primary_term: 1
}获取文档
根据id获取某个索引的文档http://localhost:9200/books/_doc/1 获取某个索引的所有的文档GET请求 http://localhost:9200/books/_search 3. 根据指定条件获取某个索引的所有的文档
GET请求 http://localhost:9200/books/_search?qname:springboot
# q查询属性名:查询属性值删除文档
根据id进行删除DELETE请求 http://localhost:9200/books/_doc/1
修改文档分为全量更新和部分更新
全量更新注意这里是put请求以及_doc
PUT请求 http://localhost:9200/books/_doc/1根据指定id进行修改传入的数据就是修改后的数据。 //文档通过请求参数传递数据格式json
{name:springboot,type:springboot,description:springboot
}修改文档部分更新注意这里是post请求以及_update
POST请求 http://localhost:9200/books/_update/1
//文档通过请求参数传递数据格式json
{ doc:{ //部分更新并不是对原始文档进行更新而是对原始文档对象中的doc属性中的指定属性更新name:springboot //仅更新提供的属性值未提供的属性值不参与更新操作}
}三、Springboot整合ES 整合步骤依旧是拿三板斧 导入依赖 做配置springboot底层有默认的配置 调用它的api接口 ES有两种级别的客户端一种是Low Level Client一种是High Level Client。 Low Level Client这种客户端操作方式性能方面略显不足不推荐使用但是springboot最初整合ES的时候使用的是低级别客户端所以企业开发需要更换成高级别的客户端模式。High Level Clien高级别客户端与ES版本同步更新
Springboot整合Low Level Client的ES不推荐使用了这里了解一下
ES早期的操作方式如下 步骤①导入springboot整合ES的starter坐标spiringboot里面有指定版本就是低级别的版本号
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-elasticsearch/artifactId
/dependency步骤②进行基础配置
spring:elasticsearch:rest:uris: http://localhost:9200配置ES服务器地址端口9200默认就是9200
步骤③使用springboot整合ES的专用客户端接口ElasticsearchRestTemplate来进行操作
SpringBootTest
class Springboot18EsApplicationTests {Autowiredprivate ElasticsearchRestTemplate template;
}springboot测试类中的测试类的初始化方法和销毁方法的使用
BeforeEach:在测试类中每个操作运行前运行的方法AfterEach 在测试类中每个操作运行后运行的方法
SpringBootTest
class Springbootests {BeforeEach //在测试类中每个操作运行前运行的方法void setUp() {//各种操作}AfterEach //在测试类中每个操作运行后运行的方法void tearDown() {//各种操作}}Springboot整合High Level Client的ES
高级别客户端方式进行springboot整合ES操作步骤如下 步骤①导入springboot整合ES高级别客户端的坐标此种形式目前没有对应的starter
dependencygroupIdorg.elasticsearch.client/groupIdartifactIdelasticsearch-rest-high-level-client/artifactId
/dependency这里的springboot版本为2.5.4es的版本为7.16.2那时候的springboot没有整合高级别的ES所以配置文件里不需要配置只能写硬编码配置 步骤②使用编程的形式设置连接的ES服务器并获取客户端对象
步骤③使用客户端对象操作ES例如创建索引为索引添加文档等等操作。
ES-----创建客户端
SpringBootTest
class Springboot18EsApplicationTests {Autowiredprivate BookMapper bookMapper;private RestHighLevelClient client;Testvoid testCreateClient() throws IOException {//先创建ES客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);client.close();}
}配置ES服务器地址与端口9200记得客户端使用完毕需要手工关闭。由于当前客户端是手工维护的因此不能通过自动装配的形式加载对象。
ES-----根据客户端创建索引
SpringBootTest
class Springboot18EsApplicationTests {Autowiredprivate BookMapper bookMapper;private RestHighLevelClient client;Testvoid testCreateIndex() throws IOException {//先创建ES客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);//在通过ES客户端创建索引CreateIndexRequest request new CreateIndexRequest(books);client.indices().create(request, RequestOptions.DEFAULT); client.close();}
}高级别客户端操作是通过发送请求的方式完成所有操作的ES针对各种不同的操作设定了各式各样的请求对象上例中创建索引的对象是CreateIndexRequest其他操作也会有自己专用的Request对象。
ES-----根据客户端创建索引使用Ik分词器
使用分词器IK
//json的参数
{mappings:{properties:{id:{type:keyword},name:{type:text,analyzer:ik_max_word,copy_to:all},type:{type:keyword},description:{type:text,analyzer:ik_max_word,copy_to:all},all:{type:text,analyzer:ik_max_word}}}
}Testvoid testCreateClientIndexByIk() throws IOException {
// 创建客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);CreateIndexRequest request new CreateIndexRequest(books);String json {\n \mappings\:{\n \properties\:{\n \id\:{\n \type\:\keyword\\n },\n \name\:{\n \type\:\text\,\n \analyzer\:\ik_max_word\,\n \copy_to\:\all\\n },\n \type\:{\n \type\:\keyword\\n },\n \description\:{\n \type\:\text\,\n \analyzer\:\ik_max_word\,\n \copy_to\:\all\\n },\n \all\:{\n \type\:\text\,\n \analyzer\:\ik_max_word\\n }\n }\n }\n };//设置请求中的参数添加分词器request.source(json, XContentType.JSON);client.indices().create(request, RequestOptions.DEFAULT);client.close();}IK分词器是通过请求参数的形式进行设置的设置请求参数使用request对象中的source方法进行设置至于参数是什么取决于你的操作种类。当请求中需要参数时均可使用当前形式进行参数设置。
ES-----为索引添加文档
// 添加文档Testvoid testCreateClientIndexByIkAddData() throws IOException {
// 创建客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);// 进行添加操作因为前面已经创建好了books索引Book book bookMapper.selectById(1);
// 把book对象数据转换为json数据String json JSON.toJSONString(book);
// 指定添加的文档的id为book.getId()需要添加文档的索引为booksIndexRequest request new IndexRequest(books).id(book.getId().toString());
// 传入数据request.source(json,XContentType.JSON);client.index(request,RequestOptions.DEFAULT);client.close();}
添加文档使用的请求对象是IndexRequest与创建索引使用的请求对象不同。
ES-----为索引批量添加文档
// 批量添加Testvoid testCreateClientIndexByIkAddBatchData() throws IOException {
// 创建客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);// 进行添加操作因为前面已经创建好了books索引ListBook bookList bookMapper.selectList(null);
// BulkRequest的对象可以将该对象理解为是一个保存request对象的容器
// 将所有的请求都初始化好后添加到BulkRequest对象中再使用BulkRequest对象的bulk方法一次性执行完毕BulkRequest bulk new BulkRequest();for (Book book : bookList) {// 把book对象数据转换为json数据String json JSON.toJSONString(book);
// 指定添加的文档的id为book.getId()需要添加文档的索引为booksIndexRequest request new IndexRequest(books).id(book.getId().toString());
// 传入数据request.source(json,XContentType.JSON);
// 把数据放进BulkRequest对象里面bulk.add(request);}
// 批量执行client.bulk(bulk,RequestOptions.DEFAULT);
// 关闭客户端client.close();}
批量做时先创建一个BulkRequest的对象可以将该对象理解为是一个保存request对象的容器将所有的请求都初始化好后添加到BulkRequest对象中再使用BulkRequest对象的bulk方法一次性执行完毕。
ES-----查询文档
根据id查询 Test//按id查询void testGetById() throws IOException {// 创建客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);// 根据id查询GetRequest request new GetRequest(books,1);GetResponse response client.get(request, RequestOptions.DEFAULT);
// 获取查询到的数据中的source属性的数据String json response.getSourceAsString();System.out.println(json);client.close();}条件查询 Test//按条件查询void testSearch() throws IOException {// 创建客户端HttpHost host HttpHost.create(http://localhost:9200);RestClientBuilder builder RestClient.builder(host);client new RestHighLevelClient(builder);//SearchRequest request new SearchRequest(books);//创建条件查询对象SearchSourceBuilder searchSourceBuilder new SearchSourceBuilder();
// 设置查询条件searchSourceBuilder.query(QueryBuilders.termQuery(all, spring));
// 把查询条件放进请求中request.source(searchSourceBuilder);// 根据请求获取返回数据SearchResponse response client.search(request, RequestOptions.DEFAULT);
// 获取返回数据里面的hits属性获取的具体属性可以看上面的postman操作SearchHits hits response.getHits();for (SearchHit hit : hits) {String source hit.getSourceAsString();//把json数据转换为对象Book book JSON.parseObject(source, Book.class);System.out.println(book);}}Mysql与Es数据同步的实现这里只是基本了解一下
在实际项目开发中我们经常将mysql作为业务数据库ES作为擦汗寻数据库用来实现读写分离缓解mysql数据库的查询压力应对海量数据的复杂查询。
1、同步双写
这是一种最为简单的方式在将数据写入mysql的同时也把数据写到ES里面优缺点 优点 业务逻辑简单 2、 实时性高 缺点 硬编码有需要写入MySQL的地方都需要添加写入es的代码 业务强耦合 存在双写失败丢失数据的风险 性能较差本来的mysql的性能不是很高再加一个es系统的性能必然会下降
2. 异步双写
针对多数据源写入的场景可以借助MQ实现异步的多源写入优缺点 优点 性能高 不易出现数据丢失问题主要基于MQ消息的消费保障机制比如ES宕机或者写入失败还能重新消费MQ消息 多源写入之间相互隔离便于扩展更多的数据源写入 缺点 硬编码问题接入新的数据源需要实现新的消费者代码 2、系统复杂度增加映入了消息中间件3、数据实时问题mq是异步消费用户输入不一定会马上同步让他看到
3、基于sql抽取定时任务
上面两种方案都存在硬编码问题代码的侵入性太强如果对实时性要求不高的情况下可以考虑用定时器来处理 数据库的相关表中增加一个字段为updatetime自己定义的名称字段任何CURD操作都会导致该字段的实际发生变化 原来程序中的crud操作不做任何变化 增加一个定时器程序让该程序按一定的时间周期扫描指定的表把该时间段内发生的变化的数据提取出来 比较此字段来确认变更数据然后把变更的数据逐条写入ES中。 优缺点 优点 1、不改原代码没有侵入性没有硬编码2、没有业务强耦合不改变原来程序的性能3、worker代码编写简单不需要考虑增删改查 缺点 1、时效性太差由于采取定时器根据固定频率查询表来同步数据尽管将同步周期设置到秒级也还是会存在一定时间的延迟。2、对数据库有一定的轮询压力。 优化的方案1、将轮寻放到压力不大的从库上2、借助logstash实现数据同步其底层实现原理就是根据配置定期使用sql查询新增的数据写入es中实现数据的增量同步经典方案
4、基于Binlog实现同步 前三种代码要么有代码侵入要么有延迟。 而基于Binlog与mysql实现同步既能保证数据同步的实时性又没有代入、侵入性。 实施步骤 1、读取mysql 的binlog日志获取指定表的日志信息2、将读取的信息转为mq3、编写一个mq消费程序4、不断消费mq每费完一条消息将消息写入到es中 优缺点 优点 1、没有代码侵入没有硬编码原有系统不需要任何变化没有感知3、性能高4、业务解耦不需要关注原来系统的业务逻辑 缺点 1、构建Binlog系统复杂2、如皋采用MQ消费解析的Binlog信息也会存在MQ延时的风险
数据迁移工具选型
对于上面的四种数据同步方案“基于Binlog实时同步”方案是目前最为常用的也诞生了很多优秀的数据迁移工具主要有以下几种 1、canal 原理是伪装成mysql的从数据库2、阿里云DTS 需付费3、databus4、Flink5、CloudCanal6、Maxwell