Elastic Search(ES)Java 入门实操(2)搜索代码

news2024/11/22 20:51:39

上篇解释了 ES 的基本概念和分词器。Elastic Search (ES)Java 入门实操(1)下载安装、概念-CSDN博客

Elastic Search(ES)Java 入门实操(3)数据同步-CSDN博客

这篇主要演示 Java 整合 ES进行数据搜索。

ES 实现搜索接口

首先根据 MySQL 字段,在 ES 创建索引。

create table mydb
(
    id          int auto_increment comment '序号'
        primary key,
    title       varchar(20)                        not null comment '标题',
    content     text                               not null comment '内容',
    cretateTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    updateTime  datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    isDelete    tinyint  default 0                 not null comment '是否删除'
)
    comment '文章' collate = utf8mb4_unicode_ci;
PUT article_1
{
  "aliases": {  #别名
    "article": {}
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text", #字段类型
        "analyzer": "ik_max_word",#插入时分词方式
        "search_analyzer": "ik_smart", #查询时分词方式
        "fields": { #字段配置,子字段
          "keyword": { 
            "type": "keyword", #精确匹配
            "ignore_above": 256 #超过 256 字符就忽略查询
          }
        }
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "createTime": {
        "type": "date"
      },
      "updateTime": {
        "type": "date"
      },
      "isDelete": {
        "type": "keyword"
      }
    }
  }
}

引入 spring-data-elasticsearch 依赖

需要注意版本号一定要兼容

Spring Data Elasticsearch - Reference Documentation

这里使用的是 7.17版本,所以选择相近的 4.4.x版本的 依赖,同样的 springboot 的版本也得严格对应。Maven Repository: org.springframework.data » spring-data-elasticsearch » 4.4.7 (mvnrepository.com)

 下面的报错就是版本不对,需要把springboot 改为 2.7+,

java.lang.NoSuchFieldError: INDEX_CONTENT_TYPE
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-elasticsearch -->
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>4.4.7</version>
</dependency>

启动 springboot,有调用的日志

给 ES 索引创建实体类 

/**
 * ES 实体类
 * document 注解是将Java 对象映射到 Elasticsearch 索引和类型中
 */
@Document(indexName = "article")
@Data
public class ArticleEsDto implements Serializable {
    private static final String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    /**
     * id
     * 需要打上 id 注解,指定 ES 中存储的 id 是唯一字段
     * 如果新增是不传入,则 ES 会自动生成
     */
    @Id
    private long id;
    /**
     * 标题
     */
    private String title;

    /**
     * 内容
     */
    private String content;

    /**
     * 创建时间
     */
    @Field(index = false, store = true,type = FieldType.Date,format = {},pattern = DATE_TIME_PATTERN)
    private Date createTime;

    /**
     * 更新时间
     * Field:这是一个MyBatis-Plus注解,用于标注该字段在数据库表中的对应关系。
     * 其中,index = false表示该字段不在数据库表的索引中,
     * store = true表示该字段在数据库表的存储中,
     * type = FieldType.Date表示该字段的类型为Date,
     * format = {}表示该字段的格式为空,
     * pattern = DATE_TIME_PATTERN表示该字段的日期时间格式为DATE_TIME_PATTERN。
     */
    @Field(index = false, store = true,type = FieldType.Date,format = {},pattern = DATE_TIME_PATTERN)
    private Date updateTime;

    /**
     * 是否删除
     */
    private Integer isDelete;

    private static final long serialVersionUID = 1L;
}

第一种方式

elasticsearch Respository,新建类继承该类,默认提供了简单的增删改查方法,多用于可以预期的,相对不复杂的查询

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
    <S extends T> S save(S entity);

    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    Optional<T> findById(ID id);

    boolean existsById(ID id);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> ids);

    long count();

    void deleteById(ID id);

    void delete(T entity);

    void deleteAllById(Iterable<? extends ID> ids);

    void deleteAll(Iterable<? extends T> entities);

    void deleteAll();
}
/**
 * ES 的控制层
 * 继承 ElasticsearchRepository 即可
 */
public interface ArticleEsDao extends ElasticsearchRepository<ArticleEsDto, Long> {

    // 这里可以扩展一些自定义方法
    // 例如:根据标题模糊查询
    List<ArticleEsDto> findByTitle(String title);

}

新增测试

//注入接口
    @Resource
    private ArticleEsDao articleEsDao;
    
    //测试新增
    @Test
    void EsTest1(){
        //创建实体对象并添加属性
        ArticleEsDto articleEsDto = new ArticleEsDto();
        articleEsDto.setId(1L);
        articleEsDto.setTitle("青花瓷");
        articleEsDto.setContent("天青色等烟雨而我在等你");
        articleEsDto.setCreateTime(new Date());
        articleEsDto.setUpdateTime(new Date());
        articleEsDto.setIsDelete(0);
        //调用方法保存
        articleEsDao.save(articleEsDto);
        System.out.println(articleEsDto.getId());
    }

dev tools 查看

GET article/_search/

自定义方法测试

我们在上面创建接口的时候创建了一个根据标题查询的方法

    @Test
    void EsTest2(){
        List<ArticleEsDto> articleEsDtos = articleEsDao.findByTitle("青花瓷");
        System.out.println(articleEsDtos);
    }

 第二种方式

spring 默认提供了操作 ES 的客户端对象 ElasticSearchRestTemplate,同样提供了增删改查,更加灵活,适用于更加复杂的操作,返回结果更加完整,但是需要自己解析。

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

提示,在编写查询条件以及处理数据时,可以先在 Dev Tools 中执行一下查询,没问题之后再进行代码层面的条件编写。

查询 DSL

官方文档:Query and filter context | Elasticsearch Guide [8.14] | Elastic

查询模式:Boolean query | Elasticsearch Guide [8.14] | Elastic

GET /_search
{
  "query": {  
    "bool": {  //组合条件
      "must": [ //必须匹配
        { "match":  // 模糊匹配{ "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [ //
        { "term": //精确匹配 { "status": "published" }},
        { "range": //范围匹配 { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}

除了 must ,filter,还有 must_not,必须不存在才能匹配,should,至少有多少个条件相符才匹配,同时还有一个参数 minimum_should_match 满足最小的条件数,比如 1,至少满足一个条件才能查询到,比如标题和描述存在一个就可以返回结果。

POST _search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user.id" : "kimchy" }
      },
      "filter": {
        "term" : { "tags" : "production" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 20 }
        }
      },
      "should" : [
        { "term" : { "tags" : "env1" } },
        { "term" : { "tags" : "deployed" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

需要注意的是,通过模糊查询之后,查询结果中有一个参数是 max_score,表示这条数据和搜索条件的最高匹配度。

在 Java 中编写查询条件以及处理查询的数据。

主要使用到的 API

//查询条件构造器
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

//排序条件构造器
SortBuilder<?> sortBuilder = SortBuilders.scoreSort();

//分页
PageRequest pageRequest = PageRequest.of((int) current, (int) pageSize);

//组合查询条件
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest).withSorts(sortBuilder).build();
//调用 elasticsearchRestTemplate 查询
SearchHits<PostEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);

完整代码

/**
 * 从 es 查询数据
 */
@Service
public class ArticleEsManager {

    @Resource
    private ArticleMapper articleMapper;


    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    public Page<Article> searchByEs(ArticleQueryRequest articleQueryRequest) {
        //提取查询参数
        Long id = articleQueryRequest.getId();
        String searchText = articleQueryRequest.getSearchText();
        String content = articleQueryRequest.getContent();
        String title = articleQueryRequest.getTitle();
        //设置分页参数,起始页为 0
        int current = articleQueryRequest.getCurrent() -1 ;
        int pageSize = articleQueryRequest.getPageSize();
        String sortField = articleQueryRequest.getSortField();
        String sortOrder = articleQueryRequest.getSortOrder();
        //构建布尔查询,创建 boolqueryBuilder,用于后续查询条件构建
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //过滤查询条件
        //过滤掉被逻辑删除的 term 是精确匹配
        boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete",0));
        //id必须精确匹配
        if(id!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("id",id));
        }
        //模糊查询,按照查询词(关键词)检索
        if(StringUtils.isNotEmpty(searchText)){
            boolQueryBuilder.should(QueryBuilders.matchQuery("title",searchText));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content",searchText));
            //设置至少多少匹配才进行查询
            boolQueryBuilder.minimumShouldMatch(1);
        }
        //根据标题检索
        if(StringUtils.isNotEmpty(title)){
            boolQueryBuilder.should(QueryBuilders.matchQuery("title",title));
            boolQueryBuilder.minimumShouldMatch(1);
        }
        //根据内容检索
        if(StringUtils.isNotEmpty(content)){
            boolQueryBuilder.should(QueryBuilders.matchQuery("content",searchText));
            //设置至少多少匹配才进行查询
            boolQueryBuilder.minimumShouldMatch(1);
        }
        //进行排序
        //对查询结果的分数进行排序
        SortBuilder<?> sortBuilder = SortBuilders.scoreSort();
        if (StringUtils.isNotEmpty(sortField) && StringUtils.isNotEmpty(sortOrder)){
            sortBuilder = SortBuilders.fieldSort(sortField);
            sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC:SortOrder.DESC);
        }
        //分页
        PageRequest pageRequest = PageRequest.of(current, pageSize);
        //构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest).withSorts(sortBuilder).build();
        //调用 elasticsearchRestTemplate 执行查询
        SearchHits<ArticleEsDto> searchHits = elasticsearchRestTemplate.search(searchQuery, ArticleEsDto.class);
        System.out.println(searchHits);
        Page<Article> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());
        //新建集合存储文章
        List<Article> resourceList = new ArrayList<>();
        //处理结果,判断是否有搜索结果
        if(searchHits.hasSearchHits()){
            //获取结果列表
            List<SearchHit<ArticleEsDto>> searchHits1 = searchHits.getSearchHits();
            System.out.println(searchHits1);
            //获取结果的id,使用id在数据库中查询
            List<Long> ids = searchHits1.stream().map(searchHit -> searchHit.getContent().getId()).collect(Collectors.toList());
            List<Article> articles = articleMapper.selectBatchIds(ids);
            //将查询结果与数据库查询结果进行匹配
            if (CollectionUtils.isNotEmpty(articles)) {
                //将查询结果与数据库查询结果进行匹配
                Map<Long, List<Article>> collect = articles.stream().collect(Collectors.groupingBy(Article::getId));
                //遍历文章id
                articles.forEach(articleId -> {
                    if(collect.containsKey(articleId)){
                        resourceList.add(collect.get(articleId).get(0));
                    }else{
                        // 从 es 清空 db 已物理删除的数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(articleId), ArticleEsDto.class);
                    }
                });
            }
        }
        page.setRecords(resourceList);
        return page;
    }
}

成功查询到数据 

完整代码

/**
 * 从 es 查询数据
 */
@Service
public class ArticleEsManager {

    @Resource
    private ArticleMapper articleMapper;


    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;


    public Page<Article> searchByEs(ArticleQueryRequest articleQueryRequest) {
        //提取查询参数
        Long id = articleQueryRequest.getId();
        String searchText = articleQueryRequest.getSearchText();
        String content = articleQueryRequest.getContent();
        String title = articleQueryRequest.getTitle();
        //设置分页参数,起始页为 0
        int current = articleQueryRequest.getCurrent() -1 ;
        int pageSize = articleQueryRequest.getPageSize();
        String sortField = articleQueryRequest.getSortField();
        String sortOrder = articleQueryRequest.getSortOrder();
        //构建布尔查询,创建 boolqueryBuilder,用于后续查询条件构建
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //过滤查询条件
        //过滤掉被逻辑删除的 term 是精确匹配
        boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete",0));
        //id必须精确匹配
        if(id!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("id",id));
        }
        //模糊查询,按照查询词(关键词)检索
        if(StringUtils.isNotEmpty(searchText)){
            boolQueryBuilder.should(QueryBuilders.matchQuery("title",searchText));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content",searchText));
            //设置至少多少匹配才进行查询
            boolQueryBuilder.minimumShouldMatch(1);
        }
        //根据标题检索
        if(StringUtils.isNotEmpty(title)){
            boolQueryBuilder.should(QueryBuilders.matchQuery("title",title));
            boolQueryBuilder.minimumShouldMatch(1);
        }
        //根据内容检索
        if(StringUtils.isNotEmpty(content)){
            boolQueryBuilder.should(QueryBuilders.matchQuery("content",searchText));
            //设置至少多少匹配才进行查询
            boolQueryBuilder.minimumShouldMatch(1);
        }
        //进行排序
        //对查询结果的分数进行排序
        SortBuilder<?> sortBuilder = SortBuilders.scoreSort();
        if (StringUtils.isNotEmpty(sortField) && StringUtils.isNotEmpty(sortOrder)){
            sortBuilder = SortBuilders.fieldSort(sortField);
            sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC:SortOrder.DESC);
        }
        //分页
        PageRequest pageRequest = PageRequest.of(current, pageSize);
        //构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest).withSorts(sortBuilder).build();
        //调用 elasticsearchRestTemplate 执行查询
        SearchHits<ArticleEsDto> searchHits = elasticsearchRestTemplate.search(searchQuery, ArticleEsDto.class);
        System.out.println(searchHits);
        Page<Article> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());
        //新建集合存储文章
        List<Article> resourceList = new ArrayList<>();
        //处理结果,判断是否有搜索结果
        if(searchHits.hasSearchHits()){
            //获取结果列表
            List<SearchHit<ArticleEsDto>> searchHits1 = searchHits.getSearchHits();
            System.out.println(searchHits1);
            //获取结果的id,使用id在数据库中查询
            List<Long> ids = searchHits1.stream().map(searchHit -> searchHit.getContent().getId()).collect(Collectors.toList());
            List<Article> articleList = articleMapper.selectBatchIds(ids);
            //将查询结果与数据库查询结果进行匹配
            if (CollectionUtils.isNotEmpty(articleList)) {
                //将查询结果与数据库查询结果进行匹配
                Map<Long, List<Article>> collect = articleList.stream().collect(Collectors.groupingBy(Article::getId));
                //遍历文章id
                ids.forEach(articleId -> {
                    if(collect.containsKey(articleId)){
                        resourceList.add(collect.get(articleId).get(0));
                    }else{
                        // 从 es 清空 db 已物理删除的数据
                        String delete = elasticsearchRestTemplate.delete(String.valueOf(articleId), ArticleEsDto.class);
                    }
                });
            }
        }
        //设置到分页里
        page.setRecords(resourceList);
        return page;
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day 42 LVS四层负载均衡

一&#xff1a;负载均衡简介 1.集群是什么 ​ 集群&#xff08;cluster&#xff09;技术是一种较新的技术&#xff0c;通过集群技术&#xff0c;可以在付出较低成本的情况下获得在性能、可靠性、灵活性方面的相对较高的收益&#xff0c;其任务调度则是集群系统中的核心技术 …

PyTorch深度学习实战(44)——基于 DETR 实现目标检测

PyTorch深度学习实战&#xff08;44&#xff09;——基于 DETR 实现目标检测 0. 前言1. Transformer1.1 Transformer 基础1.2 Transformer 架构 2. DETR2.1 DETR 架构2.2 实现 DETR 模型 3. 基于 DETR 实现目标检测3.1 数据加载与模型构建3.2 模型训练与测试 小结系列链接 0. 前…

windows安装tensorboard

要在Windows系统上使用TensorBoard来可视化你的TensorFlow模型训练过程&#xff0c;请按照以下步骤进行操作&#xff1a; 安装TensorFlow和TensorBoard 安装Python&#xff1a; 确保你已经安装了Python。你可以从Python官方网站下载并安装最新版本的Python。 安装TensorFlow&…

kafka-重试和死信主题(SpringBoot整合Kafka)

文章目录 1、重试和死信主题2、死信队列3、代码演示3.1、appication.yml3.2、引入spring-kafka依赖3.3、创建SpringBoot启动类3.4、创建生产者发送消息3.5、创建消费者消费消息 1、重试和死信主题 kafka默认支持重试和死信主题 重试主题&#xff1a;当消费者消费消息异常时&…

基于思通数科大模型的设备隐患智能检测:图像处理与声音分析的融合应用

在现代工业生产中&#xff0c;设备的稳定运行对保障生产效率和产品质量至关重要。然而&#xff0c;设备的老化、磨损以及异常状态的检测往往需要大量的人力和物力。思通数科大模型结合图像处理技术和声音分析技术&#xff0c;为设备隐患检测提供了一种自动化、高效的解决方案。…

源码、反码和补码

对于有符号数而言&#xff0c;原码就是一个数的二进制表示。二进制的最高位是符号位&#xff0c;0 表示正数&#xff0c;1 表示负数。 计算机用数的原码进行显示&#xff0c;数的计算和存储是用补码进行的。 正数的原码&#xff0c;反码和补码都一样&#xff0c;即正数三码合…

Matching Anything by Segmenting Anything

摘要 在复杂场景中跨视频帧稳健地关联相同对象是许多应用的关键&#xff0c;特别是多目标跟踪&#xff08;MOT&#xff09;。当前方法主要依赖于标注的特定领域视频数据集&#xff0c;这限制了学习到的相似度嵌入的跨域泛化能力。我们提出了MASA&#xff0c;一种新颖的方法用于…

JavaScript 动态网页实例 —— 图像显示

图像是网页设计中必不可少的内容之一,而图像的显示方式更是关系到网站的第一印象。本章介绍图像的显示,主要包括:图片的随机显示、图像的显示和隐藏、图像的滚动显示、图像的探照灯扫描显示、多幅图像的翻页显示、图像的水纹效果显示、全景图效果显示手电照射效果显示以及雷达…

揭秘800G以太网——简介

什么是800G以太网&#xff1f; 800G以太网是一种高带宽以太网标准&#xff0c;每秒可传输800 Gbps&#xff08;千兆位每秒&#xff09;的数据速率。它代表了以太网技术的又一进步&#xff0c;旨在满足不断增长的数据传输需求以及处理大量数据的能力。因此&#xff0c;800G以太…

杰理AC632N提升edr的hid传输速率, 安卓绝对坐标触摸点被识别成鼠标的修改方法

第一个问题: 首先修改edr的hid传输速率.修改你的板级配置,里面的一个地方给注释掉了,请打开那个注释就能提升edr的hid传输效率了 第二个问题: 修改632n系别把触摸板的hid报告描述符识别成鼠标点,修改如下: 注释掉上面的pnp,改成下面的

RocketMQ的安装

首先到RocketMQ官网下载页面下载 | RocketMQ (apache.org)&#xff0c;本机解压缩&#xff0c;作者在这里用的是最新的5.2.0版本。按照如下步骤安装。 1、环境变量配置rocket mq地址 ROCKETMQ_HOME D:\rocketmq-all-5.2.0-bin-release 在变量path中添加”%ROCKETMQ_HOME%\bi…

04 架构核心技术之分布式消息队列

本课时的主题是分布式消息队列&#xff0c;分布式消息队列的知识结构如下图。 本课时主要介绍以下内容。 同步架构和异步架构的区别。异步架构的主要组成部分&#xff1a;消息生产者、消息消费者、分布式消息队列。异步架构的两种主要模型&#xff1a;点对点模型和发布订阅模型…

RandomDate(接口参数化-随机生成日期)

目录 1、入口位置&#xff1a;2、验证函数生成值3、获取 年月日时分秒 的全随机4、时间函数 前言&#xff1a;有时候我们做性能测试或者接口测试时&#xff0c;参数需要传入日期格式&#xff0c;但是又不想每次都是用同一个日期&#xff0c;我们就可以使用Jmeter工具中函数助手…

[MQTT]服务器EMQX搭建SSL/TLS连接过程(wss://)

&#x1f449;原文阅读 &#x1f4a1;章前提示 本文采用8084端口进行连接&#xff0c;是EMQX 默认提供了四个常用的监听器之一&#xff0c;如果需要添加其他类型的监听器&#xff0c;可参考官方文档&#x1f517;管理 | EMQX 文档。 本文使用自签名CA&#xff0c;需要提前在L…

三次谐波式发电机定子单相接地保护Simulink仿真

在用于接地保护的发电机定子回路的仿真模型的基础上增加三次谐波电动势,得到用于仿真三次谐波式接地保护的发电机定子回路的Simulink仿真模型,如图1所示。 图 1发电机定子回路的Simulink仿真模型 发电机端和中性点侧的三次谐波电压的获取采用如图2所示的方法。 图 2 …

校园生活服务平台的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;用户管理&#xff0c;跑腿管理&#xff0c;文娱活动管理&#xff0c;活动申请管理&#xff0c;备忘录管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff…

使用wheelnav.js构建酷炫的动态导航菜单

目录 前言 一、WheelNav是什么 1、项目地址 2、关于开源协议 3、相关目录介绍 二、如何使用wheelnav.js 1、新建html页面 2、设置style样式 3、创建展示元素实现动态导航 三、参数即方法介绍 1、参数列表 2、运行方法 3、实际成果 四、总结 前言 用户体验永远是一…

数据结构和算法一轮

前言 本文参考《2025年数据结构考研复习指导&#xff08;王道论坛组编&#xff09;》和相关文章&#xff0c;为考试前复习而写。 目录 前言 第一章线性表 1.1顺序表 1.2单链表 1.3循环链表 ​1.4双向链表 第二章栈和队列 2.1栈 2.2共享栈 2.3链栈 2.4队列 2.5循环…

大学生创新与创业搜题软件?推荐7个搜题软件和学习工具 #媒体#知识分享

随着大学课程的增多和知识的不断积累&#xff0c;大学生们常常面临着繁重的作业和复杂的题目。为了解决这一问题&#xff0c;许多大学生搜题软件应运而生。 1.彩虹搜题 这个是公众号 个性化推荐功能&#xff0c;精准满足需求。更高效地获取你想要的答案。 下方附上一些测试的…

项目质量保证措施(Word原件)

一、 质量保障措施 二、 项目质量管理保障措施 &#xff08;一&#xff09; 资深的质量经理与质保组 &#xff08;二&#xff09; 全程参与的质量经理 &#xff08;三&#xff09; 合理的质量控制流程 1&#xff0e; 质量管理规范&#xff1a; 2&#xff0e; 加强协调管理&…