小蚯蚓 - 默认分类
type: channel
link: https://xiaoqiuyinboke.cn/category/default/
description: 只是一个默认分类
items: GitHub Action Flow 使用
items: Mac 电脑的常见设置
items: 如何接入Google广告 - 完整教程
items: 建站技术 | 为自己的网站使用Google Analytics统计
items: Auth2.0原理介绍 | 权威指南
items: ODS到ADS详解：数仓分层策略与实践
items: Elasticsearch DSL基本使用：详细教程和最佳实践
items: TCP协议详解 | 网络通信的核心技术
items: ER 建模基础和进阶教程 | 掌握 ER 建模的关键概念
items: 进程与线程：详细理解

GitHub Action Flow 使用
type: item
date: 2026-01-25T21:19:14+08:00
description: 1. 创建 docker-image.yml 在项目目录底下，创建一个 .github/workflows 文件夹，然后创建一个 docker-image.yml 文件，内容如下: # https://docs.github.com/zh/actions/use-cases-and-examples/publishing-packages/publishing-docker-images name: Create and publish a Docker image # Configures this workflow to run every time a change is pushed to the branch called `release`. on: push: branches: ['main'] # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. jobs: build-and-push-image: runs-on: ubuntu-latest # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. permissions: contents: read packages: write attestations: write id-token: write # steps: - name: Checkout repository uses: actions/checkout@v4 # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # This step uses the `docker/build-push-action` action to build the image, based on your repos…

Mac 电脑的常见设置
type: item
date: 2026-01-06T22:09:00+08:00
description: 1. 修改修饰键 打开 Mac 系统偏好设置，进入 键盘选项，然后点击 修饰键，直接看图修改！ Mac 系统了 fn 键，一般无法重新映射 2. Funter 设置 2.1. 显示隐藏文件 选中访达，然后输入快捷键 command+shift+.即可 2.2. 左侧常驻家目录 设置里将这个勾选起来即可 3. 访达如何快速跳转到某个目录 只需要使用快捷键 command+shift+g即可 4. 禁止 F1-F12 功能键 有时候打游戏或者用专业软件快捷键是 F1~F12，，但 Mac 键盘直接按就是亮度音量之类的功能，还得按住 fn 才能实现 F1~12 的按键，挺不方便的。 设置路径：键盘/功能键，将开关开启来 5. 常用的 Brew 命令集 Brew（Homebrew）是一个强大的包管理器，用于在 macOS 上安装、更新和管理各种软件包。它使得在 Mac 上安装开发工具、应用程序和库变得轻松和便捷。本博客将介绍一些在 Mac 中常用的 Brew 命令，以帮助您更好地管理您的软件包。 安装 Homebrew，如果您还没有安装 Homebrew，您可以使用以下命令在 Mac 上进行安装： /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 5.1. 更新 Brew 定期更新 Brew 可以确保您拥有最新的软件包和版本： brew update 5.2. 搜索软件包 使用 Brew 可以轻松搜索需要的软件包，只需使用 search 命令： brew search package_name 例如，要搜索 Node.js： brew search node 5.3. 安装软件包 要安装软件包，使用 install 命令，并指定软件包的名称： brew install package_name 例如，要安装 Git： brew install git 5.4. 查看已安装的软件包 您可以使用 list 命令查看已经安装的软件包列表： brew list 5.5. 卸载软件包 如果您不再需要某个软件包，可以使用 uninstall 命令来卸载它： brew uninstall package_name 例如，要卸载 Git： brew uninstall git 5.6. 查看软件包信息 使用 info 命令可以查看有关软件包的详细信息，包括其依赖项和链接： brew info package_name 例如，要查看关于 Node.js 的信息： brew info node 5.7. 清理过期的软件包 定期清理不再需要的旧版本和无用的库文件可以释放磁盘空间： brew cleanup 5.8. 显示 Brew 版本信息 要查看 Brew 的版本信息，可以运行： brew --version 这将显示安装的 Brew 版本以及相关的信息。 5.9. 列出过时的软件包 使用 outdated 命令可以列出所有过时的软件包： brew outdated 5.10. 更新软件包 要更新 Brew 中的所有过时软件包，可以使用 upgrade 命令： brew upgrade 5.11. 安装 Cask 扩展 Brew Cask 是 Brew 的扩展，用于安装和管理 macOS 应用程序。您可以使用以下命令安装 Cask 扩展： brew tap homebrew/cask 5.12. 安装应用程序 使用 Brew Cask 可以轻松安装 macOS 应用程序。例如，要安装 Visual Studio Code： brew install --cask visual-studio-code 5.13. 查看软件包的依赖关系 要查看软件包的依赖关系，可以使用 deps 命令。这将列出软件包所依赖的其他软件包。例如： brew deps package_name 5.14. 查看软件包的可选依赖关系 有些软件包具有可选的依赖关系，可以使用 options 命令查看这些选项。例如： brew options package_name 5.15. 查看已安装软件包的版本历史 使用 versions 命令可以查看已安装软件包的版本历史。这将列出所有可用版本以及它们的安装状态。例如： brew versions package_name 5.16. 使用 Brew Cask 安装 GUI 应用程序 使用 Brew Cask 可以轻松安装 macOS GUI 应用程序。例如，要安装 Google Chrome： brew install --cask google-chrome 5.17. 查看 Brew 配置信息 要…

如何接入Google广告 - 完整教程
type: item
date: 2025-03-22T20:33:00+08:00
description: 1. 前言 前段时间花了一些精力尝试和摸索主题接入 Google Ads 的问题，算是阶段性成功了吧，这次简单分享一下，如果有缘看到这篇文章，应该会有些启发。 2. 展示效果 上篇文章说到，前两天我在我的两款主题中内置了 Google Ads 广告位，并且我自己的网站也启用了，下图是这两天的成果： 确实有点低，但起码是一个好的开始。当然，主要还是因为流量着实太低了，你如果有网站，肯定会比这个好得多得多，下面是今天早上截的图： 浏览量才 22，确实低的有点可怜，但万丈高楼平地起嘛，单纯从比例上看，还是可以的，不是吗？这还是没有人点击的结果。当然，这也和网站的质量、垂直度等有关，如果是泛泛地记录日常，价值含量比较低，单价可能会更低，而如果是知识性、科技性的，单价可能会很高。 如果你平时喜欢分享，也写公众号、技术博客之类的，把文章同步一份到自己的网站，难道不香吗？ 3. 如何起步 首先要有一个自己的专属网站，这个我个人博客的一系列文章中有完整的部署过程，也提供了内置 Google Ads 广告的主题，按照步骤来，我相信这个不是问题。 其次，就是需要一个 Google Ads 账号了。但由于我已经注册好了，很多操作步骤没办法重现，不过我是按照下面这个视频操作的，实测有效，大家可以参考： https://www.youtube.com/watch?v=ILR7n0dWRbo 本来一开始还想着，可能有些人访问不了 YouTube，但后来一想，如果连 YouTube 都不知道怎么访问，那看这篇文章可能也没多大意义吧。这个不能细说，我只能说网上有答案，GitHub 上也有免费开源的项目。 值得注意的是，视频中提到的需要设置成英文的地方，一定要设置成英文，否则可能收不到短信验证码，切记！ 4. 网站审批 网站部署完成，并且也注册了 Google Ads 账号之后，就需要提交你的网站审批申请了，通过后是下面这样的： 说起来简单，其实这里也是一个老大难问题，首先你的网站得看起来正规，至少得有 15篇以上的正经文章，并且没有测试页面，也就是说不是一个测试或正在建设中的网站。更重要的是，按官方说法，你的域名得注册满 6个月，但看很多朋友域名注册一两个月也通过了，可能是他们内容做的比较好吧？我就被拒了一次，几个月后的第二次才通过的。 审批申请比较简单，点击 新建网站 按要求填写即可，下面列出几个值得注意的点。 4.1. 验证方式 Google Ads 提供了三种验证方式： 我选用的是第二种 ads.txt 文件的方式，因为我觉得这种方式不需要改代码，侵入性最小，只需要将文件放置到站点根目录即可，如下图所示。 放置完成后，可以通过 https:\\你的域名\ads.txt 试试能否访问，并且，还要检查一下 robots.txt文件（如果有的话），确保没有被排除。接下来，就是等待审批了。 如果审批结果还是提示找不到文件，就可能需要手动检查一下，我就是所有环节都没问题，但还是提示找不到文件，通过手动检查才找到的，如下图这样： 另外两种方式也有其优点，比如就没有上面文件找不到的担心，并且也可以比较方便地集成到后台配置页面，用户不用关心站点目录在哪里了。 需要注意的是：因为 google 是检测 ads.txt 的时候是没有带 www 的，网站配置的时候要支持没有 www 也可以访问，不然会提示“找不到 ads.txt” 4.2. 子域名怎么办 以我自己为例，我有一个 ilaozhu.com 的博客网站，还有一个 nav.ilaozhu.com 导航网站，后面还可能会有其它 xxx.ilaozhu.com 网站，我一开始也搜了很多资料，各种说法都有，而且很多都是过时的答案，越看越迷糊。实际上，只要 ilaozhu.com 审核通过就可以了，其它子域名自动就通过了，不需要任何额外操作，如果子域名网站希望放置广告，只需要在其根目录放置 ads.txt 文件就可以了，Google Ads 会自动发现，统一管理的。 5. 放置广告 网站审批通过后就可以放置广告了，Google Ads 提供了两种方式：按网站和按广告单元。其中按网站，又细分为自动广告和非自动广告。 看似选择很多，但其实这些都不重要，我摸索了好久，最终选择了下面两个结合的方式，大家可以参考一下，如果有更好的方式，也欢迎给些意见。 5.1. 按网站 自动广告看似美妙，操作简单，不需要编写一行代码，而且谷歌自己也说会根据网站自适应。但实际上，效果并不好，我折腾了半天，最后还是选择了放弃，只保留了一个穿插广告，也就是页面切换的间隙弹出的广告，其它的都去掉了，如下图所示： 5.2. 按广告单元 广告单元也有很多种形式，但我们仅使用展示广告就可以了，其它的不用理会。 不管哪一种形式的广告单元，都需要修改代码，自己设置广…

建站技术 | 为自己的网站使用Google Analytics统计
type: item
date: 2025-03-15T19:06:00+08:00
description: 须知 你应当知晓：在中国大陆境内的服务器使用Google Analytics是不合法行为。 《中华人民共和国个人信息保护法》 第三十六条：国家机关处理的个人信息应当在中华人民共和国境内存储；确需向境外提供的，应当进行安全评估。安全评估可以要求有关部门提供支持与协助。 第三十九条：个人信息处理者向中华人民共和国境外提供个人信息的，应当向个人告知境外接收方的名称或者姓名、联系方式、处理目的、处理方式、个人信息的种类以及个人向境外接收方行使本法规定权利的方式和程序等事项，并取得个人的单独同意。 本教程仅适用于满足使用条件的网站，如果你在不满足使用条件的情况下参考本教程使用Google Analytics，本教程不承担任何责任。 是什么？为什么？怎么做？ 关于Google Analytics的详细介绍可以参考这位博主的文章：谷歌流量分析工具Google Analytics使用方法指南教程 本教程只记录步骤而省略一部分解释。 如何使用Google Analytics 注册一个Google账号（需要科学上网） 打开 Google Analytics官网（需要科学上网），点击开始衡量 开设账号 填自己的账号名 填写账号名 名称取自己好认的即可，时区和人民币按默认的。 取名 如实填写即可 行业与企业的填写 完成后点击创建，会弹出一个弹窗问你是否同意协议，勾选同意后选择我接受，完成账号创建 同意协议 完成后会自动跳转到刚刚新建的媒体源，选择平台为网站 选择平台 设置网站和数据流的名称，然后点击创建数据流，注意http和https不要选错，网站网址也不要写错 设置名称 接下来设置统计代码 在数据流详情页面点击查看代码说明 查看代码说明 如果是使用CMS来构建网站的话使用第一项可以快捷设置，这里我是静态网页，因此点击手动添加，然后点击代码块右上角复制代码 复制代码 将代码复制到你的网站源代码的 body 标签中 添加代码 重新部署至服务器，统计就会生效了 查看你的网站数据，具体面板详细介绍可以看谷歌流量分析工具Google Analytics使用方法指南教程，上面讲的很详细 至此，你已成功为你的网站使用了Google Analytics。 注意 根据官网：数据可能最多需要 24 小时才会显示在您的 Google Analytics（分析）帐号中。 我这边将近十分钟就有数据，如果你等太久也没有看到统计，建议F12检查一下统计代码是否生效。 附录 参考文献 中华人民共和国个人信息保护法 谷歌流量分析工具Google Analytics使用方法指南教程

Auth2.0原理介绍 | 权威指南
type: item
date: 2024-06-07T22:50:00+08:00
description: 简单解释 OAuth 2.0 是目前最流行的授权机制，用来授权第三方应用，获取用户数据。 这个标准比较抽象，使用了很多术语，初学者不容易理解。其实说起来并不复杂，下面我就通过一个简单的类比，帮助大家轻松理解，OAuth 2.0 到底是什么。 快递员问题 我住在一个大型的居民小区。 小区有门禁系统。 进入的时候需要输入密码。 我经常网购和外卖，每天都有快递员来送货。我必须找到一个办法，让快递员通过门禁系统，进入小区。 如果我把自己的密码，告诉快递员，他就拥有了与我同样的权限，这样好像不太合适。万一我想取消他进入小区的权力，也很麻烦，我自己的密码也得跟着改了，还得通知其他的快递员。 有没有一种办法，让快递员能够自由进入小区，又不必知道小区居民的密码，而且他的唯一权限就是送货，其他需要密码的场合，他都没有权限？ 授权机制的设计 于是，我设计了一套授权机制。 第一步，门禁系统的密码输入器下面，增加一个按钮，叫做"获取授权"。快递员需要首先按这个按钮，去申请授权。 第二步，他按下按钮以后，屋主（也就是我）的手机就会跳出对话框：有人正在要求授权。系统还会显示该快递员的姓名、工号和所属的快递公司。 我确认请求属实，就点击按钮，告诉门禁系统，我同意给予他进入小区的授权。 第三步，门禁系统得到我的确认以后，向快递员显示一个进入小区的令牌（access token）。令牌就是类似密码的一串数字，只在短期内（比如七天）有效。 第四步，快递员向门禁系统输入令牌，进入小区。 有人可能会问，为什么不是远程为快递员开门，而要为他单独生成一个令牌？这是因为快递员可能每天都会来送货，第二天他还可以复用这个令牌。另外，有的小区有多重门禁，快递员可以使用同一个令牌通过它们。 互联网场景 我们把上面的例子搬到互联网，就是 OAuth 的设计了。 首先，居民小区就是储存用户数据的网络服务。比如，微信储存了我的好友信息，获取这些信息，就必须经过微信的"门禁系统"。 其次，快递员（或者说快递公司）就是第三方应用，想要穿过门禁系统，进入小区。 最后，我就是用户本人，同意授权第三方应用进入小区，获取我的数据。 简单说，OAuth 就是一种授权机制。数据的所有者告诉系统，同意授权第三方应用进入系统，获取这些数据。系统从而产生一个短期的进入令牌（token），用来代替密码，供第三方应用使用。 令牌与密码 令牌（token）与密码（password）的作用是一样的，都可以进入系统，但是有三点差异。 （1）令牌是短期的，到期会自动失效，用户自己无法修改。密码一般长期有效，用户不修改，就不会发生变化。 （2）令牌可以被数据所有者撤销，会立即失效。以上例而言，屋主可以随时取消快递员的令牌。密码一般不允许被他人撤销。 （3）令牌有权限范围（scope），比如只能进小区的二号门。对于网络服务来说，只读令牌就比读写令牌更安全。密码一般是完整权限。 上面这些设计，保证了令牌既可以让第三方应用获得权限，同时又随时可控，不会危及系统安全。这就是 OAuth 2.0 的优点。 注意，只要知道了令牌，就能进入系统。系统一般不会再次确认身份，所以令牌必须保密，泄漏令牌与泄漏密码的后果是一样的。 这也是为什么令牌的有效期，一般都设置得很短的原因。 OAuth 2.0 对于如何颁发令牌的细节，规定得非常详细。具体来说，一共分成四种授权类型（authorization grant），即四种颁发令牌的方式，适用于不同的互联网场景。 四种授权方式 OAuth 2.0 的标准是 RFC 6749 文件。该文件先解释了 OAuth 是什么。 OAuth 引入了一个授权层，用来分离两种不同的角色：客户端和资源所有者。......资源所有者同意以后，资源服务器可以向客户端颁发令牌。客户端通过令牌，去请求数据。 这段话的意思就是，OAuth 的核心就是向第三方应用颁发令牌。然后，RFC 6749 接着写道： （由于互联网有多种场景，）本标准定义了获得令牌的四种授权方式（authorization grant ）。 也就是说，OAuth 2.0 规定了四种获得令牌的流程。你可以选择最适合自己的那一种，向第三方应用颁发令牌。下面就是这四种授权方式。 授权码（authorization-code） 隐藏式（implicit） 密码式（password）： 客户端凭证（client credentials） 注意，不管哪一种授权方式，第三方应用申请令牌之前，都必须先到系统备案，说明自己的身份，然后会拿到两个身份识别码：客户端 ID（client ID）和客户端密钥（client secret）。这是为了防止令牌被滥用，没有备案过的第三方应用，是不会拿到令牌的。 第一种授权方式：授权码 授权码（authorization code）方…

ODS到ADS详解：数仓分层策略与实践
type: item
date: 2024-02-19T22:25:00+08:00
description: 为什么要对数据仓库分层 只有数据模型将数据有序的组织和存储起来之后，大数据才能得到高性能、低成本、高效率、高质量的使用。 分层意义 清晰数据结构：每一个数据分层都有它的作用域，这样我们在使用表的时候能更方便地定位和理解。 数据溯源追踪：我们最终给业务提供的是一能直接使用的张业务表，但是它的来源有很多，如果有一张来源表出问题了，我们希望能够快速准确地定位到问题，并清楚它的危害范围。 数据复用，减少重复开发：规范数据分层，下层可以使用上层的一些数据。 把复杂问题简单化：将一个复杂的任务分解成多个步骤来完成，每一层只处理单一的步骤，比较简单和容易理解。 数据仓库（ETL）的四个操作 ETL (extraction transformation loading)负责将数据源中的数据抽取到临时中间层后进行清洗、转换、集成，最后加载到数据仓库或数据集市中。 ETL 是实施数据仓库的核心和灵魂，ETL 规则的设计和实施约占整个数据仓库搭建工作量的 60%～80%。 数据抽取 (extraction)：包括初始化数据装载和数据刷新：初始化数据装载主要关注的是如何建立表，并把相应的数据放到这些数据表中；而数据刷新关注的是当源数据发生变化时如何对数据仓库中的相应数据进行追加和更新等维护 (比如可以创建定时任务，或者触发器的形式进行数据的定时刷新)。 数据清洗：主要是针对源数据库中出现的二义性、重复、不完整、违反业务或逻辑规则等问题的数据进行统一的处理。即清洗掉不符合业务或者没用的的数据。比如通过编写 hive 或者 MR 清洗字段中长度不符合要求的数据。 数据转换 (transformation)：主要是为了将数据清洗后的数据转换成数据仓库所需要的数据：来源于不同源系统的同一数据字段的数据字典或者数据格式可能不一样 (比如 A 表中叫 id, B 表中叫 ids)，在数据仓库中需要给它们提供统一的数据字典和格式，对数据内容进行归一化；另一方面，数据仓库所需要的某些字段的内容可能是源系统所不具备的，而是需要根据源系统中多个字段的内容共同计算确定。 数据加载（loading）：是将最后上面处理完的数据导入到对应的存储空间里（hbase，mysql 等）以方便给数据集市提供，进而可视化。 一般大公司为了数据安全和操作方便，都是自己封装的数据平台和任务调度平台，底层封装了大数据集群比如 hadoop 集群，spark 集群，sqoop, hive, zookeepr, hbase 等只提供 web 界面，并且对于不同员工加以不同权限，然后对集群进行不同的操作和调用。 以数据仓库为例，将数据仓库分为逻辑上的几个层次。这样对于不同层次的数据操作，创建不同层次的任务，可以放到不同层次的任务流中进行执行（大公司一个集群通常每天的定时任务有几千个等待执行，甚至上万个，所以划分不同层次的任务流，不同层次的任务放到对应的任务流中进行执行，会更加方便管理和维护）。 分层的误区 数仓层内部的划分不是为了分层而分层，分层是为了解决 ETL 任务及工作流的组织、数据的流向、读写权限的控制、不同需求的满足等各类问题。 业界较为通行的做法将整个数仓层又划分成了 DWD、DWT、DWS、DIM、DM等很多层。然而我们却始终说不清楚这几层之间清晰的界限是什么，或者说我们能说清楚它们之间的界限，复杂的业务场景却令我们无法真正落地执行。 所以数据分层这块一般来说三层是最基础的，至于DW层如何进行切分，是根据具体的业务需求和公司场景自己去定义。 数据仓库的技术架构 技术架构，这部分了解即可 数据中台包含的内容很多，对应到具体工作中的话，它可以包含下面的这些内容： 系统架构：以Hadoop、Spark等组件为中心的架构体系 数据架构：顶层设计，主题域划分，分层设计，ODS-DW-ADS 数据建模：维度建模，业务过程-确定粒度-维度-事实表 数据管理：资产管理，元数据管理、质量管理、主数据管理、数据标准、数据安全管理 辅助系统：调度系统、ETL系统、监控系统 数据服务：数据门户、机器学习数据挖掘、数据查询、分析、报表系统、可视化系统、数据交换分享下载 数仓分层架构 数据仓库标准上可以分为四层。但是注意这种划分和命名不是唯一的，一般数仓都是四层，但是不同公司可能叫法不同。但是核心的理念都是从四层数据模型而来。 贴源层（ODS, Operational Data Store） 数据引入层（ODS，Operational Data Store，又称数据基础层）：将原始数据几乎无处理地存放在数据仓库系统中，结构上与源系统基本保持一致，是数据仓库的数据准备区。这一层的主要职责是将基础数据同步、存储。 一般来说 ODS 层的数据和源系统的数据是同构的，主要目的是简化后续数据加工处理的工作。从数据粒度上来说…

Elasticsearch DSL基本使用：详细教程和最佳实践
type: item
date: 2024-01-21T23:01:00+08:00
description: 查询 使用 from 和 size 分页查询，需要注意的是：from+size 要小于 10000，不然会报错 // 从第9条开始，查询100条 GET index_test/_search?from=9&size=100 // 这个也行 GET index_test/_search { "from":9, "size":100 } 查询某个 id: DE7BEo0BngUdM_im08lv GET index_test/_doc/DE7BEo0BngUdM_im08lv 查询结果不要元字段，只查询 _source，使用 _source api 加上 id GET index_test/_source/2 一次性查询多个 id 值 GET index_test/_mget { "ids":[1,2] } GET index_test/_search { "query":{ "ids": { "values":[1,2,4] } } } match match 搜索需要注意以下几点： 被查询字段必须是可以分词的，比如 name 字段必须是可以分词的，例如 text 类型。 搜索过程是：首先对搜索词进行分词，然后只要一个某个分词和被搜索字段的分词匹配上了，就满足。、 es 分词的时候，首先会对分词统一改成小写，所以不区分大小写了。 例如下例子中，name 字段必须是可以分词的字段，然后搜索词 小米手机，会被分词 GET index_test/_search { "query":{ "match": { "name": "小米手机" } } } 搜索词分词的时候，本身也会作为分词结果之一，例如 HuaWei Mate 9000 会作为一个特殊项，作为整体去匹配 GET index_test/_search { "query":{ "match": { "name.keyword": "HuaWei Mate 9000" } } } match_phrase 这个查询和 match 查询一样，不同点在于所有分词要按顺序都匹配上 会对搜索词进行分词 搜索词的分词必须全部匹配上，并且顺序也要相同，中间不能有其他词。 中间不能有其它词，不过这个可以通过 slop 配置允许多少个其他词，默认是 0 个。 例如下例中：搜索词 xiao mi 会被分词成 xiao、mi 两个单词。这两个单词去 name 的分词中搜索，如果 name 中有个 xiao mi 既可以被匹配上，如果 name 是 xiao x mi 就不能匹配上，因为中间有其他干扰词语。 GET index_test/_search { "query":{ "match_phrase": { "name": "xiao mi" } } } 可以通过 slop 参数配置干扰词的数量，例如下例中，slop=1，这样 name 是 xiao x mi 就能匹配上了 GET index_test/_search { "query":{ "match_phrase": { "name": { "query": "小米手机", "slop": 1 } } } } term 一般用于精确查询 不会对搜索词进行分词，会保留搜索词的所有属性，包括大小写，标点符号等。 被搜索字段一般是子字段 keyword（text 类型一般都有子字段，叫做 keyword，记录着原始信息，不过文本内容如果太长的话，就会忽略，导致搜索不到），或者其他不分词的字段 被搜索是可以分词的字段也是可以，需要和分词结果匹配上就行 下面例子中，Xiao mi shou ji 会作为整体去匹配，name 必须也是 Xiao mi shou ji 才可以被匹配上 GET index_test/_search { "query":{ "term": { "name.keyword": { "value": "Xiao mi shou ji" } } } } 如果想要一次搜索多个词，可以用 terms GET index_test/_search { "query":{ "terms": { "name.keyword": ["xiao mi shou ji","hua wei shou ji"] } } } range 只支持大于，大于等于，小于，小于等于 GET index_test/_search { "query":{ "range": { "age":{ "gte":10, "lte":20 } } } } bool 组合 组合查询，就是多条件查询，bool 里的每个条件自己是 and 关系。 must must 查询，定义多个必须同时满足的条件 GET index_test/_search { "_source":fase, …

TCP协议详解 | 网络通信的核心技术
type: item
date: 2023-12-30T11:10:31+08:00
description: tcp概述 TCP（Transmission Control Protocol）又叫传输控制协议，是面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接：一定是「一对一」才能连接，不能像 UDP 协议可以一个主机同时向多个主机发送消息，也就是一对多是无法做到的； 可靠的：无论的网络链路中出现了怎样的链路变化，TCP 都可以保证一个报文一定能够到达接收端； 字节流：用户消息通过 TCP 协议传输时，消息可能会被操作系统「分组」成多个的 TCP 报文，如果接收方的程序如果不知道「消息的边界」，是无法读出一个有效的用户消息的。并且 TCP 报文是「有序的」，当「前一个」TCP 报文没有收到的时候，即使它先收到了后面的 TCP 报文，那么也不能扔给应用层去处理，同时对「重复」的 TCP 报文会自动丢弃。 优点： 可靠，稳定。TCP的可靠性体现在传输数据之前，三次握手建立连接（四次挥手断开连接），并且在数据传递时，有确认，窗口，重传，拥塞控制机制，数据传完之后断开连接来节省系统资源。 应用场景： 对网络通信质量有要求时，比如：整个数据要准确无误的传递给对方，这往往对于一些要求可靠的应用，比如HTTP,HTTPS,FTP等传输文件的协议，POP,SMTP等邮件的传输协议，websocket协议等。 头部格式 我们先来看看 TCP 头的格式，标注颜色的表示与本文关联比较大的字段，其他字段不做详细阐述 序列号： 在建立连接时由计算机生成的随机数作为其初始值，通过 SYN 包传给接收端主机，每发送一次数据，就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。 确认应答号： 指下一次「期望」收到的数据的序列号，发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。 控制位： ACK（Acknowledge character即是确认字符）：该位为 1 时，「确认应答」的字段变为有效，TCP 规定除了最初建立连接时的 SYN 包之外该位必须设置为 1 。 RST：该位为 1 时，表示 TCP 连接中出现异常必须强制断开连接。 SYN（同步序列编号Synchronize Sequence Numbers）：该位为 1 时，表示希望建立连接，需要同步序列号，并在其「序列号」的字段进行序列号初始值的设定。 FIN：该位为 1 时，表示今后不会再有数据发送，希望断开连接。当通信结束希望断开连接时，通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。 3次握手4次挥手 一个可靠连接肯定会有以下三个过程：创建连接、 数据传输、 终止连接 创建连接 这里就是常说的‘三次握手’，其实完全可以用常识来理解这个过程，两个人之间如果想建立一个通信，至少需要有三次对话才能保证通信的可靠。举个栗子，相信大家打游戏的时候都跟队友语音过。 {timeline} {timeline-item color="#19be6b"} A：听得到吗？ 建立连接，客户端发送连接请求报文段，将SYN位置为1，Sequence Number为x；然后，客户端进入SYN_SEND状态，等待服务器的确认 {/timeline-item} {timeline-item color="#ed4014"} B：我听到了，你能听到我说话吗？ 服务器收到SYN报文段。服务器收到客户端的SYN报文段，需要对这个SYN报文段进行确认，设置Acknowledgment Number为x+1(Sequence Number+1)；同时，自己自己还要发送SYN请求信息，将SYN位置为1，Sequence Number为y；服务器端将上述所有信息放到一个报文段（即SYN+ACK报文段）中，一并发送给客户端，此时服务器进入SYN_RECV状态； {/timeline-item} {timeline-item color="#ed4014"} A：ok，我能听到~ 客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1，向服务器发送ACK报文段，这个报文段发送完毕以后，客户端和服务器端都进入ESTABLISHED状态，完成TCP三次握手。 {/timeline-item} {/timeline} 数据传输 {timeline} {timeline-item color="#19be6b"} A：我给你发个一堆东西，你按照顺序拼好 {/timeline-item} {timeline-item color="#ed4014"} B：收到了 发送的文件其实被拆成一个一个的小块，seq（Sequence Number）的作用是序列号，让服务器端能拼回来。 {/timeline-item} {/timeline} 终止…

ER 建模基础和进阶教程 | 掌握 ER 建模的关键概念
type: item
date: 2023-10-15T15:42:00+08:00
description: 概述 entity–relationship model (简称 ER Model) 用于描述特定知识领域中相互关联的事物，基本的 ER 模型由实体类型和他们之间的关系组成 一般我们在 ER 建模的时候，将实体类型简单的叫做实体。但是在技术角度来说，实体是抽象实体类型的实例，因为是具体实例，所以命名的时候，经常使用单数表示。 实体名称通常是大写的，虽然在这方面没有公认的标准，但是这是约定成俗的做法。 ER 模型中，用头尾带有乌鸦脚符号的线条来表示实体之间的关系。 关系 基本数量上的关系 ER 如下所示: erDiagram customer }|..|{ delivery_adress : "有多个地址" customer ||--|{ order : "有多个地址" order ||--|{ order_detail : "有订单明细" customer { int id PK "自增id" string name "客户姓名" } delivery_adress { int id PK "递增id" string adress "省市区" int created_time "创建时间" } order { int id PK "订单id" int customer_id FK "订单类型" int created_time "创建时间" } order_detail { int id PK "递增id" int order_id FK "订单id" int product_id "商品id" int product_num "商品数量" int created_time "创建时间" } 数量上的关系 这个 ER 模型中，标识的是： 一个订单 order 有多个 order_deatil 一个订单 order 有 0 个或者 1 个物流信息，还没发货就没有物流信息 这个乌鸦脚的有两个符号组合表示数量关系： | 表示有一个 O 表示 0 个 { 表示多个 并且这个两个符号属于或者的关系，相对于关系标签来说（如上面的属于、有），外层的代表是最大是数量，内层的表示最小的数量，例如： ||，1 个或者 1 个, 就是标识只能一个 o|，表示 0 个或者 1 个 标识和非标识关系（Identifying and Non-Identifying Relationships）, 这个关系用于实线和虚线来表示，例如： 实线表示标识关系，就是两个实体之间有直接的关系，有外键进行关联，例如 order_detail 通过 order_id 和父表 order 的 id 进行关联 虚线标识非标识关系，就是两个实体之间没有直接关系，独立存在，他们的关系需要通过中间表进行连接。例如 customer 和 delivery_address 没有外键进行直接关联起来，一个客户有多个地址，一个地址可以属于多个客户，他们可以分别独立存在 当然，如果要将非标识关系转为标识关系的话，可以建立一个中间实体，例如： erDiagram customer ||--|{ customer_deliver_relation : "有多个地址" delivery_adress ||--|{ customer_deliver_relation : "有多个地址" customer { int id PK "自增id" string name "客户姓名" } customer_deliver_relation { int id PK "递增id" int customer_id FK "客户id" int delivery_adress_id FK "地址id" int created_time "创建时间" } delivery_adress { int id PK "递增id" string adress "省市区" int created_time "创建时间" } 通过创建一个中间实体 customer_deliver_relation，这样 customer 和 customer_deliver_relation，以及 delivery_adress 和 customer_deliver_relation 之间，都是标识关系了。 父子关系 在 ER 图中，有父子关系，并且在 mermaid 中，中间的 label 是相对于第一实体，也就父亲来说的。在 ER 图中的父子关系，可以通过图形的上下位置来确定，上边的是父亲，下边的是孩子。

进程与线程：详细理解
type: item
date: 2023-10-04T11:10:00+08:00
description: 进程 有了进程之后，即使 cpu 只有一个，但是他们也有并发的能力，它们将单独的 cpu，变换成多个虚拟的 cpu，就好像每个程序进程都有自己独占的 cpu 一样。 一个进程是一个正在执行的程序实例，包括程序计数器、寄存器、变量的当前值，从概念上来说，每个进程都有自己虚拟的 cpu。 虚拟 cpu 的实现方式是，cpu 由一个进程快速切换到另一个进程，每个进程运行几十或几百毫秒，严格来说，在某一瞬间，单核 cpu 只能运行一个进程。 创建 场景 操作系统启动的时候创建 一个正在运行的进程，通过系统调用，创建新的进程协助工作。 在交互式系统中，输入一个命令，或者双击图标，可以启动一个程序，开启一个新的进程 从技术角度来说，新进程，都是由已经存在的进程，通过系统调用来创建的。 在 unix 中，通过 fork 调用，这个系统调用会创建一个和调用进程相同的副本。父子进程拥有相同的内存镜像、同样的环境字符串、同样的打开文件。通常，子进程会接着执行 execve 系统调用，来修改内存镜像，并运行一个新的程序 windows 中，可以通过调用 CreateProcess 来创建新的进程 在 windows 和 unix 中，进程创建后，父进程和子进程拥有不同的地址空间，如果某个进程在它的地址空间修改了个字，其他进程是不感知的。 在 unix 中，子进程的地址空间是父进程的镜像，读的时候是可以共享的，如果要写的话，就会写时复制，写的内容会写到自己的私有空间。 在 window 中，创建子进程的时候，就是不同的地址空间。 终止 场景 程序逻辑自己在正常退出。 unix 中，调用 exit，或者界面上的一些退出菜单项 window 中的，ExitProcess 调用 严重错误异常退出，致命错误，进程会收到中断信号 被其他进程杀死 例如 unix 中的 kill 命令 window 中的 TerminateProcess 调用 层次结构 一个进程，可以有 0 个，或者多个子进程。 在 unix 中，系统启动的时候，有一个 init 特殊进程，然后这个进程开始创建其他子进程，子进程再创建其他进程。就形成了一个树状结构，init 进程就是根 windows 中没有进程层次概念，所有进程地位都是相同的 进程的状态 尽管每个进程是一个独立的实体，有自己的程序计数器和内部状态，但是进程之间需要有相互作用通信，例如 cat a.log b.log | grep ERROR 有可能 grep 已经准备就绪可以运行，但是输入还没完成，这个时候必须阻塞 grep。 进程的 3 种状态 运行态，该时刻实际占用 cpu 就绪态，可以运行，但是因为 cpu 正在运行其他进程，暂停着 阻塞态，除非某种外部事件发生，否则不能运行，监听事件触发 进程的实现 操作系统维护一张表格，即进程表。每个进程占用表格的一行，每行里有该进程的重要信息，例如状态，程序计数器，堆栈等。 线程 每个进程有一个地址空间和一个控制线程。随着技术发展，一个进程下有多个线程。 进程用于把资源集中在一起，线程是被 cpu 调用执行的实体。 同一个进程中并行运行多个线程，是对一台计算机中并行运行多个进程的模拟。 前一种：多个线程共享进程里的地址空间和其他资源 后一种：多个进程，共享计算机的物理内存和其他硬件资源 多线程的优势 多个线程之间可以共享地址空间，进程地址空间是独立的 线程比进程轻量，cpu 切换多线程速度快 多线程和进程共享的内容 进程中被线程共享的 线程中独立的内容 地址空间 程序计数器 全局变量 寄存器 打开文件 堆栈 子进程 状态 账户信息等