SpringBoot集成ElasticSearch实现支持错别字检索和关键字高亮的模糊查询

文章目录

  • 一、背景
  • 二、环境准备
    • 1.es8集群
    • 2.Kibana
    • 3.Canal
  • 三、集成到SpringBoot
    • 1.新增依赖
    • 2.es配置类
    • 3.建立索引
    • 4.修改查询方法
  • 四、修改前端

一、背景

我们在开发项目的搜索引擎的时候,如果当数据量庞大、同时又需要支持全文检索模糊查询,甚至你想做到像百度、CSDN等大型网站的搜索效果——支持错别字查询关键字高亮显示,搜索结果根据相关性排序,如下图所示,那么就需要集成ElasticSearch来实现了。

在这里插入图片描述

本文用若依的“通知公告”页面的搜索功能来演示如何集成ElasticSearch到SpringBoot项目中改造优化搜索引擎,最终效果如下图所示

在这里插入图片描述

二、环境准备

需要部署好的中间件如下:

  • ElasticSearch(8.14.3)【集群】
  • Kibana(8.14.3)
  • Canal(1.1.8)

本文主要讲解es项目实战使用,关于部署部分就简单说下

1.es8集群

参考:ElasticSearch8集群的安装部署_es8搭建集群-CSDN博客

我这里用了三台虚拟机来部署es集群,这里推荐一个es浏览器GUI插件——Elasticvue,可视化操作界面,很方便,可用来监看节点状态、索引数据等。如下图所示

在这里插入图片描述

elasticsearch.yml 如下所示(另外两台要改下node.name)

cluster.name: es-clusternode.name: node-1# 节点属性
node.roles: [master,data]path.data: /data/es/elasticsearch-8.14.3/datapath.logs: /data/es/elasticsearch-8.14.3/logsnetwork.host: 0.0.0.0http.port: 9200discovery.seed_hosts: ["192.168.100.182:9300", "192.168.100.183:9300", "192.168.100.184:9300"]cluster.initial_master_nodes: ["node-1","node-2","node-3"]# 安全认证
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl:enabled: true # 注意第一个空格keystore.path: /data/es/elasticsearch-8.14.3/config/certs/http.p12truststore.path: /data/es/elasticsearch-8.14.3/config/certs/http.p12
xpack.security.transport.ssl:enabled: trueverification_mode: certificatekeystore.path: /data/es/elasticsearch-8.14.3/elastic-certificates.p12truststore.path: /data/es/elasticsearch-8.14.3/elastic-certificates.p12
http.host: [_local_, _site_]
ingest.geoip.downloader.enabled: false
xpack.security.http.ssl.client_authentication: none

2.Kibana

参考:Elasticsearch集群以及kibana安装_elasticsearch集群安装-CSDN博客

kibana.yml

注意这里的账号是es里本身自带的,然后密码是后期随机生成的(kibana不能配置es超管用户)

server.port: 5601server.host: "0.0.0.0"elasticsearch.hosts: - "https://192.168.100.182:9200"- "https://192.168.100.183:9200"- "https://192.168.100.184:9200"elasticsearch.username: "kibana_system"
elasticsearch.password: "z3P+5vZVRh2dh10p=i-s"
elasticsearch.ssl.verificationMode: none
i18n.locale: "zh-CN"

3.Canal

参考:canal实现MySQL和ES同步实践_canal mysql es-CSDN博客

canal.adapter-1.1.8\conf\application.yml

server:port: 8081
spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8default-property-inclusion: non_nullcanal.conf:mode: tcp #tcp kafka rocketMQ rabbitMQflatMessage: truezookeeperHosts:syncBatchSize: 1000retries: -1timeout:accessKey:secretKey:consumerProperties:# canal tcp consumercanal.tcp.server.host: 127.0.0.1:11111canal.tcp.zookeeper.hosts:canal.tcp.batch.size: 500canal.tcp.username:canal.tcp.password:# kafka consumerkafka.bootstrap.servers: 127.0.0.1:9092kafka.enable.auto.commit: falsekafka.auto.commit.interval.ms: 1000kafka.auto.offset.reset: latestkafka.request.timeout.ms: 40000kafka.session.timeout.ms: 30000kafka.isolation.level: read_committedkafka.max.poll.records: 1000# rocketMQ consumerrocketmq.namespace:rocketmq.namesrv.addr: 127.0.0.1:9876rocketmq.batch.size: 1000rocketmq.enable.message.trace: falserocketmq.customized.trace.topic:rocketmq.access.channel:rocketmq.subscribe.filter:# rabbitMQ consumerrabbitmq.host:rabbitmq.virtual.host:rabbitmq.username:rabbitmq.password:rabbitmq.resource.ownerId:srcDataSources:defaultDS:url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=trueusername: canalpassword: canal123canalAdapters:- instance: example # canal instance Name or mq topic namegroups:- groupId: g1outerAdapters:- name: logger- name: es8hosts: https://192.168.100.183:9200 # 127.0.0.1:9200 for rest modeproperties:mode: rest  # transport or restsecurity.ca.path: C:\Users\znak\Desktop\elasticsearch.crtsecurity.ssl.verification_mode: none  # ✅ 忽略 SSL 证书验证security.auth: elastic:rwfejTWwHo666BmrQ2QW #  only used for rest modecluster.name: es-cluster

注意这里有个elasticsearch.crt证书要配置,我的Canal是部署在window本地的,es开启了ssl认证,canal adapter(客户端)需要有这个证书才能访问,【这里虽然我配置了忽略ssl验证,但是发现没效果)

cmd执行:

#生成证书
echo -n | openssl s_client -connect https://192.168.100.182:9200 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > elasticsearch.crt
#导入到Java 信任库
keytool -importcert -alias elasticsearch-cert -keystore "E:\xuyue\jre1.8\lib\security\cacerts" -file "C:\Users\znak\Desktop\elasticsearch.crt"

canal.adapter-1.1.8\conf\es8\sys_notice.yml

这个是同步mysql的相关配置,本文以若依的通知表sys_notice演示,所以这里配置的是这个表的sql,可以参考一下

dataSourceKey: defaultDS
destination: example
esMapping:_index: sys_notice_type: _doc_id: notice_idupsert: truesql: "SELECT sn.notice_id as id, sn.notice_id, sn.notice_title, sn.notice_type, CONVERT(sn.notice_content USING utf8mb4) AS notice_content, sn.status, sn.create_time, sn.update_time,sn.remark,sn.create_by,sn.update_by FROM sys_notice sn"commitBatch: 3000

启动canal后,默认是增量同步,如果原先数据表里已经有数据,想要先同步到es,可以手动调用全量同步接口,如下所示:

curl http://127.0.0.1:8081/etl/es8/sys_notice.yml -X POST

在这里插入图片描述

三、集成到SpringBoot

1.新增依赖

ruoyi-system/pom.xml

        <dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>8.1.0</version><exclusions><exclusion><artifactId>jakarta.json-api</artifactId><groupId>jakarta.json</groupId></exclusion><exclusion><artifactId>elasticsearch-rest-client</artifactId><groupId>org.elasticsearch.client</groupId></exclusion></exclusions></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-client</artifactId><version>8.1.0</version><scope>compile</scope></dependency><dependency><groupId>jakarta.json</groupId><artifactId>jakarta.json-api</artifactId><version>2.1.2</version></dependency><dependency><groupId>jakarta.json.bind</groupId><artifactId>jakarta.json.bind-api</artifactId><version>3.0.0</version></dependency><!--官方文档中如果遇到ClassNotFouind:jakarta.json.spi.JsonProvider,就需要导入这个包--><dependency><groupId>org.glassfish</groupId><artifactId>jakarta.json</artifactId><version>2.0.1</version></dependency>

2.es配置类

ElasticsearchConfig.java

package com.ruoyi.system.config;import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;@Configuration
public class ElasticsearchConfig {@Beanpublic ElasticsearchClient elasticsearchClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {// 认证信息BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "rwfejTWwHo666BmrQ2QW"));// 创建不验证证书的 SSLContextSSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true)  // 信任所有证书.build();// 创建 RestClientRestClientBuilder builder = RestClient.builder(new HttpHost("192.168.100.182", 9200, "https"),new HttpHost("192.168.100.183", 9200, "https"),new HttpHost("192.168.100.184", 9200, "https")).setHttpClientConfigCallback(httpClientBuilder ->httpClientBuilder.setSSLContext(sslContext).setDefaultCredentialsProvider(credentialsProvider));// 创建 Elasticsearch Java API ClientRestClient restClient = builder.build();RestClientTransport transport = new RestClientTransport(restClient, new co.elastic.clients.json.jackson.JacksonJsonpMapper(new ObjectMapper()));return new ElasticsearchClient(transport);}}

3.建立索引

索引创建是一个一次性操作,这里我直接建了一个测试类来创建

注意:

  • 这里字段我用的下划线格式,但是实体类里的是驼峰,所以后续需要手动映射下;同时注意数据库同步到es的时候,字段也要注意映射关系
  • 需要模糊查询的用text类型,并选择合适的分词器
  • 日期这里我加了yyyy-MM-dd’T’HH:mm:ssXXX这种类型,是因为我用canal同步mysql到es的时候,日期格式一直是这种格式(虽然mysql是yyyy-MM-dd HH:mm:ss)
    @Testvoid testIndexExample() throws IOException {//1.创建索引String indexName = "sys_notice";//检查索引是否已存在BooleanResponse exists = client.indices().exists(c -> c.index(indexName));//如果存在,则删除索引if (exists.value()) {client.indices().delete(c -> c.index(indexName));} else {// 创建索引// 设置索引配置CreateIndexResponse createIndexResponse = client.indices().create(c -> c.index(indexName).settings(s -> s.numberOfShards("1").numberOfReplicas("1")).mappings(m -> m.properties("notice_id", p -> p.keyword(k -> k)).properties("notice_title", p -> p.text(t -> t.analyzer("ik_max_word"))).properties("notice_type", p -> p.keyword(k -> k)).properties("notice_content", p -> p.text(t -> t.analyzer("ik_max_word"))).properties("status", p -> p.keyword(k -> k)).properties("create_by", p -> p.keyword(k -> k)).properties("create_time", p -> p.date(d -> d.format("yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ssXXX||epoch_millis"))).properties("update_by", p -> p.keyword(k -> k)).properties("update_time", p -> p.date(d -> d.format("yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ssXXX||epoch_millis"))).properties("remark", p -> p.text(t -> t.analyzer("ik_smart")))));if (Boolean.TRUE.equals(createIndexResponse.acknowledged())) {System.out.println("索引 " + indexName + " 创建成功");} else {System.out.println("索引 " + indexName + " 创建失败");}}}

索引建好我们可以用kibana来查看

GET /sys_notice

在这里插入图片描述

4.修改查询方法

com.ruoyi.system.service.impl.SysNoticeServiceImpl


@Resource
private ElasticsearchClient client;/*** 查询公告列表* * @param notice 公告信息* @return 公告集合*/
@Override
public List<SysNotice> selectNoticeList(SysNotice notice)
{Integer pageNum = Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1);Integer pageSize = Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10);SysNoticeOfES noticeOfES = new SysNoticeOfES();BeanUtils.copyBeanProp(noticeOfES, notice);noticeOfES.setNotice_title(notice.getNoticeTitle());noticeOfES.setCreate_by(notice.getCreateBy());noticeOfES.setNotice_type(notice.getNoticeType());List<SysNoticeOfES> noticesFromEs = searchNoticesFromEs(noticeOfES, pageNum, pageSize);if (noticesFromEs != null && noticesFromEs.size() > 0) {//转化为List<SysNotice>return noticesFromEs.stream().map(noticeOfES1 -> {SysNotice sysNotice = new SysNotice();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");BeanUtils.copyBeanProp(sysNotice, noticeOfES1);sysNotice.setNoticeId(noticeOfES1.getId());sysNotice.setNoticeTitle(noticeOfES1.getNotice_title());sysNotice.setCreateBy(noticeOfES1.getCreate_by());sysNotice.setUpdateBy(noticeOfES1.getUpdate_by());sysNotice.setNoticeContent(noticeOfES1.getNotice_content());sysNotice.setNoticeType(noticeOfES1.getNotice_type());try {sysNotice.setCreateTime(sdf.parse(sdf.format(noticeOfES1.getCreate_time())));sysNotice.setUpdateTime(noticeOfES1.getUpdate_time() != null ? sdf.parse(sdf.format(noticeOfES1.getUpdate_time())) : null);} catch (ParseException e) {e.printStackTrace();throw new GlobalException("日期转换异常");}sysNotice.setUpdateBy(noticeOfES1.getUpdate_by());return sysNotice;}).collect(Collectors.toList());} else {System.out.println("从数据库中查询");return noticeMapper.selectNoticeList(notice);}
}private List<SysNoticeOfES> searchNoticesFromEs(SysNoticeOfES notice, int pageNum, int pageSize) {try {// 计算 ES 分页参数int from = (pageNum - 1) * pageSize;// 构建 ES 查询SearchRequest request = new SearchRequest.Builder().index("sys_notice") // ES 索引名称.query(q -> q.bool(b -> {if (notice.getNotice_title() != null) {b.must(m -> m.match(t -> t.field("notice_title").query(notice.getNotice_title()).fuzziness("AUTO")));}if (notice.getCreate_by() != null) {b.must(m -> m.wildcard(t -> t.field("create_by").value("*" + notice.getCreate_by() + "*")));}if (notice.getNotice_type() != null) {b.must(m -> m.term(t -> t.field("notice_type").value(notice.getNotice_type())));}return b;})).highlight(h -> h.fields("notice_title", hf -> hf.preTags("<span style='color:red;'>")  // 高亮前缀.postTags("</span>")).requireFieldMatch(false)).from(from).size(pageSize).build();// 执行查询SearchResponse<SysNoticeOfES> response = client.search(request, SysNoticeOfES.class);// 解析结果return response.hits().hits().stream().map(hit -> {SysNoticeOfES sysNoticeOfES = hit.source();  // 获取原始的 SysNotice 数据if (hit.highlight() != null && hit.highlight().containsKey("notice_title")) {// 从 highlight 中获取高亮的内容,假设只有一个高亮值assert sysNoticeOfES != null;sysNoticeOfES.setNotice_title(hit.highlight().get("notice_title").get(0));  // 更新 noticeTitle 为高亮文本}return sysNoticeOfES;  // 返回更新后的 SysNotice}).collect(Collectors.toList());} catch (Exception e) {e.printStackTrace();return new ArrayList<>();}
}

requireFieldMatch(false)是指允许模糊查询高亮

fuzziness("AUTO")表示:

  • 如果查询词 ≤ 2 个字符,不允许错别字。
  • 如果查询词 3~5 个字符,允许 1 个错别字。
  • 如果查询词 ≥ 6 个字符,允许 2 个错别字。

上面的查询用es语法相当于(用下图的参数为例):

在这里插入图片描述

GET /sys_notice/_search
{"query": {"bool": {"must": [{"match": {"notice_title": {"query": "若一集成es","fuzziness": "AUTO"}}},{"wildcard": {"create_by": {"value": "*ad*"}}},{"term": {"notice_type": "1"}}]}},"highlight": {"fields": {"notice_title": {"pre_tags": ["<span style='color:red;'>"],"post_tags": ["</span>"]}},"require_field_match": false},"from": 0,"size": 10
}

在kibana执行的结果:

{"took": 3,"timed_out": false,"_shards": {"total": 1,"successful": 1,"skipped": 0,"failed": 0},"hits": {"total": {"value": 3,"relation": "eq"},"max_score": 3.1798086,"hits": [{"_index": "sys_notice","_id": "10","_score": 3.1798086,"_source": {"notice_title": "测试若依集成es","notice_type": "1","notice_content": "<p>一条测试通知</p>","status": "0","create_time": "2025-03-13T10:39:09+08:00","update_time": null,"remark": null,"create_by": "admin","update_by": "","id": 10},"highlight": {"notice_title": ["测试<span style='color:red;'>若</span>依<span style='color:red;'>集成</span><span style='color:red;'>es</span>"]}},{"_index": "sys_notice","_id": "11","_score": 2.9974954,"_source": {"notice_title": "测试若依与es集成-3","notice_type": "1","notice_content": "<p>111</p>","status": "0","create_time": "2025-03-13T10:39:52+08:00","update_time": null,"remark": null,"create_by": "admin","update_by": "","id": 11},"highlight": {"notice_title": ["测试<span style='color:red;'>若</span>依与<span style='color:red;'>es</span><span style='color:red;'>集成</span>-3"]}},{"_index": "sys_notice","_id": "2","_score": 1.4532554,"_source": {"notice_title": "维护通知:2018-07-01 若依系统凌晨维护","notice_type": "1","notice_content": "维护内容","status": "0","create_time": "2024-04-30T11:53:10+08:00","update_time": null,"remark": "管理员","create_by": "admin","update_by": "","id": 2},"highlight": {"notice_title": ["维护通知:2018-07-01 <span style='color:red;'>若</span>依系统凌晨维护"]}}]}
}

com.ruoyi.system.domain.SysNoticeOfES

package com.ruoyi.system.domain;import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.BaseEntityOfES;
import com.ruoyi.common.xss.Xss;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;/*** 通知公告表 sys_notice* * @author ruoyi*/
public class SysNoticeOfES extends BaseEntityOfES
{private static final long serialVersionUID = 1L;/** 公告ID */private Long id;/** 公告标题 */private String notice_title;/** 公告类型(1通知 2公告) */private String notice_type;/** 公告内容 */private String notice_content;/** 公告状态(0正常 1关闭) */private String status;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getNotice_title() {return notice_title;}public void setNotice_title(String notice_title) {this.notice_title = notice_title;}public String getNotice_type() {return notice_type;}public void setNotice_type(String notice_type) {this.notice_type = notice_type;}public String getNotice_content() {return notice_content;}public void setNotice_content(String notice_content) {this.notice_content = notice_content;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}
}

com.ruoyi.common.core.domain.BaseEntityOfES

package com.ruoyi.common.core.domain;import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** Entity基类* * @author ruoyi*/
public class BaseEntityOfES implements Serializable
{private static final long serialVersionUID = 1L;/** 搜索值 */@JsonIgnoreprivate String searchValue;/** 创建者 */private String create_by;/** 创建时间 */@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")private Date create_time;/** 更新者 */private String update_by;/** 更新时间 */@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")private Date update_time;/** 备注 */private String remark;/** 请求参数 */@JsonInclude(JsonInclude.Include.NON_EMPTY)private Map<String, Object> params;public String getSearchValue(){return searchValue;}public void setSearchValue(String searchValue){this.searchValue = searchValue;}public String getCreate_by() {return create_by;}public void setCreate_by(String create_by) {this.create_by = create_by;}public Date getCreate_time() {return create_time;}public void setCreate_time(Date create_time) {this.create_time = create_time;}public String getUpdate_by() {return update_by;}public void setUpdate_by(String update_by) {this.update_by = update_by;}public Date getUpdate_time() {return update_time;}public void setUpdate_time(Date update_time) {this.update_time = update_time;}public String getRemark() {return remark;}public void setRemark(String remark) {this.remark = remark;}public Map<String, Object> getParams(){if (params == null){params = new HashMap<>();}return params;}public void setParams(Map<String, Object> params){this.params = params;}
}

四、修改前端

最后,前端要修改table的展示,使其能够识别html标签,实现关键字高亮显示的效果

ruoyi-ui/src/views/system/notice/index.vue

<el-table-columnlabel="公告标题"align="center"prop="noticeTitle":show-overflow-tooltip="true"><template slot-scope="scope"><span v-html="scope.row.noticeTitle"></span>  <!-- 允许 HTML 高亮显示 --></template>
</el-table-column>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/35294.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

麒麟系统使用-安装 SQL Developer

文章目录 前言一、基础准备1.基本环境2.相关包下载 二、进行相关配置1.配置JAVA2.配置SQL Developer 总结 前言 作为我国自主研发的操作系统&#xff0c;麒麟系统在使用时需要考虑安装相应的app。尽管麒麟系统是基于linux开发&#xff0c;可由于版本的一些差异&#xff0c;麒麟…

PrimeTime:timing_report_unconstrained_paths变量

相关阅读 PrimeTimehttps://blog.csdn.net/weixin_45791458/category_12900271.html?spm1001.2014.3001.5482 PrimeTime自Q-2019.12版本起引入了timing_report_unconstrained_paths变量&#xff08;默认值为false&#xff09;&#xff0c;该变量控制是否在使用report_timing命…

洛谷 P1115 最大子段和(前缀和详解)c++

题目链接&#xff1a;P1115 最大子段和 - 洛谷 1.题目分析 2.算法原理 解法&#xff1a;利用前缀和 思考&#xff1a;如何求出以a[i]为结尾的所有子区间中最大的子段和 假设 i 等于5&#xff0c;以 a[ i ] 为结尾的区间一共是五段&#xff08;黑色线条部分&#xff09;&#…

JetBrains(全家桶: IDEA、WebStorm、GoLand、PyCharm) 2024.3+ 2025 版免费体验方案

JetBrains&#xff08;全家桶: IDEA、WebStorm、GoLand、PyCharm&#xff09; 2024.3 2025 版免费体验方案 前言 JetBrains IDE 是许多开发者的主力工具&#xff0c;但从 2024.02 版本起&#xff0c;JetBrains 调整了试用政策&#xff0c;新用户不再享有默认的 30 天免费试用…

【数据分析】数据筛选与访问行列元素3

访问元素 .loc属性可以通过传入index的值访问行数据。 .loc属性允许传入两个参数&#xff0c;分别是index的值和columns的值&#xff0c;参数间用“逗号”隔开&#xff0c;这样便可以访问数据中的元素。 1. 访问单个元素 访问单个元素比较简单&#xff0c;只需要通过它的in…

C++ std::list超详细指南:基础实践(手搓list)

目录 一.核心特性 1.双向循环链表结构 2.头文件&#xff1a;#include 3.时间复杂度 4.内存特性 二.构造函数 三.list iterator的使用 1.学习list iterator之前我们要知道iterator的区分 ​编辑 2.begin()end() 3.rbegin()rend() 四.list关键接口 1.empty() 2. size…

【免费】2004-2017年各地级市进出口总额数据

2004-2017年各地级市进出口总额数据 1、时间&#xff1a;2004-2017年 2、来源&#xff1a;城市年鉴 3、指标&#xff1a;进出口贸易总额 4、范围&#xff1a;286个地级市 5、指标说明&#xff1a;进出口总额是指一个国家在特定时期内&#xff08;通常为一年&#xff09;所…

谈谈 undefined 和 null

*** 补充 null 和 ‘’

【第15届蓝桥杯】软件赛CB组省赛

个人主页&#xff1a;Guiat 归属专栏&#xff1a;算法竞赛真题题解 文章目录 A. 握手问题&#xff08;填空题&#xff09;B. 小球反弹&#xff08;填空题&#xff09;C. 好数D. R格式E. 宝石组合F. 数字接龙G. 爬山H. 拔河 正文 总共8道题。 A. 握手问题&#xff08;填空题&…

【计算机视觉】工业表计读数(2)--表计检测

1. 简介 工业表计&#xff08;如压力表、电表、气表等&#xff09;在工控系统、能源管理等领域具有重要应用。然而&#xff0c;传统人工抄表不仅工作量大、效率低&#xff0c;而且容易产生数据误差。近年来&#xff0c;基于深度学习的目标检测方法在工业检测中展现出极大优势&…

提示词工程(Prompt Engineering)

https://www.bilibili.com/video/BV1PX9iYQEry 一、懂原理&#xff0c;要知道 为什么有的指令有效&#xff0c;有的指令无效为什么同样的指令有时有效&#xff0c;又是无效怎么提升指令有效的概率 大模型应用架构师想什么&#xff1f; 怎样能更准确&#xff1f;答&#xff1…

从Instagram到画廊:社交平台如何改变艺术家的展示方式

从Instagram到画廊&#xff1a;社交平台如何改变艺术家的展示方式 在数字时代&#xff0c;艺术家的展示方式正在经历一场革命。社交平台&#xff0c;尤其是Instagram&#xff0c;已经成为艺术家展示作品、与观众互动和建立品牌的重要渠道。本文将探讨社交平台如何改变艺术家的…

Typora 使用教程(标题,段落,字体,列表,区块,代码,脚注,插入图片,表格,目录)

标题 一个#是一级标题, 2个#是二级标题, 以此类推, 最多可达六级标题 示例 输入#号和标题后回车即可 注意: #和标题内容之间需要存在空格(一个或多个均可), 没有空格就会变成普通文字 标题快捷键 Ctrl数字 1-6 可以快速调成对应级别的标题 (选中文本/把光标放在标题上再按…

关于deepseek R1模型分布式推理效率分析

1、引言 DeepSeek R1 采用了混合专家&#xff08;Mixture of Experts&#xff0c;MoE&#xff09;架构&#xff0c;包含多个专家子网络&#xff0c;并通过一个门控机制动态地激活最相关的专家来处理特定的任务 。DeepSeek R1 总共有 6710 亿个参数&#xff0c;但在每个前向传播…

力扣hot100二刷——二叉树

第二次刷题不在idea写代码&#xff0c;而是直接在leetcode网站上写&#xff0c;“逼”自己掌握常用的函数。 标志掌握程度解释办法⭐Fully 完全掌握看到题目就有思路&#xff0c;编程也很流利⭐⭐Basically 基本掌握需要稍作思考&#xff0c;或者看到提示方法后能解答⭐⭐⭐Sl…

网络安全 --- 基于网络安全的 Linux 最敏感目录及文件利用指南

目录 基于网络安全的 Linux 最敏感目录及文件利用指南 Linux 中最敏感的目录及文件 1. /etc 2. /root 3. /var/log 4. /proc 5. /tmp 6. /home 7. /boot 8. /dev 如何利用这些敏感文件 你可能没想到的知识点 总结 Linux 中最敏感的目录及文件 1. /etc 存放内容&a…

深入浅出:Java实现斐波那契数列的七种武器与性能调优指南

​​​ 引言:当数学之美邂逅算法之力 斐波那契数列——这个诞生于13世纪的数学瑰宝,在计算机科学中焕发出新的生命力。作为递归与动态规划的经典案例,它不仅是算法入门的必修课,更是性能优化的试金石。本文将带您深入探索Java实现斐波那契数列的七种核心方法,并揭秘不同…

音视频入门基础:RTP专题(17)——音频的SDP媒体描述

一、引言 在《音视频入门基础&#xff1a;RTP专题&#xff08;3&#xff09;——SDP简介》中对SDP协议进行了简介&#xff0c;以H.264为例介绍了视频的SDP的媒体描述。本文对该文章进行补充&#xff0c;以AAC为例&#xff0c;讲述音频的SDP媒体描述。 二、文档下载 《RFC 364…

MyBatis-Plus防全表更新与删除插件BlockAttackInnerInterceptor

防全表更新与删除插件 BlockAttackInnerInterceptor 是 MyBatis-Plus 框架提供的一个安全插件&#xff0c;专门用于防止恶意的全表更新和删除操作。该插件通过拦截 update 和 delete 语句&#xff0c;确保这些操作不会无意中影响到整个数据表&#xff0c;从而保护数据的完整性…

嵌入式开发之STM32学习笔记day06

基于STM32F103C8T6的开发实践——从入门到精通01 1. 引言 STM32系列微控制器是STMicroelectronics推出的一款高性能、低功耗的32位微控制器&#xff0c;广泛应用于嵌入式系统中。STM32F103C8T6是其中非常受欢迎的一款&#xff0c;凭借其强大的性能、丰富的外设接口和低廉的价格…