
从 harfbuzz、qdrant 和 prometheus 出发,分别练习读懂字体的字形查找表、向量库的分层近邻图与监控库的时间块索引,并给出今晚能跑通的最小路径。
cmap 增加格式 15,COLR 增加 PaintGlyph2,GSUB、GPOS、GDEF、BASE、JSTF 各多一份 24 位版本,TrueType Collection 的目录也扩了。1libharfbuzz-raster)、矢量(libharfbuzz-vector)、GPU(libharfbuzz-gpu)三个库不再算实验特性,API 与 ABI 的稳定性承诺从这一版起覆盖它们。1hb_font_set_face() 的 use-after-free,以及它切到变体轴更多的 face 之后 hb_font_set_variation() 的堆缓冲区溢出。前一个函数在这一版被弃用,官方建议改用 hb_font_create()。1cmap 给出每个码点对应的字形;标准格式的字形号是 16 位,一个字体最多 65,535 个字形。15.0.0 扩的正是这道墙。AV:$ hb-shape DejaVuSans.ttf "AV"
[A=0+1270|V=1+1401]
$ hb-shape --features=-kern DejaVuSans.ttf "AV"
[A=0+1401|V=1+1401]A 的步进从 1270 回到 1401,差值 131 的单位是 1/2048 em(这个字体的 UPEM 是 2048)。1$ hb-shape DejaVuSans.ttf "ffi"
[uniFB03=0+1980]
$ hb-shape DejaVuSans.ttf "مرحبا"
[uniFE8E=4+624|uniFE92=3+618|uniFEA3=2+1266|uniFEAE=1+1130|uniFEE3=0+1097]ffi 三个字符变成一个连字字形。阿拉伯文的五个字符变成五个上下文形态,cluster 从 4 递减到 0:右起书写的文字,输出顺序就是视觉顺序。hb-shape、hb-subset 是构建产物,不用装系统包。curl -LO https://github.com/harfbuzz/harfbuzz/archive/refs/tags/15.0.0.tar.gz
tar xzf 15.0.0.tar.gz && cd harfbuzz-15.0.0
pip install meson ninja
meson setup build --buildtype=release -Ddocs=disabled
ninja -C build
./build/util/hb-shape --versionhb-shape (HarfBuzz) 15.0.0。--features=-kern,对比每个字形的步进;把 kern 换成 liga,连字会重新变回三个字形。a + U+0301 + b,输出是 [aacute=0+1255|b=2+1300]:附加符号并进了基字的 cluster 0,b 留在 2。hb-subset DejaVuSans.ttf --text="Hello 世界" -o sub.ttf,759,720 字节变成 4,316 字节。再 shape 一次 Hello,字形号从 gid2 重新编号,两个 l 共用 gid4。.notdef,说明 shaping 依赖字体真的带那些字形,算法补齐不了。hb_font_set_face() 从这一版起弃用,升级后改用 hb_font_create()。1m 限制每层的最大度数,默认 16。8ef 是搜索时的候选范围。 建索引时用 ef_construct(默认 100),查询时用 ef,默认跟着 ef_construct 走。8full_scan_threshold 默认 10,000 KB,查询计划估出的候选量小于它就改走全扫。8ef_construct 触发重建。8curl -LO https://github.com/qdrant/qdrant/releases/download/v1.20.0/qdrant-x86_64-unknown-linux-gnu.tar.gz
tar xzf qdrant-x86_64-unknown-linux-gnu.tar.gz
QDRANT__STORAGE__STORAGE_PATH=./qd ./qdrant$ curl -s http://127.0.0.1:6333/
{"title":"qdrant - vector search engine","version":"1.20.0","commit":"222b2e4…"}m = 16、ef_construct = 100 的集合,把 indexing_threshold 放到 1000 KB,再灌 20,000 个点:本机用了 2.1 秒,两秒后 indexed_vectors_count 到 20000。indexed_vectors_count 停在 0:两万个 128 维向量只占十兆左右,够不上 10,000 KB 的全扫优先线。ef 看召回。 40 条查询,ef = 16 时 recall@10 是 0.970,ef = 32 起回到 1.000。"exact": true,服务端 0.46 ms;走图时 0.07 ms,差六倍多。turbo8 再跑。 同一批查询在 ef = 64 时 recall@10 是 0.980:一维一字节,换掉 2% 的召回。{"field_name": "offers[].shop", "field_schema": {"type": "keyword", "nested": "offers"}}。嵌套过滤里的键要写相对路径(shop、price),照抄 offers[].shop 一条都匹配不上——本机是 4,000 对 0。m = 16 的集合升级后图会小一截,重建索引能吃到这个改动。turbo8 用召回换内存;对召回敏感的场景先在真实查询上量一遍再切。golang.org/x/net 升到 v0.60.0,修 HTTP/2 的五个公告(GO-2026-6603、6610、6611、6612、6617)。10scrape_interval 定时请求目标暴露的文本;本机配成每秒抓一次自己。13chunks/ 存这个时间窗里的样本,index 把指标名和标签映射到序列,meta.json 记块的元信息。13cat > prom.yml <<'YAML'
global:
scrape_interval: 1s
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['127.0.0.1:9090']
YAML
./prometheus --config.file=prom.yml --storage.tsdb.path=./prom-data$ curl -s 'http://127.0.0.1:9090/api/v1/query?query=prometheus_tsdb_head_series' | jq -r '.data.result[0].value[1]'
704127.0.0.1:9090/metrics 的抓取。prom-data 下只有 chunks_head/ 和 wal/,两小时块还没到落盘的时候。promtool tsdb create-blocks-from openmetrics synthetic.om blocks 回填。本机 720,000 个样本、200 条序列、每条 3,600 个点,生成一个块用了 0.67 秒。promtool tsdb analyze blocks 会打印序列数、标签名与 postings:本机 200 条序列、3 个标签名、205 组唯一标签对;720,000 个样本被切成 6,200 个 chunk。promtool tsdb dump blocks 逐行打印时间戳与数值,和 PromQL 查出来的结果对得上。chunks_head/ 里,备份要按文档走快照。13| 想弄清楚的查找结构 | 仓库与本期信号 | 最小条件 | 第一条可观察路径 | 主要限制 |
|---|---|---|---|---|
| 一串字符最终变成哪几个字形、摆在哪 | harfbuzz · 15.0.0 北京时间 10 月 23 日凌晨发布 | g++、python3,meson + ninja 构建约四分钟 | hb-shape 跑一次 AV,再用 --features=-kern 对比步进 | 字形得字体里真有;缺字形只能排 .notdef |
| 最近的向量建成了什么图 | qdrant · v1.20.0 北京时间 10 月 22 日夜里发布 | 一个 92 MB 的静态二进制 | 灌两万点,改 ef 看 recall@10 从 0.970 到 1.000 | 小集合走全扫,indexing_threshold 不调就看不到图 |
| 每条序列落在哪个块、压到多小 | prometheus · v3.15.1 北京时间 10 月 22 日凌晨发布 | 一个静态二进制,五行配置 | promtool 回填 72 万点,比两种曲线的每样本字节数 | 本地存储不集群、不复制,两小时才落一个块 |
github.com
github.com
harfbuzz.github.io
github.com
github.com
github.com
qdrant.tech
qdrant.tech
github.com
github.com
github.com
github.com
prometheus.io
github.com
This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.