2024年8月

高阶 (2n) VSVC
单位增益
巴特沃斯低通滤波器设计,可分解为 n 个二阶低通,通过对这多个二阶低通的组合优化,可提高滤波器的低通特性和稳定性。

串联的传递函数是各个二阶滤波器传递函数的乘积:
\({{\rm{H}}_{2n}}(s) = \prod\nolimits_{i - 1}^n {{H_2}^{(i)}(s)}\)

二阶压控电压源低通滤波器电路图:
image
由“虚短-虚断”得到,传输函数:
\(H(s) = {{\mathop V\nolimits_o } \over {\mathop V\nolimits_i }} = {{\mathop A\nolimits_F /\mathop R\nolimits_1 \mathop R\nolimits_2 \mathop C\nolimits_1 \mathop C\nolimits_2 } \over {\mathop s\nolimits^2 + s({1 \over {\mathop R\nolimits_1 \mathop C\nolimits_1 }} + {1 \over {\mathop R\nolimits_2 \mathop C\nolimits_1 }} + {{1 - \mathop A\nolimits_F } \over {\mathop R\nolimits_2 \mathop C\nolimits_2 }}) + {1 \over {\mathop R\nolimits_1 \mathop C\nolimits_1 \mathop R\nolimits_2 \mathop C\nolimits_2 }}}}\)

其中
\(s = j\omega\)

\(\mathop A\nolimits_F = 1 + {{\mathop R\nolimits_f } \over {\mathop R\nolimits_r }}\)

去归一化低通滤波器的传递函数:
\(H(s) = {{\mathop H\nolimits_0 \mathop \omega \nolimits_0^2 } \over {\mathop S\nolimits^2 + \alpha \mathop \omega \nolimits_0 S + \beta \mathop \omega \nolimits_0^2 }}\)

其中
\(\beta \mathop \omega \nolimits_0^2 = {1 \over {\mathop R\nolimits_1 \mathop R\nolimits_2 \mathop C\nolimits_1 \mathop C\nolimits_2 }}\)

\(\mathop H\nolimits_0 \mathop \omega \nolimits_0^2 = {{\mathop A\nolimits_F } \over {\mathop R\nolimits_1 \mathop R\nolimits_2 \mathop C\nolimits_1 \mathop C\nolimits_2 }}\)

\(\alpha \mathop \omega \nolimits_0 = {1 \over {\mathop R\nolimits_1 \mathop C\nolimits_1 }} + {1 \over {\mathop R\nolimits_2 \mathop C\nolimits_1 }} + {{1 - \mathop A\nolimits_F } \over {\mathop R\nolimits_2 \mathop C\nolimits_2 }}\)

\({\omega _0}\)
是截止角频率,
\(\alpha\)

\(\beta\)
是二项式系数,代表不同的滤波特性。

设定
\(\mathop C\nolimits_2 = k\mathop C\nolimits_1\)
,那么
\(\mathop H\nolimits_0 = \beta \mathop A\nolimits_F\)

\(\beta \mathop k\nolimits^2 \mathop \omega \nolimits_0^2 \mathop C\nolimits_1^2 \mathop R\nolimits_2^2 - \alpha k\mathop \omega \nolimits_0 \mathop C\nolimits_1 \mathop R\nolimits_2 + (1 + k - \mathop A\nolimits_F ) = 0\)
(关于
\({R_2}\)
的二次方程),由于
\({R_2}\)
存在实数解,则 k 必满足
\(k \le {{\mathop \alpha \nolimits^2 } \over {4\beta }} + \mathop A\nolimits_F - 1\)
;

求解可得:
\(\mathop R\nolimits_1 = {{\alpha \mp \sqrt {{\alpha ^2} - 4\beta (1 + k - {A_F})} } \over {2\beta (1 + \kappa - {{\rm A}_F}){\omega _0}{C_1}}}\)

\(\mathop R\nolimits_2 = {{\alpha \pm \sqrt {{\alpha ^2} - 4\beta (1 + k - {A_F})} } \over {2\beta k{\omega _0}{C_1}}}\)

选定
\({C_1}\)
,k后根据计算公式设计任意特性的VSVC低通滤波器。

归一化的巴特沃斯多项式:
image

对于单位增益
\(\mathop A\nolimits_F = 1\)
,二阶低通,多项式系数
\(\beta=1\)

那么
\(\mathop H\nolimits_0 = 1\)

\(k \le 0.25{\alpha ^2}\)
(k取值为
\(0.25{\alpha ^2}\)
时,VCVS二阶单位增益低通同时具有方便、低成本和稳定的优势)并且
\(\mathop R\nolimits_1 = {{\alpha \mp \sqrt {{\alpha ^2} - 4k} } \over {2k{\omega _0}{C_1}}}\)

\(\mathop R\nolimits_2 = {{\alpha \pm \sqrt {{\alpha ^2} - 4k} } \over {2k{\omega _0}{C_1}}}\)

通常情况下,为设计硬件电路方便,使得
\({R_1} = {R_2}\)

\({C_1}\)
的选取一般根据经验公式
\({C_1} \approx {10^{ - 3 \sim - 5}}{f_0}^{ - 1}\)
得出。

这样进一步简化为:
\({C_2} = 0.25{\alpha ^2}{C_1}\)

\({R_1} = {R_2} = {2 \over {\alpha {\omega _0}{C_1}}} = {1 \over {\pi \alpha {f_0}{C_1}}}\)

另外为运放正端提供回路补偿失调,取定
\({R_f} \ll {R_r},{R_f}//{R_r} \approx {R_f} = {R_1} + {R_2} = {2 \over {\pi \alpha {f_0}{C_1}}}\)
,到此完成了低通二阶巴特沃斯低通滤波器的参数配置。

对于高阶LPF设计,参照多项式系数和设定的截止频率即可完成。

实例仿真设计:
以截止频率为100khz,增益为1,设计四阶巴特沃斯低通滤波器:

四阶低通存在参数:
\({\alpha _1} = 0.7654,{\alpha _2} = 1.8478\)
,f=100khz,取第一级\第二级
\({C_1} = 4.7nF\)

得到:
第一级
\({C_2} = 0.68nF\)

\({R_1} = {R_2} = 884.8Ω\)

\({R_f} = 1769.6Ω\)

第二级
\({C_2} = 4.02nF\)

\({R_1} = {R_2} = 366.5Ω\)

\({R_f} = 733Ω\)

\({R_r}\)
取定1MΩ。Multisim仿真如下:

image

1、前言

在当今这个数据驱动的时代,数据库作为企业核心信息资产的载体,其重要性不言而喻。随着企业业务规模的不断扩大,数据库的数量和种类也日益增多,这对数据库的管理与运维工作提出了前所未有的挑战。在这样的背景下,一款高效、易用的数据库管理工具显得尤为重要。Archery,作为一款开源的数据库管理平台,以其独特的魅力成为了众多开发者和运维工程师的得力助手,如同古代战场上的利箭,精准而有力地击中了数据库管理的痛点。

2、Archery介绍

Archery
是一个基于
Python Flask
开发的数据库管理平台,它支持多种数据库(如MySQL、PostgreSQL、MariaDB、Redis等),提供了包括数据库查询、管理、权限控制、SQL审核、数据备份与恢复等功能在内的全方位数据库管理解决方案。其设计初衷是为了简化数据库管理流程,提高运维效率,同时保证数据的安全性和可靠性。

项目地址

https://github.com/hhyo/Archery
https://gitee.com/rtttte/Archery

3、核心功能解析

  1. 数据库管理
    Archery通过直观的Web界面,允许用户轻松管理多个数据库实例。用户可以添加、删除、修改数据库连接信息,实时查看数据库状态,以及执行诸如数据库备份、恢复、优化等高级操作。这一功能极大地降低了数据库管理的门槛,使得即便是非专业的运维人员也能快速上手。

  2. SQL查询与审核
    Archery内置了强大的SQL编辑器,支持语法高亮、自动补全等功能,极大提升了SQL编写和调试的效率。同时,它还提供了SQL审核功能,通过预设的规则库对SQL语句进行自动化审查,帮助用户及时发现并纠正潜在的风险,保障数据库操作的安全性和合规性。

  3. 权限控制
    Archery支持细粒度的权限控制策略,可以针对不同的用户或用户组设置不同的操作权限。这一功能有效防止了数据泄露和误操作的风险,保障了数据的安全性和隐私性。

  4. 数据备份与恢复
    数据备份是数据库运维中不可或缺的一环。Archery提供了自动化的数据备份和恢复功能,用户可以自定义备份策略,实现定时备份、增量备份等需求。同时,当数据发生丢失或损坏时,用户可以迅速通过备份文件恢复数据,保障业务的连续性。

  5. 可视化监控
    Archery还集成了数据库性能监控功能,通过图表和报告的形式展示数据库的运行状态、性能指标等关键信息。这使得运维人员能够实时监控数据库的健康状况,及时发现并解决潜在的问题。

4、优势与应用场景

优势

  • 开源免费:Archery作为一款开源项目,其源代码完全公开,用户可以自由下载、使用并根据实际需求进行修改和扩展。
  • 易于部署:Archery支持Docker等容器化部署方式,简化了部署流程,降低了部署门槛。
  • 功能全面:涵盖了数据库管理的各个方面,满足了从日常运维到高级管理的各种需求。
  • 安全性高:通过权限控制、SQL审核等功能保障了数据的安全性和合规性。

应用场景

  • 中小型企业:对于资源有限的中小型企业而言,Archery提供了一种低成本、高效率的数据库管理解决方案。
  • 互联网企业:面对海量数据和复杂的数据库环境,Archery的自动化管理和监控功能能够显著提升运维效率。
  • 金融、医疗等敏感行业:这些行业对数据的安全性和合规性要求极高,Archery的权限控制和SQL审核功能能够有效保障数据的安全性。

5、安装与使用

Archery
提供了容器化部署和非容器化部署两种模式,部署较为简单,在此不过多介绍,可参照如下部署文档即可

1、容器化部署:

https://github.com/hhyo/archery/wiki/docker

2、非容器化部署:

https://github.com/hhyo/archery/wiki/manual

3、在线体验地址
:
https://demo.archerydms.com/
在这里插入图片描述
账号和密码为:archer/archer

6、小结

Archery
作为一款开源的数据库管理平台,以其丰富的功能、易于部署的特点和强大的性能赢得了广泛的关注和好评。它如同一把精准的利箭,穿透了数据库管理的重重迷雾,为数据库的管理与运维工作带来了前所未有的便利和效率。未来,随着技术的不断进步和应用的不断深化,Archery有望成为更多企业和个人首选的数据库管理工具。

image

摄取 API

在这节教程中,我们将介绍如何使用 Ingest API 向 Quickwit 发送数据。

要跟随这节教程,您需要有一个
本地的 Quickwit 实例
正在运行。

要启动它,请在终端中运行
./quickwit run

创建索引

首先,我们创建一个无模式的索引。

# Create the index config file.
cat << EOF > stackoverflow-schemaless-config.yaml
version: 0.7
index_id: stackoverflow-schemaless
doc_mapping:
  mode: dynamic
indexing_settings:
  commit_timeout_secs: 30
EOF
# Use the CLI to create the index...
./quickwit index create --index-config stackoverflow-schemaless-config.yaml
# Or with cURL.
curl -XPOST -H 'Content-Type: application/yaml' 'http://localhost:7280/api/v1/indexes' --data-binary @stackoverflow-schemaless-config.yaml

摄取数据

让我们先下载
StackOverflow 数据集
的一个样本。

# Download the first 10_000 Stackoverflow posts articles.
curl -O https://quickwit-datasets-public.s3.amazonaws.com/stackoverflow.posts.transformed-10000.json

您可以使用命令行界面或 cURL 来发送数据。命令行界面对于发送几 GB 的数据更为方便,因为当 Ingest 队列已满时,Quickwit 可能会返回
429
响应。在这种情况下,Quickwit 命令行界面将自动重试发送。

# Ingest the first 10_000 Stackoverflow posts articles with the CLI...
./quickwit index ingest --index stackoverflow-schemaless --input-path stackoverflow.posts.transformed-10000.json --force

# OR with cURL.
curl -XPOST -H 'Content-Type: application/json' 'http://localhost:7280/api/v1/stackoverflow-schemaless/ingest?commit=force' --data-binary @stackoverflow.posts.transformed-10000.json

执行搜索查询

现在您可以对索引进行搜索了。

curl 'http://localhost:7280/api/v1/stackoverflow-schemaless/search?query=body:python'

清理源(可选)

curl -XDELETE 'http://localhost:7280/api/v1/indexes/stackoverflow-schemaless'

至此完成了教程。现在您可以继续阅读下一教程。

本地文件

在这节教程中,我们将介绍如何使用 Quickwit 命令行界面来索引本地文件。

要跟随这节教程,您需要有
Quickwit 二进制文件

创建索引

首先,我们创建一个无模式的索引。我们需要仅为了创建索引而启动 Quickwit 服务器,因此我们将启动它并在之后关闭它。

启动 Quickwit server。

./quickwit run

在另一个终端中创建索引。

# Create the index config file.
cat << EOF > stackoverflow-schemaless-config.yaml
version: 0.7
index_id: stackoverflow-schemaless
doc_mapping:
  mode: dynamic
indexing_settings:
  commit_timeout_secs: 30
EOF

./quickwit index create --index-config stackoverflow-schemaless-config.yaml

现在您可以通过在第一个终端中按下
Ctrl+C
来关闭服务器。

摄取文件

要发送文件,只需执行以下命令:

./quickwit tool local-ingest --index stackoverflow-schemaless --input-path stackoverflow.posts.transformed-10000.json

几秒钟后,您应该能看到以下输出:

❯ Ingesting documents locally...

---------------------------------------------------
 Connectivity checklist
 ✔ metastore
 ✔ storage
 ✔ _ingest-cli-source

 Num docs   10000 Parse errs     0 PublSplits   1 Input size     6MB Thrghput  3.34MB/s Time 00:00:02
 Num docs   10000 Parse errs     0 PublSplits   1 Input size     6MB Thrghput  2.23MB/s Time 00:00:03
 Num docs   10000 Parse errs     0 PublSplits   1 Input size     6MB Thrghput  1.67MB/s Time 00:00:04

Indexed 10,000 documents in 4s.
Now, you can query the index with the following command:
quickwit index search --index stackoverflow-schemaless --config ./config/quickwit.yaml --query "my query"
Clearing local cache directory...
✔ Local cache directory cleared.
✔ Documents successfully indexed.

支持像
s3://mybucket/mykey.json
这样的对象存储 URI 作为
--input-path
,前提是您的环境配置了适当的权限。

清理源(可选)

就这样!现在您可以清理创建的源。您可以通过运行以下命令来完成:

./quickwit run

在另一个终端中:

./quickwit index delete --index-id stackoverflow-schemaless

至此完成了教程。现在您可以继续阅读下一教程。

Kafka

在这节教程中,我们将介绍如何在几分钟内设置 Quickwit 以从 Kafka 摄取数据。首先,我们将创建一个索引并配置 Kafka 源。然后,我们将创建一个 Kafka 主题并将一些事件从
GH Archive
加载到其中。最后,我们将执行一些搜索和聚合查询来探索新发送的数据。

前提条件

要完成这篇教程,您需要以下条件:

创建索引

首先,我们创建一个新的索引。以下是与 GH Archive 事件模式对应的索引配置和文档映射:

#
# Index config file for gh-archive dataset.
#
version: 0.7

index_id: gh-archive

doc_mapping:
  field_mappings:
    - name: id
      type: text
      tokenizer: raw
    - name: type
      type: text
      fast: true
      tokenizer: raw
    - name: public
      type: bool
      fast: true
    - name: payload
      type: json
      tokenizer: default
    - name: org
      type: json
      tokenizer: default
    - name: repo
      type: json
      tokenizer: default
    - name: actor
      type: json
      tokenizer: default
    - name: other
      type: json
      tokenizer: default
    - name: created_at
      type: datetime
      fast: true
      input_formats:
        - rfc3339
      fast_precision: seconds
  timestamp_field: created_at

indexing_settings:
  commit_timeout_secs: 10

执行这些 Bash 命令来下载索引配置并创建
gh-archive
索引:

# Download GH Archive index config.
wget -O gh-archive.yaml https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/gh-archive/index-config.yaml

# Create index.
./quickwit index create --index-config gh-archive.yaml

创建并填充 Kafka topic

现在,我们创建一个 Kafka 主题并将一些事件加载到其中。

# Create a topic named `gh-archive` with 3 partitions.
bin/kafka-topics.sh --create --topic gh-archive --partitions 3 --bootstrap-server localhost:9092

# Download a few GH Archive files.
wget https://data.gharchive.org/2022-05-12-{10..15}.json.gz

# Load the events into Kafka topic.
gunzip -c 2022-05-12*.json.gz | \
bin/kafka-console-producer.sh --topic gh-archive --bootstrap-server localhost:9092

创建 Kafka 源

这篇教程假设 Kafka 集群在默认端口(9092)上本地可用。
如果情况并非如此,请相应地更新
bootstrap.servers
参数。

#
# Kafka source config file.
#
version: 0.8
source_id: kafka-source
source_type: kafka
num_pipelines: 2
params:
  topic: gh-archive
  client_params:
    bootstrap.servers: localhost:9092

运行这些命令来下载源配置文件并创建源。

# Download Kafka source config.
wget https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/gh-archive/kafka-source.yaml

# Create source.
./quickwit source create --index gh-archive --source-config kafka-source.yaml

如果您遇到以下错误:

Command failed: Topic `gh-archive` has no partitions.

这意味着 Kafka 主题
gh-archive
在前一步骤中未正确创建。

启动索引和搜索服务

最后,执行此命令以服务器模式启动 Quickwit。

# Launch Quickwit services.
./quickwit run

在幕后,这个命令会启动一个索引器和一个搜索器。启动时,索引器将连接到由源指定的 Kafka 主题,并开始从组成主题的分区流式处理和索引事件。使用默认的提交超时值(参见
索引设置
),索引器应在大约 60 秒后发布第一个分片。

您可以在另一个 shell 中运行此命令来检查索引的属性并查看当前发布的分片数量:

# Display some general information about the index.
./quickwit index describe --index gh-archive

一旦发布了第一个分片,您就可以开始运行搜索查询。例如,我们可以找到所有关于 Kubernetes
仓库
的事件:

curl 'http://localhost:7280/api/v1/gh-archive/search?query=org.login:kubernetes%20AND%20repo.name:kubernetes'

也可以通过
Quickwit 用户界面
访问这些结果。

我们还可以按类型对这些事件进行分组并计数它们:

curl -XPOST -H 'Content-Type: application/json' 'http://localhost:7280/api/v1/gh-archive/search' -d '
{
  "query":"org.login:kubernetes AND repo.name:kubernetes",
  "max_hits":0,
  "aggs":{
    "count_by_event_type":{
      "terms":{
        "field":"type"
      }
    }
  }
}'

安全的 Kafka 连接(可选)

Quickwit 的 Kafka 源支持 SSL 和 SASL 身份验证。这对于从外部 Kafka 服务消费数据特别有用。

证书和密钥文件必须存在于所有 Quickwit 节点上,以便创建 Kafka 源并成功运行索引管道。

SSL 配置

version: 0.8
source_id: kafka-source-ssl
source_type: kafka
num_pipelines: 2
params:
  topic: gh-archive
  client_params:
    bootstrap.servers: your-kafka-broker.com
    security.protocol: SSL
    ssl.ca.location: /path/to/ca.pem
    ssl.certificate.location: /path/to/service.cert
    ssl.key.location: /path/to/service.key

SASL 配置

version: 0.8
source_id: kafka-source-sasl
source_type: kafka
num_pipelines: 2
params:
  topic: gh-archive
  client_params:
    bootstrap.servers: your-kafka-broker.com
    ssl.ca.location: /path/to/ca.pem
    security.protocol: SASL_SSL
    sasl.mechanisms: SCRAM-SHA-256
    sasl.username: your_sasl_username
    sasl.password: your_sasl_password
如果您遇到以下错误:

Client creation error: ssl.ca.location failed: error:05880002:x509 certificate routines::system lib

通常意味着 CA 证书的路径不正确。请相应地更新
ssl.ca.location
参数。

清理源(可选)

让我们删除为这篇教程创建的文件和源。

# Delete Kafka topic.
bin/kafka-topics.sh --delete --topic gh-archive --bootstrap-server localhost:9092

# Delete index.
./quickwit index delete --index gh-archive

# Delete source config.
rm kafka-source.yaml

至此完成了教程。如果您有关于 Quickwit 的任何问题或遇到任何问题,请不要犹豫,在
GitHub
上提出
问题
或打开
问题报告
,或者直接在
Discord
上联系我们。

Pulsar

在这节教程中,我们将介绍如何在几分钟内设置 Quickwit 以从 Pulsar 摄取数据。首先,我们将创建一个索引并配置 Pulsar 源。然后,我们将创建一个 Pulsar topic 并将一些事件从
Stack Overflow 数据集
加载到其中。最后,我们将执行一些搜索。

前提条件

要完成这篇教程,您需要以下条件:

Quickwit 设置

下载
Quickwit 并启动一个服务器。然后打开一个新的终端,使用同一个二进制文件执行 CLI 命令。

./quickwit run

测试集群是否正在运行:

./quickwit index list

Pulsar 设置

Local

wget https://archive.apache.org/dist/pulsar/pulsar-2.11.0/apache-pulsar-2.11.0-bin.tar.gz
tar xvfz apache-pulsar-2.11.0-bin.tar.gz
cd apache-pulsar-2.11.0
bin/pulsar standalone

Docker

docker run -it -p 6650:6650 -p 8080:8080 apachepulsar/pulsar:2.11.0 bin/pulsar standalone

请参阅
官方文档
的详细信息。

准备 Quickwit

首先,我们创建一个新的索引。以下是与 Stack Overflow 帖子模式对应的索引配置和文档映射:

#
# Index config file for Stack Overflow dataset.
#
version: 0.7

index_id: stackoverflow

doc_mapping:
  field_mappings:
    - name: user
      type: text
      fast: true
      tokenizer: raw
    - name: tags
      type: array<text>
      fast: true
      tokenizer: raw
    - name: type
      type: text
      fast: true
      tokenizer: raw
    - name: title
      type: text
      tokenizer: default
      record: position
      stored: true
    - name: body
      type: text
      tokenizer: default
      record: position
      stored: true
    - name: questionId
      type: u64
    - name: answerId
      type: u64
    - name: acceptedAnswerId
      type: u64
    - name: creationDate
      type: datetime
      fast: true
      input_formats:
        - rfc3339
      fast_precision: seconds
  timestamp_field: creationDate

search_settings:
  default_search_fields: [title, body]

indexing_settings:
  commit_timeout_secs: 10

执行这些 Bash 命令来下载索引配置并创建
stackoverflow
索引。

# Download stackoverflow index config.
wget -O stackoverflow.yaml https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/stackoverflow/index-config.yaml

# Create index.
./quickwit index create --index-config stackoverflow.yaml

创建 Pulsar 源

Pulsar 源只需要定义主题列表和实例地址。

#
# Pulsar source config file.
#
version: 0.7
source_id: pulsar-source
source_type: pulsar
params:
  topics:
    - stackoverflow
  address: pulsar://localhost:6650

运行这些命令来下载源配置文件并创建源。

# Download Pulsar source config.
wget -O stackoverflow-pulsar-source.yaml https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/stackoverflow/pulsar-source.yaml

# Create source.
./quickwit source create --index stackoverflow --source-config stackoverflow-pulsar-source.yaml

一旦创建了 Pulsar 源,Quickwit 控制平面将请求索引器启动一个新的索引管道。您可以在索引器上看到类似下面的日志:

INFO spawn_pipeline{index=stackoverflow gen=0}:pulsar-consumer{subscription_name="quickwit-stackoverflow-pulsar-source" params=PulsarSourceParams { topics: ["stackoverflow"], address: "pulsar://localhost:6650", consumer_name: "quickwit", authentication: None } current_positions={}}: quickwit_indexing::source::pulsar_source: Seeking to last checkpoint positions. positions={}

创建并填充 Pulsar topic

我们将使用 Pulsar 的默认租户/命名空间
public/default
。为了填充主题,我们将使用一个 Python 脚本:

import json
import pulsar

client = pulsar.Client('pulsar://localhost:6650')
producer = client.create_producer('public/default/stackoverflow')

with open('stackoverflow.posts.transformed-10000.json', encoding='utf8') as file:
   for i, line in enumerate(file):
       producer.send(line.encode('utf-8'))
       if i % 100 == 0:
           print(f"{i}/10000 messages sent.", i)

client.close()

安装本地 Python 客户端,更多详情请参阅
文档页面

# Download the first 10_000 Stackoverflow posts articles.
curl -O https://quickwit-datasets-public.s3.amazonaws.com/stackoverflow.posts.transformed-10000.json

# Install pulsar python client.
# Requires a python version < 3.11
pip3 install 'pulsar-client==2.10.1'
wget https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/stackoverflow/send_messages_to_pulsar.py
python3 send_messages_to_pulsar.py

开始搜索!

您可以运行此命令来检查索引的属性并查看当前发布的分片和文档数量:

# Display some general information about the index.
./quickwit index describe --index stackoverflow

您将特别注意到发布的文档数量。

现在您可以执行一些查询了。

curl 'http://localhost:7280/api/v1/stackoverflow/search?query=search+AND+engine'

如果您的 Quickwit 服务器是本地的,您可以通过 Quickwit UI 访问结果,网址为
localhost:7280

清理源(可选)

让我们删除为这篇教程创建的文件和源。

# Delete quickwit index.
./quickwit index delete --index stackoverflow --yes
# Delete Pulsar topic.
bin/pulsar-admin topics delete stackoverflow

至此完成了教程。如果您有关于 Quickwit 的任何问题或遇到任何问题,请不要犹豫,在
GitHub
上提出
问题
或打开
问题报告
,或者直接在
Discord
上联系我们。

Kinesis

在这节教程中,我们将介绍如何在几分钟内设置 Quickwit 以从 Kinesis 摄取数据。首先,我们将创建一个索引并配置 Kinesis 源。然后,我们将创建一个 Kinesis 流并将一些事件从
GH Archive
加载到其中。最后,我们将执行一些搜索和聚合查询来探索新发送的数据。

在这篇教程中使用 Amazon Kinesis 服务会产生一些费用。

前提条件

要完成这篇教程,您需要以下条件:

jq
用于重塑事件成为可通过 Amazon Kinesis API 发送的记录。

创建索引

首先,我们创建一个新的索引。以下是与 GH Archive 事件模式对应的索引配置和文档映射:

#
# Index config file for gh-archive dataset.
#
version: 0.7

index_id: gh-archive

doc_mapping:
  field_mappings:
    - name: id
      type: text
      tokenizer: raw
    - name: type
      type: text
      fast: true
      tokenizer: raw
    - name: public
      type: bool
      fast: true
    - name: payload
      type: json
      tokenizer: default
    - name: org
      type: json
      tokenizer: default
    - name: repo
      type: json
      tokenizer: default
    - name: actor
      type: json
      tokenizer: default
    - name: other
      type: json
      tokenizer: default
    - name: created_at
      type: datetime
      fast: true
      input_formats:
        - rfc3339
      fast_precision: seconds
  timestamp_field: created_at

indexing_settings:
  commit_timeout_secs: 10

执行这些 Bash 命令来下载索引配置并创建
gh-archive
索引。

# Download GH Archive index config.
wget -O gh-archive.yaml https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/gh-archive/index-config.yaml

# Create index.
./quickwit index create --index-config gh-archive.yaml

创建并填充 Kinesis 流

现在,我们创建一个 Kinesis 流并将一些事件加载到其中。

这一步可能相当慢,具体取决于可用带宽。当前命令通过仅取从 GH Archive 下载的每个文件的前 10,000 行来限制要发送的数据量。如果您有足够的带宽,可以移除它来发送整套文件。您也可以通过增加分片的数量和/或
parallel
启动的任务数量 (
-j
选项) 来加快速度。

# Create a stream named `gh-archive` with 3 shards.
aws kinesis create-stream --stream-name gh-archive --shard-count 8

# Download a few GH Archive files.
wget https://data.gharchive.org/2022-05-12-{10..12}.json.gz

# Load the events into Kinesis stream
gunzip -c 2022-05-12*.json.gz | \
head -n 10000 | \
parallel --gnu -j8 -N 500 --pipe \
'jq --slurp -c "{\"Records\": [.[] | {\"Data\": (. | tostring), \"PartitionKey\": .id }], \"StreamName\": \"gh-archive\"}" > records-{%}.json && \
aws kinesis put-records --cli-input-json file://records-{%}.json --cli-binary-format raw-in-base64-out >> out.log'

创建 Kinesis 源

#
# Kinesis source config file.
#
version: 0.7
source_id: kinesis-source
source_type: kinesis
params:
  stream_name: gh-archive

运行这些命令来下载源配置文件并创建源。

# Download Kinesis source config.
wget https://raw.githubusercontent.com/quickwit-oss/quickwit/main/config/tutorials/gh-archive/kinesis-source.yaml

# Create source.
./quickwit source create --index gh-archive --source-config kinesis-source.yaml

如果此命令出现以下错误消息而失败:

Command failed: Stream gh-archive under account XXXXXXXXX not found.

Caused by:
    0: Stream gh-archive under account XXXXXXXX not found.
    1: Stream gh-archive under account XXXXXXXX not found.

这意味着 Kinesis 流在前一步骤中未正确创建。

启动索引和搜索服务

最后,执行此命令以服务器模式启动 Quickwit。

# Launch Quickwit services.
./quickwit run

在幕后,这个命令会启动一个索引器和一个搜索器。启动时,索引器将连接到由源指定的 Kinesis 流,并开始从组成流的分片流式处理和索引事件。使用默认的提交超时值(参见
索引设置
),索引器应在大约 60 秒后发布第一个分片。

您可以在另一个 shell 中运行此命令来检查索引的属性并查看当前发布的分片数量:

# Display some general information about the index.
./quickwit index describe --index gh-archive

也可以通过
Quickwit 用户界面
获取索引信息。

一旦发布了第一个分片,您就可以开始运行搜索查询。例如,我们可以找到所有关于 Kubernetes
仓库
的事件:

curl 'http://localhost:7280/api/v1/gh-archive/search?query=org.login:kubernetes%20AND%20repo.name:kubernetes'

也可以通过
用户界面
访问这些结果。

我们还可以按类型对这些事件进行分组并计数它们:

curl -XPOST -H 'Content-Type: application/json' 'http://localhost:7280/api/v1/gh-archive/search' -d '
{
  "query":"org.login:kubernetes AND repo.name:kubernetes",
  "max_hits":0,
  "aggs":{
    "count_by_event_type":{
      "terms":{
        "field":"type"
      }
    }
  }
}'

清理源(可选)

让我们删除为这篇教程创建的文件和源。

# Delete Kinesis stream.
aws kinesis delete-stream --stream-name gh-archive

# Delete index.
./quickwit index delete --index gh-archive

# Delete source config.
rm kinesis-source.yaml

至此完成了教程。如果您有关于 Quickwit 的任何问题或遇到任何问题,请不要犹豫,在
GitHub
上提出
问题
或打开
问题报告
,或者直接在
Discord
上联系我们。

具有 SQS 通知的 S3

在这篇教程中,我们介绍如何设置 Quickwit 以从 S3 摄取数据,其中桶通知事件通过 SQS 流式传输。我们首先使用 Terraform 创建 AWS 源(S3 桶、SQS 队列、通知)。然后配置 Quickwit 索引和文件源。最后,我们将一些数据发送到源桶并验证其是否被正确索引。

AWS 源

完整的 Terraform 脚本可以从
这里
下载。

首先,创建接收源数据文件(NDJSON 格式)的桶:

resource "aws_s3_bucket" "file_source" {
  bucket_prefix = "qw-tuto-source-bucket"
}

然后设置 SQS 队列,当文件添加到桶时,队列将承载通知。队列配置了一个策略,允许源桶向其写入 S3 通知消息。同时创建一个死信队列 (DLQ),用于接收文件源无法处理的消息(例如损坏的文件)。消息在经过 5 次索引尝试后会被移动到 DLQ。

locals {
  sqs_notification_queue_name = "qw-tuto-s3-event-notifications"
}

data "aws_iam_policy_document" "sqs_notification" {
  statement {
    effect = "Allow"

    principals {
      type        = "*"
      identifiers = ["*"]
    }

    actions   = ["sqs:SendMessage"]
    resources = ["arn:aws:sqs:*:*:${local.sqs_notification_queue_name}"]

    condition {
      test     = "ArnEquals"
      variable = "aws:SourceArn"
      values   = [aws_s3_bucket.file_source.arn]
    }
  }
}

resource "aws_sqs_queue" "s3_events_deadletter" {
  name = "${locals.sqs_notification_queue_name}-deadletter"
}

resource "aws_sqs_queue" "s3_events" {
  name   = local.sqs_notification_queue_name
  policy = data.aws_iam_policy_document.sqs_notification.json

  redrive_policy = jsonencode({
    deadLetterTargetArn = aws_sqs_queue.s3_events_deadletter.arn
    maxReceiveCount     = 5
  })
}

resource "aws_sqs_queue_redrive_allow_policy" "s3_events_deadletter" {
  queue_url = aws_sqs_queue.s3_events_deadletter.id

  redrive_allow_policy = jsonencode({
    redrivePermission = "byQueue",
    sourceQueueArns   = [aws_sqs_queue.s3_events.arn]
  })
}

配置桶通知,每当源桶中创建新文件时,都会向 SQS 写入消息:

resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = aws_s3_bucket.file_source.id

  queue {
    queue_arn = aws_sqs_queue.s3_events.arn
    events    = ["s3:ObjectCreated:*"]
  }
}

只支持
s3:ObjectCreated:*
类型的事件。
其他类型(例如
ObjectRemoved
)会被确认,并且会记录警告日志。

源需要能够访问通知队列和源桶。以下策略文档包含了源所需的最小权限:

data "aws_iam_policy_document" "quickwit_node" {
  statement {
    effect = "Allow"
    actions = [
      "sqs:ReceiveMessage",
      "sqs:DeleteMessage",
      "sqs:ChangeMessageVisibility",
      "sqs:GetQueueAttributes",
    ]
    resources = [aws_sqs_queue.s3_events.arn]
  }
  statement {
    effect    = "Allow"
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.file_source.arn}/*"]
  }
}

创建 IAM 用户和凭证,以便将其与本地 Quickwit 实例关联:

resource "aws_iam_user" "quickwit_node" {
  name = "quickwit-filesource-tutorial"
  path = "/system/"
}

resource "aws_iam_user_policy" "quickwit_node" {
  name   = "quickwit-filesource-tutorial"
  user   = aws_iam_user.quickwit_node.name
  policy = data.aws_iam_policy_document.quickwit_node.json
}

resource "aws_iam_access_key" "quickwit_node" {
  user = aws_iam_user.quickwit_node.name
}

我们不建议在生产环境中使用 IAM 用户凭证运行 Quickwit 节点。
这只是为了简化教程设置。在 EC2/ECS 上运行时,应将策略文档附加到 IAM 角色上。

下载
完整的 Terraform 脚本
,并使用
terraform init

terraform apply
部署它。成功执行后,将列出配置 Quickwit 所需的输出。您可以使用以下命令显示敏感输出(密钥 ID 和密钥)的值:

terraform output quickwit_node_access_key_id
terraform output quickwit_node_secret_access_key

运行 Quickwit

本地安装 Quickwit
,然后在安装目录中,使用必要的访问权限运行 Quickwit,将
<quickwit_node_access_key_id>

<quickwit_node_secret_access_key>
替换为匹配的 Terraform 输出值:

AWS_ACCESS_KEY_ID=<quickwit_node_access_key_id> \
AWS_SECRET_ACCESS_KEY=<quickwit_node_secret_access_key> \
AWS_REGION=us-east-1 \
./quickwit run

配置索引和源

在另一个终端中,在 Quickwit 安装目录中,创建一个索引:

cat << EOF > tutorial-sqs-file-index.yaml
version: 0.7
index_id: tutorial-sqs-file
doc_mapping:
  mode: dynamic
indexing_settings:
  commit_timeout_secs: 30
EOF

./quickwit index create --index-config tutorial-sqs-file-index.yaml


<notification_queue_url>
替换为相应的 Terraform 输出值,为该索引创建一个文件源:

cat << EOF > tutorial-sqs-file-source.yaml
version: 0.8
source_id: sqs-filesource
source_type: file
num_pipelines: 2
params:
  notifications:
    - type: sqs
      queue_url: <notification_queue_url>
      message_type: s3_notification
EOF

./quickwit source create --index tutorial-sqs-file --source-config tutorial-sqs-file-source.yaml

num_pipeline
配置控制了多少个消费者将并行地从队列中轮询。根据您想要为此源分配的索引器计算资源选择数字。一般而言,每 2 个核心配置 1 个管道。

摄取数据

我们现在可以通过将文件上传到 S3 来向 Quickwit 发送数据。如果您已安装 AWS CLI,运行以下命令,将
<source_bucket_name>
替换为关联的 Terraform 输出:

curl https://quickwit-datasets-public.s3.amazonaws.com/hdfs-logs-multitenants-10000.json | \
    aws s3 cp - s3://<source_bucket_name>/hdfs-logs-multitenants-10000.json

如果您不想使用 AWS CLI,您也可以下载文件并通过 AWS 控制台手动将其上传到源桶。

等待大约 1 分钟,数据应该会出现在索引中:

./quickwit index describe --index tutorial-sqs-file

清理源

这节教程中实例化的 AWS 源不会产生固定成本,但我们仍然建议您完成后删除它们。在包含 Terraform 脚本的目录中,运行
terraform destroy

更多

1.
Binance 如何使用 Quickwit 构建 100PB 日志服务(Quickwit 博客)

《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,全书共分10章,第1章主要让读者认识数据资产,了解数据资产相关的基础概念,以及数据资产的发展情况。第2~8章主要介绍大数据时代数据资产管理所涉及的核心技术,内容包括元数据的采集与存储、数据血缘、数据质量、数据监控与告警、数据服务、数据权限与安全、数据资产管理架构等。第9~10章主要从实战的角度介绍数据资产管理技术的应用实践,包括如何对元数据进行管理以发挥出数据资产的更大潜力,以及如何对数据进行建模以挖掘出数据中更大的价值。

图书介绍:
数据资产管理核心技术与应用

今天主要是给大家分享一下第四章的内容:

第四章的标题为数据质量的技术实现

内容思维导图如下:

本文是接着

《数据资产管理核心技术与应用》读书笔记-第四章:数据质量的技术实现(一)

继续往下介绍

1、质量数据采集的技术实现

当然除了借助Apache DolphinSchedur外,我们也可以自己实现定时任务运行,相关的技术架构图如下图所示。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

  • 由于不管是数据湖还是数据仓库,都支持Spark 对其做数据读取和数据处理,所以对数据湖或者数据仓库的质量数据采集都可以通过在Spark集群中执行Spark任务的方式去获取数据。Spark 集群的部署支持Standalone、Mesos、YARN、Kubernetes 四种方式,可以参考Spark官方网址:
    https://spark.apache.org/docs/latest/cluster-overview.html#cluster-manager-types
    ,如下图所示,可以根据实际使用的数据湖或者数据仓库的部署模式,来选择相应的Spark 集群的部署模式,比如您的数据仓库Hive 是通过Hadoop的方式部署的,那么Spark集群的部署方式就应该选择Hadoop YARN的部署模式更加合适。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

  • 设计一个Spark集群上可以执行的jar包或者PySpark脚本,该Jar包或者PySpark脚本用于提交任务到Spark集群中进行运行 ,运行时,读取配置好的质量规则,任务执行完毕后,将采集到的质量结果数据入库,关于如何向Spark集群提交Jar包或者PySpark脚本任务,可以参考官网网址:
    https://spark.apache.org/docs/latest/submitting-applications.html
    ,如下图所示。

  • Jar包或者PySpark脚本中可以执行Spark SQL语句,也可以执行Scala脚本或者Python脚本。
  • 如果Spark 集群是通过Kubernetes部署的,那么需要先将Jar包或者PySpark脚本 做成Docker 镜像,然后通过镜像的方式将Jar包或者PySpark脚本运行至Spark 集群中,如下图所示,关于Kubernetes相关的知识可以参考:
    https://kubernetes.io/zh-cn/docs/home/
    。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

  • Jar包或者Python 脚本,需要做成通用的,而不是执行每一个质量规则时都需要去创建一个jar包或者Python 脚本,当然也可以支持用户自定义Jar包或者Python 脚本进行扩展,但是一定要定义Jar包或者Python 脚本的抽象接口,如下图所示。

从图中可以看到,我们至少可以在抽象接口中先预定义好读取规则、解析规则以及执行规则等这几个方法,使用Java开发语言定义的抽象接口参考代码如下:《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

public interface Example {
 
    void readRule(String rule);
 
    void analysisRule(String rule);
 
    void execRule(String data);
}

根据上面描述的数据质量规则的配置到数据质量规则的定时采集执行,可以大致设计如下图的表结构模型供参考。

1)、t_quality_rule_template为数据质量规则模板表,可以将一些通用的规则做成模板,供规则的配置者直接使用或者基于选择的规则模板再做少量的二次修改。

2)、t_quality_rule为数据质量规则配置表,表中存储了实际的数据质量采集规则以及该规则对应的数据表id以及定时采集的cron表达式,比如类似0 */30 * * * ?,就是每隔30分钟执行一次。

cron 表达式是一个字符串,该字符串通常是由 7 个域组成,每个域之间以空格格式,每个域代表一个特定的时间含义,如下表所示。

取值范围

0-59

0-59

0-23

1-31

1-12 或 JAN-DEC

1-7 或 SUN-SAT

1970-2099

3)、t_quality_rule_exec为数据质量规则执行表,表中存储了每次定时采集任务的执行记录。定时采集任务执行时,其状态的变化过程大致如下图所示,为了方便问题的定位,任务执行过程中的状态变化都需要更新到表t_quality_rule_exec中。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

2、 如何处理采集到的质量数据

质量数据采集到的是原始的数据,由于数据质量规则众多,所以每一种规则采集到的原始数据可能都不一样,所以还需要对原始的数据做归一化处理,然后才能进行入库存储,如下图所示。

虽然每个质量规则采集到的原始数据可能都是不一样的,但是我们还是需要设计一个统一的原始数据消息格式以方便做数据的统一处理,参考如下:

[{
                   "execId": "",
                   "ruleId": "",
                   "returnType": "",
                   "returnData": [],
                   "startExecTime": "",
                   "endExecTime": ""
}]
3、质量数据的存储模型设计

从架构设计的角度来看,数据质量的存储需要注意如下几点:

  • 可扩展性: 支持对多种不同质量规则采集到的质量数据的存储,比如不能出现扩展了质量规则或者用户自定义的质量规则的结果数据无法存储,从而需要修改数据存储模型的情况。
  • 可跟踪性:需要记录质量数据的变更记录,方便将来做质量数据变化的跟踪和审查。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著
  • 可维护性:支持手工运维,比如出现脏数据或者需要人工干预的情况时,可以让系统管理员进行相关的历史数据或者脏数据的清理等常规运维操作。

如下图所示基于上述的设计原则,设计了如下的数据质量存储模型供参考,下中在每张表中列出了数据质量存储模型的核心字段。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

如果需要查询某张表的质量数据时,可以根据如下图所示的关联关系来获取数据。

质量数据其实和常用的监控数据很类似,也可以考虑用时序数据库来进行存储,因为质量数据都是按照时间来时序采集的,并且数据也是时序变化的,所以使用时序数据库来存储是非常适合的。常见的时序数据库对比介绍如下表所示,可以根据实际的场景来选择。《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

数据库类型

InfluxDB

Prometheus

OpenTSDB

描述

用于存储时间序列、事件和度量的开源时序数据库

开源时序数据库,一般多用于监控系统

基于HBase的可扩展的时间序列开源数据库

官方网址

https://www.influxdata.com/products/influxdb/

官方网址为https://prometheus.io/

官方网址为http://opentsdb.net/

文档介绍

https://docs.influxdata.com/influxdb

https://prometheus.io/docs/

http://opentsdb.net/docs/build/html/index.html

底层实现的开发语言

Go

Go

Java

支持的数据类型

数字和字符串

只支持数字

指标支持数字

,标签支持字符串

是否支持SQL语言

支持类SQL查询(和SQL语法类似)

不支持

不支持

API类型

Http API

RESTful Http/JSON API

Http API

未完待续......《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著

逻辑回归算法 0基础小白也能懂(附代码)

原文链接

啥是逻辑回归算法

逻辑回归(Logistic Regression)是一种广泛用于分类任务的统计模型,特别适用于二元分类问题。尽管名称中带有“回归”,但逻辑回归主要用于分类。逻辑回归算法包含以下几个关键部分:
线性回归与分类,Sigmoid 函数与决策边界,梯度下降与优化,正则化与缓解过拟合

线性回归与分类

分类问题和回归问题有一定的相似性,都是通过对数据集的学习来对未知结果进行预测,区别在于输出值不同。

分类问题的输出值是离散值(如垃圾邮件和正常邮件)。
回归问题的输出值是连续值(例如房子的价格)。

既然分类问题和回归问题有一定的相似性,那么我们能不能在回归的基础上进行分类呢?

可以使用『线性回归+阈值』解决分类问题,
也就是根据回归的函数按照一个阈值来一分为二,但是单纯地通过将线性拟合的输出值与某一个阈值进行比较,这种方法用于分类非常不稳定呢。

但是当我们单纯地使用线性回归来解决分类问题时,输出是一个未限定范围的连续值。这样做存在几个问题:

1.范围不固定:线性回归的输出可能是任何实数(比如 -∞ 到 +∞),这使得我们无法确定一个合理的阈值来判断输出 属于哪个类别。例如,可能得到一个极大的正值或负值,难以直接映射为0或1。

2.阈值选择困难:为了将连续值映射到离散类别(例如 0 和 1),我们通常需要一个判定阈值。如果线性回归的输出值不在一个固定的范围内,选择一个合适的阈值会变得非常困难,尤其是在处理极端值时。

我们是否可以把这个结果映射到一个固定大小的区间内(比如
\((0,1)\)
),进而判断。

Sigmoid 函数与决策边界

当然可以,这就是逻辑回归做的事情,而其中用于对连续值压缩变换的函数叫做 Sigmoid 函数(也称 Logistic 函数,S函数)。

\(S(x)=\frac{1}{1+e^{-x}}\)
输出在
\((0,1)\)
之间。

上面见到了 Sigmoid 函数,下面我们来讲讲它和线性拟合的结合,如何能够完成分类问题,并且得到清晰可解释的分类器判定「决策边界」。决策边界就是分类器对于样本进行区分的边界。

那么,逻辑回归是怎么得到决策边界的,它与 Sigmoid 函数又有什么关系呢?文中讲到了两类决策边界,线性和非线性。

在这两张图中,右边的是我们的S函数,它将通过函数计算后的结果映射到了
\((0,1)\)
区间,那比如这里要做的就是二分类,就找0.5的那一条线,也就是在原函数中能将数据分成两组的函数,改变
\(\theta_0,\theta_1,\theta_2\)
之类的参数,比如线性参数的例子里就是-3,1,1,以这几个参数做出来的函数就是决策边界,0.5则是判断边界。

梯度下降与优化

损失函数

前一部分的例子中,我们手动取了一些参数
\(\theta_0,\theta_1,\theta_2\)
的取值,最后得到了决策边界。但大家显然可以看到,取不同的参数时,可以得到不同的决策边界。

哪一条决策边界是最好的呢?我们需要定义一个能量化衡量模型好坏的函数——损失函数(有时候也叫做「目标函数」或者「代价函数」)。我们的目标是使得损失函数最小化。总不能一直手动去取参数。

我们如何衡量预测值和标准答案之间的差异呢?最简单直接的方式是数学中的均方误差
\(MSE=\frac{1}{m}\sum_{i=1}^{m} (f(x_i)-y_i)^2\)

均方误差损失(MSE)在回归问题损失定义与优化中广泛应用,但是在逻辑回归问题中不太适用。 因为Sigmoid 函数的变换使得我们最终得到损失函数曲线如下图所示,是非常不光滑凹凸不平的.

我们希望损失函数如下的凸函数。凸优化问题中,局部最优解同时也是全局最优解


逻辑回归模型场景
下,我们会改用
对数损失函数(二元交叉熵损失)
,这个损失函数同样能很好地衡量参数好坏,又能保证凸函数的特性。对数损失函数的公式如下:

\(J(\theta)=-\frac{1}{m} [\sum_{i=1}^{m}y^{(i)}\log{h_{\theta}(x^{(i)})-(1-y^{(i)})\log{(1-h_{\theta}(x^{(i)})})}]\)

其中
\(h_{\theta}(x^{(i)})\)
表示的可以说是根据这个h函数预测的样本值,
\(y^{(i)}\)
表示样本取值,在其为正样本时取值为1,负样本时取值为0,正负样本就是我们之前说的分的那两类,比如正常邮件是正样本,垃圾邮件是负样本,我们分这两种情况来看看:

\(y^{(i)}=0\)
:样本为负样本时,若
\(h_{\theta}(x^{(i)})\)
接近1(预测值为正样本),那么
\(-\log{(1-h_\theta (x))}\)
值就很大,也就是对应的惩罚也越大
\(y^{(i)}=1\)
:样本为正样本时,若
\(h_{\theta}(x^{(i)})\)
接近0(预测值为负样本),那么
\(-\log{(h_\theta (x))}\)
值就很大,也就是对应的惩罚也越大
通过惩罚大小就可以判断出参数好坏了。

梯度下降

损失函数可以用于衡量模型参数好坏,但我们还需要一些优化方法找到最佳的参数(使得当前的损失函数值最小)。最常见的算法之一是「梯度下降法」,逐步迭代减小损失函数(在凸函数场景下非常容易使用)。如同下山,找准方向(斜率),每次迈进一小步,直至山底。

梯度下降(Gradient Descent)法,是一个一阶最优化算法,通常也称为最速下降法。要使用梯度下降法找到一个函数的局部极小值,必须向函数上当前点对应梯度(或者是近似梯度)的反方向的规定步长距离点进行迭代搜索。

上图中,
\(\alpha\)
称为学习率(learning rate),直观的意义是,在函数向极小值方向前进时每步所走的步长。太大一般会错过极小值,太小会导致迭代次数过多。

进一步学习梯度算法

正则化与缓解过拟合

曲线3就是过拟合,学的太死板了也就是,那咋办呢?

过拟合的一种处理方式是正则化,我们通过对损失函数添加正则化项,可以约束参数的搜索空间,从而保证拟合的决策边界并不会抖动非常厉害。如下图为对数损失函数中加入正则化项(这里是一个L2正则化项)

在损失函数后面的那一项就是L2正则化项,L2 正则化可以看作是对参数空间内欧氏距离的惩罚。其几何效果是缩小所有参数,使它们更加接近原点,从而降低模型复杂度,会惩罚较大的参数值,但不会直接将它们缩减为零。这种“平滑”的惩罚方式促使模型将所有特征的权重均衡分配,从而减少过拟合。

我们依然可以采用梯度下降对加正则化项的损失函数进行优化。

代码实现

下面使用了scikit-learn提供的乳腺癌数据集作为示例数据集

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
from sklearn.datasets import load_breast_cancer

# 加载数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 拆分数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 对特征进行标准化处理
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 初始化并训练逻辑回归模型
model = LogisticRegression()
model.fit(X_train, y_train)

# 使用模型进行预测
y_pred = model.predict(X_test)

# 计算并打印准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")

# 打印混淆矩阵
conf_matrix = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
print(conf_matrix)

# 打印分类报告
class_report = classification_report(y_test, y_pred)
print("Classification Report:")
print(class_report)

结果如下

Accuracy: 0.98
Confusion Matrix:
[[ 62   1]
 [  2 106]]
Classification Report:
              precision    recall  f1-score   support

           0       0.97      0.98      0.98        63
           1       0.99      0.98      0.99       108

    accuracy                           0.98       171
   macro avg       0.98      0.98      0.98       171
weighted avg       0.98      0.98      0.98       171

我们再用python构建一个原生的算法模型,用到了交叉损失函数和正则化

import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler


# Sigmoid 函数,将线性组合映射到 [0, 1] 区间,用于预测概率
def sigmoid(z):
    return 1 / (1 + np.exp(-z))


# 初始化模型参数,权重设为0,偏置设为0
def initialize_params(dim):
    weights = np.zeros((dim, 1))  # 权重向量,初始为全零
    bias = 0  # 偏置,初始为零
    return weights, bias


# 前向传播与反向传播,计算预测值、损失函数值以及梯度
def propagate(weights, bias, X, Y, regularization_strength):
    m = X.shape[1]  # 样本数量

    # 前向传播:计算预测值
    A = sigmoid(np.dot(weights.T, X) + bias)  # 线性组合后通过Sigmoid函数得到预测值

    # 计算对数损失函数(带正则化项)
    cost = -1 / m * np.sum(Y * np.log(A) + (1 - Y) * np.log(1 - A)) + (regularization_strength / (2 * m)) * np.sum(
        np.square(weights))

    # 反向传播:计算权重和偏置的梯度(包括正则化项)
    dw = 1 / m * np.dot(X, (A - Y).T) + (regularization_strength / m) * weights  # 计算权重的梯度(带正则化项)
    db = 1 / m * np.sum(A - Y)  # 计算偏置的梯度(偏置不正则化)

    gradients = {"dw": dw, "db": db}  # 将梯度存储在字典中

    return gradients, cost


# 梯度下降优化,更新权重和偏置
def optimize(weights, bias, X, Y, num_iterations, learning_rate, regularization_strength):
    costs = []  # 记录每100次迭代的损失值

    for i in range(num_iterations):
        # 计算梯度和损失
        gradients, cost = propagate(weights, bias, X, Y, regularization_strength)

        # 获取梯度值
        dw = gradients["dw"]
        db = gradients["db"]

        # 更新权重和偏置
        weights -= learning_rate * dw  # 权重更新
        bias -= learning_rate * db  # 偏置更新

        # 每100次迭代打印一次损失
        if i % 100 == 0:
            costs.append(cost)
            print(f"Cost after iteration {i}: {cost}")

    params = {"weights": weights, "bias": bias}  # 存储最终的权重和偏置
    gradients = {"dw": dw, "db": db}  # 存储最终的梯度

    return params, gradients, costs


# 预测函数,将训练好的模型应用于新的数据
def predict(weights, bias, X):
    m = X.shape[1]  # 样本数量
    Y_prediction = np.zeros((1, m))  # 初始化预测结果矩阵
    A = sigmoid(np.dot(weights.T, X) + bias)  # 计算预测的概率值

    for i in range(A.shape[1]):
        # 将概率值转为0或1的分类结果
        Y_prediction[0, i] = 1 if A[0, i] > 0.5 else 0

    return Y_prediction


# 将以上各部分组合成一个完整的逻辑回归模型
def model(X_train, Y_train, num_iterations=2000, learning_rate=0.5, regularization_strength=0.1):
    dim = X_train.shape[0]  # 特征数量
    weights, bias = initialize_params(dim)  # 初始化权重和偏置

    # 通过梯度下降优化权重和偏置
    params, gradients, costs = optimize(weights, bias, X_train, Y_train, num_iterations, learning_rate,
                                        regularization_strength)

    # 获取优化后的权重和偏置
    weights = params["weights"]
    bias = params["bias"]

    return weights, bias, costs


# 加载乳腺癌数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 将 y 进行 reshape 使其成为二维数组
y = y.reshape(1, y.shape[0])

# 拆分数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y.T, test_size=0.2, random_state=42)

# 转置 X_train 和 X_test 以符合我们实现的逻辑回归模型的输入要求
X_train = X_train.T
X_test = X_test.T
y_train = y_train.T
y_test = y_test.T

# 对特征进行标准化处理
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train.T).T
X_test = scaler.transform(X_test.T).T

# 训练逻辑回归模型(带正则化)
weights, bias, costs = model(X_train, y_train, num_iterations=2000, learning_rate=0.01, regularization_strength=0.1)

# 使用训练好的模型进行预测
Y_prediction_train = predict(weights, bias, X_train)
Y_prediction_test = predict(weights, bias, X_test)

# 打印训练集和测试集上的准确率
print(f"Train accuracy: {100 - np.mean(np.abs(Y_prediction_train - y_train)) * 100}%")
print(f"Test accuracy: {100 - np.mean(np.abs(Y_prediction_test - y_test)) * 100}%")

下面是结果

Cost after iteration 0: 0.6931471805599453
Cost after iteration 100: 0.2543244526519929
Cost after iteration 200: 0.1918342038605185
Cost after iteration 300: 0.16348680375028227
Cost after iteration 400: 0.14665006862221902
Cost after iteration 500: 0.13525053919817978
Cost after iteration 600: 0.12689843726947214
Cost after iteration 700: 0.12044835639062768
Cost after iteration 800: 0.11527696015953119
Cost after iteration 900: 0.1110131308144327
Cost after iteration 1000: 0.10742059509404249
Cost after iteration 1100: 0.1043409206676583
Cost after iteration 1200: 0.10166339647566097
Cost after iteration 1300: 0.0993080193536485
Cost after iteration 1400: 0.09721534841672455
Cost after iteration 1500: 0.0953401769323753
Cost after iteration 1600: 0.09364743315495462
Cost after iteration 1700: 0.09210943796116201
Cost after iteration 1800: 0.09070401842998121
Cost after iteration 1900: 0.08941317838842508
Train accuracy: 98.24175824175825%
Test accuracy: 99.12280701754386%