手把手带你做项目2:搜索引擎(附源码)

2023-11-14

1、项目介绍:

(1)认识搜索引擎:

在这里插入图片描述
比如火狐浏览器的搜索引擎就包括:百度谷歌

在这里插入图片描述
先观察,百度搜索引擎的搜索结果页中,包含了若干条结果,每一个结果中,又包含了图标,标题,描述,展示url,时间,子链,图片等。

搜索引擎的本质

  • 输入一个查询词,得到若干搜索结果,每个搜索结果包含了标题、描述、展示url和点击url

(2)搜索的核心思想:

当前我们有很多网页(假设上亿个),每个 网页 我们称为是一个 文档

如何高效进行检索?查找出有哪些网页是和查询词具有一定的相关性呢?

  • 我们可以认为,网页中包含了查询词(或者查询词的一部分),就认为具有相关性

解决方案

① 方案一 : 暴力搜索

每次处理搜索请求时,拿着查询词去所有的网页中搜索一遍,检查每个网页是否包含查询词字符串。。。

显然,这个方案的开销非常大,并且随着文档数量的增多,这样的开销会线性增长,是一种不适合的搜索方案。

② 方案二 : 倒排索引

(这是一种专门针对搜索引擎场景而设计的数据结构)

  • 文档(doc):被检索的 html 页面(经过预处理)
  • 正排索引:“一个文档包含了哪些词”。描述一个文档的基本信息,包括文档标题,文档正文,文档标题和正文分词(断句结果)
  • 倒排索引:“一个词被哪些文档引用了”。描述了一个词的基本信息,包括了词都被哪些文档引用,这个词在该文档的重要程度,以及这个词的出现位置等。

(3)项目的目标:

实现一个 Java API 文档的简单的搜索引擎

2、项目准备:

项目全部源码(项目配置) GitHub 链接:
https://github.com/JACK-QBS/Project

代码框架如下:
在这里插入图片描述
简单介绍一下:
java包 下的代码是我们的 后端 代码,用来响应来自前端的请求和与数据库的交互;
webapp包 下的代码是我们的 前端 代码,即用户界面的设计。

(1)需要的资源:

Maven、IDEA、Chrome浏览器、Fiddler4抓包工具(可使用浏览器自带的开发者工具)

(2)创建web项目:

具体创建步骤和环境配置:

https://blog.csdn.net/qq_45658339/article/details/112249187

这个项目中 pop.xml 的配置源码放到 GitHub 中:

https://github.com/JACK-QBS/Project

3、开发步骤:

(1)创建三个 JavaBean 公共模块

1、每一个本地 html 文件对应一个文档对象(文档对应的结构)

public class DocInfo {
    private Integer id;//类似数据库主键(识别不同文档)
    private String title;//标题:html文件名作为标题
    private String url; //oracle官网api文档下html的url
    private String content;//网页正文:<标签>内容</标签>,内容为正文
}

2、倒排索引 Map<String,List>中,关键词对应的信息

public class Weight {
    private DocInfo doc;
    private int weight;//权重值:通过标题和正文中,关键词的数量计算
    private String keyword;//关键词
}

3、返回结果集对象

public class Result {
    //合并文档,排序用
    private Integer id;//docInfo的id,文档合并时,文档身份的标识
    private int weight;//权重:同一个文档合并后,权限相加,再排序
    //返回给前端用
    private String title;//文档(docInfo)的标题
    private String url;//文档(docInfo)的url
    private String desc;//docInfo的content(超长时,截取指定长度)
}

(2)预处理:解析本地 html 文件

遍历 api 目录下所有的文件, 并读取每个文件的内容, 把所有文件整理成一个行文本文件( 每行对应一个 html)

每一个 文件 转化为 DocInfo 对象:

  • ① url : 官网url的前缀 + 本地 api 目录下 html 文件的相对路径
  • ② title : 简单处理为文件名
  • ③ 内容:输入流读取html内容(不读取标签本身,读取标签内容)

输出流保存到 本地 raw_data.txt 文件中

public class Parser {
    //api目录
    public static final String API_PATH = "D:\\Code\\Project\\docs\\api";
    //构建的本地文件正排索引
    public static final String RAW_DATA = "D:\\Code\\Project/raw_data.txt";
    //官方api文档的根路径(拼接本地api路径)
    public static final String API_BASE_PATH = "https://docs.oracle.com/javase/8/docs/api";

    public static void main(String[] args) throws IOException {
        //找到api本地路径下所有的html文件
        List<File> htmls = listHtml(new File(API_PATH));
        FileWriter fw = new FileWriter(RAW_DATA);
        PrintWriter pw = new PrintWriter(fw,true); //打印输出流,自动刷新缓冲区
        for (File html : htmls) {
            //一个html解析DocInfo有的属性(输入)
            DocInfo doc = parseHtml(html);
            //保存本地正排索引文件(输出)(行号代表id)
            //格式:一行为一个doc,title+\3 + url + content
            String uri = html.getAbsolutePath().substring(API_PATH.length());
            System.out.println("Parse: "+uri);
            if(doc.getTitle().contains("�")){
                System.out.println("title====================="+doc.getTitle());
            }
            if(doc.getContent().contains("�")){
                System.out.println("content====================="+doc.getContent());
            }
            pw.println(doc.getTitle()+"\3"+doc.getUrl()+"\3"+doc.getContent());
        }
    }

    private static DocInfo parseHtml(File html) {
        DocInfo doc = new DocInfo();
        //ArrayList.html长度-5
        doc.setTitle(html.getName().substring(0,html.getName().length()-".html".length()));
        //获取相对路径
        String uri = html.getAbsolutePath().substring(API_PATH.length());
        doc.setUrl(API_BASE_PATH + uri);
        doc.setContent(parseContent(html));
        //目前是从本地api目录的html文件解析为文档对象,这步不需要设置id
        return doc;
    }

    /**
     * 解析 html 内容
     * <标签>内容</标签>
     * 只取内容,有多个标签就拼接
     */
    private static String parseContent(File html) {
        StringBuilder sb = new StringBuilder();
        try {
            FileReader fr = new FileReader(html);
            int i;
            boolean isContent = false;//判断是标签还是内容
            //一个字符一个字符来读取
            while ((i = fr.read()) != -1) {
                char c = (char) i;
                if (isContent) {
                    if (c == '<') {
                        //当前标签的内容读取结束   <标签>内容<
                        isContent = false;
                        continue;
                    } else if (c == '\n' || c == '\r') { // 换行符 \r\n
                        sb.append(" ");
                    } else {
                        sb.append(c);//拼接标签内容
                    }
                } else if (c == '>'){
                    //当前不是正文,并且读取到>,之后就是正文   <标签
                    isContent = true;
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sb.toString();
    }

    //递归遍历html文件(根据传入的目录)
    private static List<File> listHtml(File dir) {
        List<File> list = new ArrayList<>();
        //列出目录中的子文件和子文件夹
        File[] children = dir.listFiles();
        if (children != null) {
            for (File child : children) {
                if (child.isDirectory()) {
                    //若是子文件夹:递归调用获取子文件夹内的html文件
                    list.addAll(listHtml(child));
                } else if (child.getName().endsWith(".html")) {
                    list.add(child);
                }
            }
        }
        return list;
    }
}

(3)构建索引:

  • 正排索引:从本地文件数据中读取到 java 内存(类似于数据库保存的数据),从本地 raw_data.txt 中读取并保存

  • 倒排索引:构建 Map<String,List<信息>>(类似数据库 hash 索引)
    map键:关键词(分词来做)
    map值: 信息:

    • (1) docInfo 对象引用或是 docInfo 的 id
    • (2) 权重(标题对应的关键词数量10 + 正文对应关键词数量1)(自定义)
    • (3) 关键词
  • 正排转倒排:

    • (1)分词操作
    • (2)List,Map操作
    • (3)遍历每一个DocInfo对象,对标题和内容分词,遍历临时保存的Map,保存到倒排
public class Index {

    //正排索引:
    private static final List<DocInfo> FORWARD_INDEX = new ArrayList<>();
    //倒排索引:
    private static final Map<String,List<Weight>> INVERTED_INDEX = new HashMap<>();

    /**
     * 构建正排索引的内容:从本地 raw_data.txt 中读取并保存
     */
    public static void buildForwardIndex() {
        try {
            FileReader fr = new FileReader(Parser.RAW_DATA);
            BufferedReader br = new BufferedReader(fr);
            int id = 0;//行号设置为 docInfo 的 id
            String line;
            while ((line = br.readLine()) != null) {
                if (line.trim().equals("")) continue;
                //一行对应一个 DocInfo 对象,类似数据库一行数据对应Java对象
                DocInfo doc =  new DocInfo();
                doc.setId(++id);
                //行文本文件每一行中有三列, 用 \3 分割. 分别是标题, url, 正文.
                String[] parts = line.split("\3");//每一行按 \3 间隔符切开
                doc.setTitle(parts[0]);
                doc.setUrl(parts[1]);
                doc.setContent(parts[2]);
                //添加到正排索引
                System.out.println(doc);
                FORWARD_INDEX.add(doc);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 构建倒排索引:从java内存中正排索引获取文档来构建
     */
    public static void buildInvertedIndex() {
        for (DocInfo doc : FORWARD_INDEX) {//doc+分词 对应 weight(doc和分词一对多,分词和weight一对一)
            //一个doc,分别对标题和正文分词,每一个分词生成一个weight对象,需要计算权重
            //如标题为:清华大学/计算机/专业/使用/计算机/炒菜
            //第一次出现的关键词,要new Weight对象,之后出现相同分词关键词时
            // 要获取之前已经拿到的相同关键词weight对象,再更新权重(把自己的权限加进去)
            //实现逻辑:先构造一个HashMap,保存分词(键)和weight对象(value)
            Map<String,Weight> cache = new HashMap<>();

            //标题 分词遍历处理
            List<Term> titleFenCis = ToAnalysis.parse(doc.getTitle()).getTerms();
            for (Term titleFenCi : titleFenCis) {
                Weight w = cache.get(titleFenCi.getName());//获取标题分词键对应的weight
                //如果没有,就创建一个并放到map中
                if (w == null) {
                    w = new Weight();
                    w.setDoc(doc);
                    w.setKeyword(titleFenCi.getName());
                    cache.put(titleFenCi.getName(),w);
                }
                //标题分词,权重就+10
                w.setWeight(w.getWeight()+10);
            }

            //正文 分词遍历处理
            List<Term> contentFenCis = ToAnalysis.parse(doc.getContent()).getTerms();
            for (Term contentFenCi : contentFenCis) {
                Weight w = cache.get(contentFenCi.getName());//获取标题分词键对应的weight
                //如果没有,就创建一个并放到map中
                if (w == null) {
                    w = new Weight();
                    w.setDoc(doc);
                    w.setKeyword(contentFenCi.getName());
                    cache.put(contentFenCi.getName(),w);
                }
                //正文分词,权重就+1
                w.setWeight(w.getWeight()+1);
            }

            //把临时保存的map数据(keyword-weight)全部保存到倒排索引
            for (Map.Entry<String,Weight> e : cache.entrySet()) {
                String keyword = e.getKey();
                Weight w = e.getValue();
                //更新保存到倒排索引 Map<String,List<Weight>> --> 多个文档,同一个关键词,保存在一个List
                //先在倒排索引中,通过keyword获得已有的值
                List<Weight> weights = INVERTED_INDEX.get(keyword);
                //如果拿不到,就创建一个,并存放到倒排索引
                if (weights == null) {
                    weights = new ArrayList<>();
                    INVERTED_INDEX.put(keyword,weights);
                }
                //System.out.println(keyword+": ("+w.getDoc().getId()+", "+w.getWeight()+") ");
                weights.add(w);//倒排中,添加当前文档每个分词对应的weight对象
            }
        }
    }

    //通过关键词(分词)在倒排中查找映射的文档(多个文档,倒排拉链)
    public static List<Weight> get(String keyword) {
        return INVERTED_INDEX.get(keyword);
    }

    public static void main(String[] args) {
        Index.buildForwardIndex();
        //测试倒排内容是否正确
        for (Map.Entry<String,List<Weight>> e : INVERTED_INDEX.entrySet()) {
            String keyword = e.getKey();
            System.out.print(keyword+": ");
            List<Weight> weights = e.getValue();
            weights.stream()
                    .map(w->{//map操作:把list中每一个对应转换为其他对象
                        return "("+w.getDoc().getId()+", "+w.getWeight()+")";
                    })//转换完,会变成List<String>
                    .forEach(System.out::print);
            System.out.println();
        }
    }
}

(4)搜索模块

在这里插入图片描述

  • (1)根据搜索内容,进行分词,遍历每个分词
  • (2)每个分词,在倒排中查找对应的文档(一个分词对应多个文档)
  • (3)一个文档转换为一个Result(不同分词可能存在相同的文档,需要合并)
  • (4)合并完成后,对List排序:权重降序排序
  • (5)设置响应体内容
//根据前端请求路径,定义后端服务路径,loadOnStartup属性表示是否在启动时初始化(默认-1启动不初始化,第一次请求初始化)
@WebServlet(value = "/search",loadOnStartup = 0)
public class SearchServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        //初始化工作:先构建正排索引,再根据正排索引构建倒排
        Index.buildForwardIndex();
        Index.buildInvertedIndex();
        System.out.println("init complete!");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json");//ajax请求,响应json格式
        //构造返回给前端的内容:使用对象,之后再序列化为json字符串
        Map<String,Object> map = new HashMap<>();
        //解析请求数据
        String query = req.getParameter("query");//搜索框内容
        List<Result> results = new ArrayList<>();
        try {
            //根据搜索内容处理搜索业务
            //校验请求数据:搜索内容
            if (query == null || query.trim().length() == 0) {
                map.put("ok",false);
                map.put("msg","搜索内容为空");
            } else {
                //1、根据搜索内容,进行分词,遍历每个分词
                for (Term t : ToAnalysis.parse(query).getTerms()) {
                    String fenci = t.getName();//搜索的分词
                    //2、每个分词,在倒排中查找对应的文档(一个分词对应多个文档)
                    List<Weight> weights = Index.get(fenci);
                    //3、一个文档转换为一个Result(不同分词可能存在相同的文档,需要合并)
                    for (Weight w : weights) {
                        //转换weight为result
                        Result r = new Result();
                        r.setId(w.getDoc().getId());
                        r.setTitle(w.getDoc().getTitle());
                        r.setWeight(w.getWeight());
                        r.setUrl(w.getDoc().getUrl());
                        //文档内容超过60的部分隐藏为...
                        String content = w.getDoc().getContent();
                        r.setDesc(content.length()<=150 ? content : content.substring(0,60)+"...");
                        results.add(r);
                    }
                }
                //4、合并完成后,对List<Result>排序:权重降序排序
                results.sort(new Comparator<Result>() {
                    @Override
                    public int compare(Result o1, Result o2) {
                        return Integer.compare(o2.getWeight(),o1.getWeight());//权重降序
                    }
                });
                map.put("ok",true);
                map.put("data",results);
            }
        }catch (Exception e) {
            e.printStackTrace();
            map.put("ok",false);
            map.put("msg","未知的错误");
        }
        PrintWriter pw = resp.getWriter();//获取输出流
        //设置响应体内容:map对象序列化为json字符串
        pw.println(new ObjectMapper().writeValueAsString(map));
    }
}

(5)前端

前端页面结构比较简单, 只要包含一个输入框和一个按钮即可.

创建一个 index.html. 这个就不说了吧, 直接发给大家:

https://github.com/JACK-QBS/Project/blob/master/%E9%A1%B9%E7%9B%AE2%EF%BC%9A%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/src/main/webapp/index.html

4、测试:

运行程序:
在这里插入图片描述

当不输入搜索内容时:
在这里插入图片描述

随便输入一个 Java 中的 API

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手把手带你做项目2:搜索引擎(附源码) 的相关文章

  • 抖音短视频seo源码开发部署-技术分享(四)

    一 抖音短视频seo源码开发流程 抖音短视频SEO源码开发流程如下 1 分析需求 首先需要明确你的SEO目标 分析竞争对手 了解抖音短视频平台的规则 选定目标关键词和主题 2 编写代码 根据需求编写代码 并将其集成到你的应用程序或网站中 3
  • WEB-7-多线程

    多线程 一 背景 二 认识线程 Thread 1 理解 2 进程和线程的区别 高频面试题 3 使用代码创建多线程 三 线程的相关操作 1 创建线程 1 方法一 继承 Thread 类 2 方法二 实现 Runnable 接口 3 其它方法
  • 学姐去微软了

    这篇文章是我邀请在微软工作的学姐写的 最近正好是金九银十校招季 所以我邀请学姐写下当年她面试时的一些经验 希望对大家有帮助 自我介绍 烤冷面 女 hitCS专业本 硕 2018年之前没有PM实习经验 2018年暑期实习拿到腾讯和微软的PM岗
  • 能力成熟度模型集成(CMMI)

    实施CMMI意义 质量和进度 能保证软件开发的质量与进度 能对 杂乱无章 无序管理 的项目开发过程进行规范 成功控制 因为质量有所保证 浪费在修改 解决客户的抱怨方面的成本降低很多 绩效管理水平 公司通过过程改进 简历财富库以共享经验 而不
  • 基于AJAX技术提高搜索引擎排名

    描述 嵌入在你的web页面中的导航元素能够降低你的搜索引擎评价排名并且降低你的网站的响应性能 本文作者想同你一起探讨如何使用AJAX技术来解决这两个问题 许多设计良好的web站点都包含大量的与实际内容相联系的可导航信息 用于导航的HTML标
  • ElasticSearch ES 安装 常见错误 Kibana安装 设置 权限 密码

    最近在学习ES数据库 所以将一些东西记录一下 以下所有的都是基于es7 8 0版本进行的 下载安装ES数据库 安装本体 下载地址 linux mac os windows es的安装非常简单 基本都是解压然后运行就行了 这里我们就以linu
  • JAVA-WEB项目中,前后台结合AES和RSA对数据加密处理

    实际项目中为了系统安全 我们经常需要对请求数据和响应数据做加密处理 这里以spring后台 vue前台的java web为例 记录一个实现过程 一 为什么要结合AES和RSA 因为AES是对称加密 即加密解密用的秘钥是一样 这样一来AES的
  • Sping之自动注入-1

    最近终于能静下心来 一步步的学习Java Web开发 在学习的过程中 遇到太多的问题 一开始好些问题真是不知道怎么解决 在这里要非常感谢 Sping In Action 一书的作者 感谢他能写出此书 让我受益匪浅 您辛苦了 本着 相互学习
  • Spring容器和应用上下文理解

    有了Spring之后 通过依赖注入的方式 我们的业务代码不用自己管理关联对象的生命周期 业务代码只需要按照业务本身的流程 走啊走啊 走到哪里 需要另外的对象来协助了 就给Spring说 我想要个对象 于是Spring就很贴心的给你个对象 听
  • mysql不是内部或外部命令,也不是可运行的程序 或批处理文件。

    安装Mysql后 当我们在window r中输入cmd中敲入mysql时会出现 Mysql 不是内部或外部命令 也不是可运行的程序或其处理文件 打开我的电脑在我的电脑右键中选择属性 然后单击选择高级系统设置 在系统属性的 高级 中选择环境变
  • 敏捷项目管理ACP解析会笔记

    互联网时代企业环境现状 产品生命周期急剧缩短 市场环境变化太快 客户不满意 客户 团队 产品 产品需求界定不清 什么是敏捷项目管理 低成本 快速度 高质量 交付更高质量 敏捷宣言 个体和交互 重于过程和工具 可工作的软件 重于面面俱到的文档
  • 《时代》评出100位AI领域最具影响力人物,黄仁勋、马斯克、萨姆·奥特曼在列...

    编辑 腾讯科技 郝博阳 郭晓静 翻译 金鹿 在过去的一个世纪里 时代 杂志的封面反映了塑造社会的力量 今年也是如此 生成式人工智能 Generative AI 无疑是今年最受关注的重塑社会的力量 我现在看到的创新水平比我一生中见过的要强几个
  • Jina 2.0 快速入门指"北"

    What Why 选择Jina的4大理由 支持所有数据类型 大规模索引和查询任何类型的非结构化数据 视频 图像 长文本 语音 源代码 PDF等 速度极快 云原生 从第一天开始 Jina就是分布式架构 具有可扩展和云原生的设计 支持容器 并行
  • 利用Apache Tika分页解析pdf文件内容

    Apache Tika 实现pdf文档分页提取内容 Apache Tika是一个多功能的文档内容提取工具 可以提取多种类型的文档内容 常用的如pdf office等格式 网上的例子基本上都是提取整篇文档内容 实际上用Tika提取pdf等文档
  • GraphQL 实现原理,不要被表象骗了

    GraphQL 实现原理 及实例 GraphQL是一种用于API的查询语言和运行时环境 它提供了一种描述数据的方式 客户端可以根据需要进行精确地获取所需的数据 下面是GraphQL的实现原理 类型系统 Type System GraphQL
  • [杂谈] 乙方甲方交互的另一个例子

    之前有讨论 电信公司与设备供应商之间的一个甲乙关系 杂谈 甲方乙方的一个交互例子 https mzhan017 blog csdn net article details 135004416 其实作为供应商自己来说 其内部也有自己的乙方 比
  • 项目进度管理:项目经理把控项目进度的技巧

    到项目后期 加班越发频繁 今天我们得加班完成这点工作了 这是在项目里我们听到最多的一句话 王嘉在公司好几年 也参与了几个项目 由于他各方面出色表现 公司分配给他一个小项目 初次成为项目经理的他信心满满 他觉得这不是一件难事 每天只需要监督好
  • 【神器】wakatime代码时间追踪工具

    文章目录 wakatime简介 支持的IDE 安装步骤 API文档 插件费用 写在最后 wakatime简介 wakatime就是一个IDE插件 一个代码时间追踪工具 可自动获取码编码时长和度量指标 以产
  • 「实战应用」如何用DHTMLX Gantt构建类似JIRA式的项目路线图(一)

    DHTMLX Gantt 是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表 可满足项目管理应用程序的所有需求 是最完善的甘特图图表库 在web项目中使用DHTMLX Gantt时 开发人员经常需要满足与UI外观相关的各种需求 因此他
  • 「实战应用」如何用DHTMLX Gantt构建类似JIRA式的项目路线图(二)

    DHTMLX Gantt 是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表 可满足项目管理应用程序的所有需求 是最完善的甘特图图表库 在web项目中使用DHTMLX Gantt时 开发人员经常需要满足与UI外观相关的各种需求 因此他

随机推荐

  • 【牛客刷题专栏】0x32:JZ45 把数组排成最小的数(C语言编程题)

    前言 个人推荐在牛客网刷题 点击可以跳转 它登陆后会保存刷题记录进度 重新登录时写过的题目代码不会丢失 个人刷题练习系列专栏 个人CSDN牛客刷题专栏 题目来自 牛客 题库 在线编程 剑指offer 目录 前言 问题描述 解法思路 代码结果
  • 数字信号带宽讲解

    引言 在学习和工作中 经常和数字信号打交道 但是经常会接触到数字信号的带宽 对于这一概念 我理解的并不是很透彻 所以今天来抽丝剥茧 把这一概念彻底理解清楚 内容引申 要理解数字信号带宽 就先要了解信号的上升时间 上升时间 上升时间的概念 任
  • Win定时任务更新SVN库

    找到计算机管理 右击任务计划程序库 gt 创建基本任务 填写好名称和描述 NEXT NEXT NEXT 这里选择好svn exe 参数配置成 update D your dictionary NEXT 设置属性 选择触发器 gt 编辑 设置
  • 修改docker容器中文件(配置文件)

    背景 在使用docker搭建hadoop时需要修改docker容器里的文件 不想装ubutu所以在容器里用不了vim命令修改文件 1 查看所有容器名称和基本信息 docker ps 2 查看某个容器信息 docker inspect 容器名
  • 了解数据库的作用、特点及关系型数据库管理系统

    学习目标 能够知道数据库的作用数据库和数据库管理系统的关系 一 数据库 1 数据库的介绍 数据库就是存储和管理数据的仓库 数据按照一定的格式进行存储 用户可以对数据库中的数据进行增加 修改 删除 查询等操作 2 数据库的分类 关系型数据库
  • 干货渗透测试面试题汇总

    干货 渗透测试面试题汇总 以下为信息安全各个方向涉及的面试题 星数越多代表问题出现的几率越大 没有填答案是希望大家如果不懂能自己动手找到答案 祝各位都能找到满意的工作 注 做这个List的目标不是全 因为无论如何都不可能覆盖所有的面试问题
  • c++,父类引用指向子类对象,虚函数

    include
  • 还不错的全民采矿小程序源码+代码已开源

    正文 还不错的全民采矿小程序源码 代码已开源 可配合流量主和激励视频 程序是单开版的 一个站点只能单个平台使用此应用 一个小程序使用此应用 下方图片是小程序工具介绍 下方是程序介绍 程序 lanzou com iRgwE04a5d0d 图片
  • 基于嵌入式Linux/Qt 开发RFID智能仓储指纹管理系统

    基于嵌入式Linux Qt 开发RFID智能仓储指纹管理系统 Qt 是一个用于桌面系统和嵌入式开发的跨平台应用程序框架 它包括一个直观的API和一个丰富的类库 以及用于GUI开发和国际化的集成工具 另外它支持Java 和C 开发 利用它 我
  • AIX下装unzip和gzip

    做个标注 AIX下安装oracle需要解压zip文件 所以需要安装unzip文件包 首先确定aix里有没有rpm rte包 lslpp l grep i rpm rte 如果没有的话需要用aix安装盘安装这个包 我的系统里现在有这个包了 就
  • Deque与Stack实现栈的区别

    使用Deque 允许两头都进 两头都出 这种队列叫双端队列 Double Ended Queue 简称Deque Java集合提供了接口Deque来实现一个双端队列 它的功能 既可以添加到队尾 也可以添加到队首 既可以从队首获取 又可以从队
  • Cloudstack常用端口(Ports used by CloudStack)

    Cloudstack常用端口 Ports used by CloudStack 管理服务器 8080 主界面 授权API端口 8096 用户 客户端连接CS管理端 不可靠的 8787 CloudStack Tomcat debug sock
  • 华为OD机试真题- 基站维修工程师【2023Q1】【JAVA、Python、C++】

    题目描述 小王是一名基站维护工程师 负责某区域的基站维护 某地方有n个基站 1
  • vue中pc端大屏怎么进行rem适配(lib-flexible + postcss-pxtorem)

    使用 插件 lib flexible 和 postcss pxtorem 进行是适配 一共是两个步骤 当我们在进行适配的时候 如果只将当前屏幕分成几份的话 那么在后面写样式的时候 样式的单位需要写成rem 但是这里我们在进行完 postcs
  • 多线程与高并发

    volatile CAS 无锁优化 Unsafe Synchronized volatile CAS Atomic gt CAS LongAdder 使用的分段锁 increment gt Sync Atomic LongAdder Ree
  • ios 微信小程序 chooseImage 相机拍照跳转页面崩溃

    问题描述 功能需求 拍照或选择图片 然后跳转页面裁剪上传头像 一开始使用 chooseImage 本人的小小安卓机和测试的ios手机都是没有问题的 后来同事的 iphone 13 mini 一试拍照跳转页面就崩溃了 一开始一筹莫展还在各处搜
  • angular入门

    架构模式 MVC gt MVP gt MVVM angular cli angular cli angular脚手架 一键构建angular项目 常用指令 ng help 查看所有指令 ng new projectName 创建angula
  • kafka实践(一):Kafka入门经典教程(转贴)

    原blog 地址 http blog csdn net hmsiwtv article details 46960053 问题导读 1 Kafka独特设计在什么地方 2 Kafka如何搭建及创建topic 发送消息 消费消息 3 如何书写K
  • java图书管理系统(IO流)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 基本结构 一 图书信息管理 1 book类 2 booklist类 1 add 2 query 3 sort 4 change 5 delete 6 write 和
  • 手把手带你做项目2:搜索引擎(附源码)

    Java API 文档搜索引擎 1 项目介绍 1 认识搜索引擎 2 搜索的核心思想 3 项目的目标 2 项目准备 1 需要的资源 2 创建web项目 3 开发步骤 1 创建三个 JavaBean 公共模块 2 预处理 解析本地 html 文