<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aleksandr Yershov</title>
    <description>The latest articles on DEV Community by Aleksandr Yershov (@alex_602).</description>
    <link>https://dev.to/alex_602</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3966198%2F7057f0fe-2444-4505-be34-25d0b7615bdf.png</url>
      <title>DEV Community: Aleksandr Yershov</title>
      <link>https://dev.to/alex_602</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alex_602"/>
    <language>en</language>
    <item>
      <title>Store embeddings at a fidelity budget, not a bit-count — a lossy vector codec for Go</title>
      <dc:creator>Aleksandr Yershov</dc:creator>
      <pubDate>Thu, 02 Jul 2026 14:45:49 +0000</pubDate>
      <link>https://dev.to/alex_602/store-embeddings-at-a-fidelity-budget-not-a-bit-count-a-lossy-vector-codec-for-go-2ojl</link>
      <guid>https://dev.to/alex_602/store-embeddings-at-a-fidelity-budget-not-a-bit-count-a-lossy-vector-codec-for-go-2ojl</guid>
      <description>&lt;p&gt;An embedding is a &lt;code&gt;[]float32&lt;/code&gt;. A store of a million of them is 512 MB of&lt;br&gt;
float32 that you will spend most of its life scanning for nearest neighbours.&lt;br&gt;
But here's the thing about that 512 MB: &lt;strong&gt;almost none of it is load-bearing.&lt;/strong&gt;&lt;br&gt;
Nearest-neighbour search only cares about the &lt;em&gt;geometry&lt;/em&gt; of the vectors —&lt;br&gt;
their relative angles — not the exact bits. Store them bit-exact and you're&lt;br&gt;
paying full price for precision your retrieval never uses.&lt;/p&gt;

&lt;p&gt;qdf — a schemaless binary serializer for Go — has an opt-in lossy vector codec&lt;br&gt;
built on that observation. Instead of asking you how many bits to keep, it asks&lt;br&gt;
what fidelity you need — "keep cosine similarity ≥ 0.99" — and then spends the&lt;br&gt;
fewest bytes that clears that bar. This post is about the knob, the numbers, and&lt;br&gt;
when you should (and shouldn't) turn it on.&lt;/p&gt;
&lt;h2&gt;
  
  
  The knob is a fidelity budget, not a bit-width
&lt;/h2&gt;

&lt;p&gt;Every other quantizer I've used makes you pick a representation: int8, 4-bit,&lt;br&gt;
this many centroids. That's backwards — you don't care about bits, you care&lt;br&gt;
about whether retrieval still works. qdf inverts it. You set a &lt;strong&gt;budget&lt;/strong&gt; on the&lt;br&gt;
output quality and the codec picks the bits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoderWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptLossyVec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetVectorBudget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinCosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.99&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// or MaxRelError / TargetSNR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three ways to state the budget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;MinCosine(0.99)&lt;/code&gt;&lt;/strong&gt; — bound the minimum cosine similarity between the
original and reconstructed vector. This is the one for embeddings: cosine is
what your ANN index compares.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;MaxRelError(1e-3)&lt;/code&gt;&lt;/strong&gt; — bound the per-vector relative L2 error. For when the
magnitude matters, not just the direction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;TargetSNR(40)&lt;/code&gt;&lt;/strong&gt; — target a signal-to-noise ratio in dB, for signal-ish
float columns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The codec only touches &lt;code&gt;[]float32&lt;/code&gt; / &lt;code&gt;[]float64&lt;/code&gt; columns of a &lt;code&gt;[]struct&lt;/code&gt;, and&lt;br&gt;
only slices long enough to amortize its header (short vectors fall back to the&lt;br&gt;
lossless path automatically). Everything else in the struct — the IDs, the&lt;br&gt;
metadata — encodes losslessly as usual.&lt;/p&gt;
&lt;h2&gt;
  
  
  How it spends the bytes
&lt;/h2&gt;

&lt;p&gt;Under the hood the pipeline is: &lt;strong&gt;rotate → quantize → entropy-code&lt;/strong&gt;, with a&lt;br&gt;
never-larger fallback.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;Hadamard rotation&lt;/strong&gt; spreads each vector's energy evenly across its
dimensions. This is the quiet workhorse — it turns a few large-magnitude
components into many similar ones, which makes the quantization error
isotropic and, crucially, makes the codec behave the same on "nice" smooth
vectors and on adversarial ones (more on that below).&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;scalar or E8-lattice quantizer&lt;/strong&gt; maps the rotated components to a grid
sized to hit your budget. The lattice option packs the same fidelity into
fewer bits by exploiting that rotated components cluster near a sphere.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;static rANS entropy pass&lt;/strong&gt; squeezes the residual redundancy out of the
quantized symbols.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never-larger fallback:&lt;/strong&gt; if the whole lossy body ever comes out bigger than
the plain lossless encoding — which can happen on tiny or already-compact
columns — qdf ships the lossless bytes instead. Turning the codec on can
never inflate your output. (This is the same discipline the rest of the
format runs on; see the codec-selection writeup.)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  The numbers — reproduce them yourself
&lt;/h2&gt;

&lt;p&gt;Here's a harness you can paste and run. It builds a corpus, sweeps the cosine&lt;br&gt;
budget, and measures the &lt;em&gt;worst&lt;/em&gt; cosine actually achieved across every vector —&lt;br&gt;
not the average, the worst, because a floor is only a floor if nothing falls&lt;br&gt;
through it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoderWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptLossyVec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetVectorBudget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinCosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lossy&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Doc&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lossy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// then: worst = min over i of cosine(docs[i].Emb, back[i].Emb)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run on 2000 vectors, &lt;code&gt;float32&lt;/code&gt;, on &lt;code&gt;ubuntu-latest&lt;/code&gt;. Two corpora: a &lt;em&gt;smooth&lt;/em&gt;&lt;br&gt;
one (sinusoids — the flattering case every quantizer paper uses) and a&lt;br&gt;
&lt;em&gt;random-unit&lt;/em&gt; one (Gaussian, L2-normalized — the honest worst case, essentially&lt;br&gt;
incompressible and much closer to what a real embedding model emits).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;128 dimensions&lt;/strong&gt; (lossless baseline: 520 B/vec):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;budget&lt;/th&gt;
&lt;th&gt;random-unit B/vec&lt;/th&gt;
&lt;th&gt;worst cosine&lt;/th&gt;
&lt;th&gt;vs lossless&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cos≥0.99&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;72.3&lt;/td&gt;
&lt;td&gt;0.9955&lt;/td&gt;
&lt;td&gt;−86%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cos≥0.995&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;80.3&lt;/td&gt;
&lt;td&gt;0.9977&lt;/td&gt;
&lt;td&gt;−85%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cos≥0.999&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;98.8&lt;/td&gt;
&lt;td&gt;0.9995&lt;/td&gt;
&lt;td&gt;−81%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;768 dimensions&lt;/strong&gt; (lossless baseline: 3080 B/vec):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;budget&lt;/th&gt;
&lt;th&gt;random-unit B/vec&lt;/th&gt;
&lt;th&gt;worst cosine&lt;/th&gt;
&lt;th&gt;vs lossless&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cos≥0.99&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;407&lt;/td&gt;
&lt;td&gt;0.9914&lt;/td&gt;
&lt;td&gt;−87%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cos≥0.995&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;470&lt;/td&gt;
&lt;td&gt;0.9957&lt;/td&gt;
&lt;td&gt;−85%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cos≥0.999&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;618&lt;/td&gt;
&lt;td&gt;0.9992&lt;/td&gt;
&lt;td&gt;−80%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ijtc4abt1zgcl7jrkjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2ijtc4abt1zgcl7jrkjr.png" alt="Worst-case cosine achieved versus bytes per vector, 128-dim and 768-dim" width="768" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two things worth calling out, because they're the honest part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The budget holds.&lt;/strong&gt; At &lt;code&gt;cos≥0.99&lt;/code&gt; the worst vector in 2000 lands at 0.9914–
0.9955 — above the floor, every time. The knob means what it says.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Random ≈ smooth.&lt;/strong&gt; On the same run, the smooth corpus compressed to 72.1
B/vec and random-unit to 72.3 — a 0.3% difference. Most quantizers fall apart
on incompressible input; the Hadamard rotation is why this one doesn't. If a
vector codec only publishes numbers on smooth synthetic data, be suspicious.
These are within noise of each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At &lt;code&gt;cos≥0.99&lt;/code&gt;, 128-dim vectors land around 4.5 bits/dimension versus float32's&lt;br&gt;
32 — a 7× shrink for a cosine hit you'd struggle to measure in recall@10 on most&lt;br&gt;
indexes.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to turn it on — and when not to
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Storing/shipping embeddings for ANN retrieval&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — cosine is exactly the metric the budget defends.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You can tolerate ~0.99 cosine (most RAG / semantic search)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — start at &lt;code&gt;MinCosine(0.99)&lt;/code&gt;, tighten if recall dips.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vectors are the bulk of your payload&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — this is where −80…−87% actually moves your bill.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need bit-exact reconstruction (dedup by hash, checksums, reproducible training)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — use &lt;code&gt;OptBalanced&lt;/code&gt;; lossy is opt-in for a reason.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short vectors (&amp;lt; 32 elems) or vectors are a rounding error in your payload&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Skip&lt;/strong&gt; — the codec falls back to lossless anyway; no harm, no gain.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Downstream compares exact float equality&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — quantization changes the bits by design.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule of thumb: if your pipeline already treats embeddings as approximate —&lt;br&gt;
and ANN search does — then storing them bit-exact is precision you're paying for&lt;br&gt;
and throwing away. Pick the cosine floor your retrieval can live with and let&lt;br&gt;
the codec find the bits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/alex60217101990/qdf
go run github.com/alex60217101990/qdf/examples/embeddings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runnable&lt;br&gt;
&lt;a href="https://github.com/alex60217101990/qdf/tree/main/examples/embeddings" rel="noopener noreferrer"&gt;&lt;code&gt;examples/embeddings&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
is the harness above, trimmed. Swap in your own vectors, sweep the budget, and&lt;br&gt;
watch the worst-case cosine — if you find a corpus where the floor doesn't hold,&lt;br&gt;
that's a bug and there's an issue template for it. Measured beats anecdotal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/alex60217101990/qdf" rel="noopener noreferrer"&gt;https://github.com/alex60217101990/qdf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>ai</category>
      <category>embeddings</category>
      <category>compression</category>
    </item>
    <item>
      <title>How a Go serializer picks the smallest encoding for every column — and never guesses wrong</title>
      <dc:creator>Aleksandr Yershov</dc:creator>
      <pubDate>Wed, 01 Jul 2026 18:10:36 +0000</pubDate>
      <link>https://dev.to/alex_602/how-a-go-serializer-picks-the-smallest-encoding-for-every-column-and-never-guesses-wrong-4mo0</link>
      <guid>https://dev.to/alex_602/how-a-go-serializer-picks-the-smallest-encoding-for-every-column-and-never-guesses-wrong-4mo0</guid>
      <description>&lt;p&gt;There is no single best way to encode a batch of records. A column of HTTP&lt;br&gt;
status codes wants run-length encoding. A column of monotonically increasing&lt;br&gt;
timestamps wants delta coding. A column of trace IDs wants substring&lt;br&gt;
compression. A column of embeddings wants something else entirely. Pick one&lt;br&gt;
codec for the whole message and you leave most of the win on the floor.&lt;/p&gt;

&lt;p&gt;qdf — a schemaless binary serializer for Go — takes the opposite approach: it&lt;br&gt;
transposes a &lt;code&gt;[]struct&lt;/code&gt; into columns and then &lt;strong&gt;chooses a codec per column&lt;/strong&gt;,&lt;br&gt;
measuring the candidates instead of guessing. And it does it under a rule that&lt;br&gt;
makes the choice safe to turn on blindly: &lt;strong&gt;it can never produce a larger column&lt;br&gt;
than the plain encoding&lt;/strong&gt;. This post is about how that works and why the&lt;br&gt;
never-larger rule is the part that actually matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: transpose to columns
&lt;/h2&gt;

&lt;p&gt;Given a &lt;code&gt;[]struct&lt;/code&gt;, row-major encoding writes field-by-field, record after&lt;br&gt;
record. That's what json, msgpack, and protobuf do — and it's why a repeated&lt;br&gt;
&lt;code&gt;"region":"eu-west-1"&lt;/code&gt; costs its full length in every row.&lt;/p&gt;

&lt;p&gt;qdf, under its Dense/columnar path, pivots the batch: all the &lt;code&gt;Status&lt;/code&gt; values&lt;br&gt;
together, all the &lt;code&gt;Timestamp&lt;/code&gt; values together, all the &lt;code&gt;TraceID&lt;/code&gt; values&lt;br&gt;
together. Now each column is a homogeneous array — and homogeneous arrays are&lt;br&gt;
exactly what specialized codecs are good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: a menu of codecs per column type
&lt;/h2&gt;

&lt;p&gt;Once you're looking at one column, the codec space opens up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integers / durations / counts&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FOR&lt;/strong&gt; (frame of reference) — subtract the column minimum, bit-pack the
residuals. Great for bounded ranges (ports, status codes, small counters).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delta + FOR&lt;/strong&gt; — encode the first value plus bit-packed deltas against a
running predictor. This is the one for monotonic sequences (timestamps, ids).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RLE&lt;/strong&gt; — one &lt;code&gt;(value, run-length)&lt;/code&gt; pair per run. Wins hard on enum-like
columns where the same value repeats (log levels, booleans, sparse counters).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dictionary&lt;/strong&gt; — a table of distinct values plus a bit-packed index per row.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patched FOR (PFOR)&lt;/strong&gt; — FOR with an exception list for the few outliers that
would otherwise blow up the bit width.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Floats&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gorilla XOR&lt;/strong&gt; — XOR each sample against the previous one and store only the
differing bits. Built for smooth time-series (sensor readings, gauges).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ALP&lt;/strong&gt; — for decimal-ish &lt;code&gt;[]float64/[]float32&lt;/code&gt; that are secretly fixed-point
(prices, quantized values), store the integer mantissa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Strings&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dictionary&lt;/strong&gt; and &lt;strong&gt;front-coding&lt;/strong&gt; for low-cardinality or shared-prefix
columns (SIDs, DNs, paths, URLs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alphabet packing&lt;/strong&gt; for high-cardinality values drawn from a small alphabet
(hex / base32 / base64 IDs — store each char in &lt;code&gt;ceil(log2|A|)&lt;/code&gt; bits).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FSST&lt;/strong&gt; — a learned table of up to 255 substrings for high-cardinality free
text (log lines, URLs), compressing at the byte level.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Whole body&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;rANS&lt;/strong&gt; — a final static order-0 entropy pass that squeezes the residual
byte-entropy the structural codecs leave behind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a lot of choices. The interesting question is not "which codecs exist"&lt;br&gt;
— it's "how do you pick, per column, without a config file and without getting&lt;br&gt;
it wrong."&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: probe, then pick the smallest
&lt;/h2&gt;

&lt;p&gt;For each column, qdf runs a cheap bounded probe that predicts the encoded size&lt;br&gt;
of the viable candidates, then emits the smallest. The probe is designed to be&lt;br&gt;
much cheaper than actually encoding every candidate — it estimates from column&lt;br&gt;
statistics (min/max, run structure, distinct count) rather than doing the full&lt;br&gt;
work five times.&lt;/p&gt;

&lt;p&gt;The expensive tiers (Gorilla, FSST, rANS) are gated behind opt-in flags&lt;br&gt;
(&lt;code&gt;OptCompression&lt;/code&gt;), because they trade encode CPU for bytes and you don't always&lt;br&gt;
want that trade. The cheap structural codecs (FOR, Delta, RLE, dictionary) run&lt;br&gt;
on the default &lt;code&gt;OptBalanced&lt;/code&gt; tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: the never-larger guarantee
&lt;/h2&gt;

&lt;p&gt;Here's the rule that ties it together: &lt;strong&gt;for every codec, qdf compares the&lt;br&gt;
candidate encoding against the plain one and emits the compressed form only when&lt;br&gt;
it is strictly smaller.&lt;/strong&gt; If a "compression" codec would make a column bigger —&lt;br&gt;
which absolutely happens on adversarial or already-incompressible data — qdf&lt;br&gt;
emits the plain encoding instead.&lt;/p&gt;

&lt;p&gt;The consequence is the useful part: &lt;strong&gt;turning compression on can never inflate&lt;br&gt;
your output.&lt;/strong&gt; You don't have to reason about whether your data is a good fit.&lt;br&gt;
You don't have to benchmark before flipping the flag. The worst case is "no&lt;br&gt;
better than plain," never "worse than plain." That property is what lets qdf&lt;br&gt;
auto-select aggressively instead of shipping a pile of knobs.&lt;/p&gt;

&lt;p&gt;It also composes down to the whole message: the final rANS pass is applied only&lt;br&gt;
when it shrinks the body, so &lt;code&gt;OptCompression&lt;/code&gt; is never larger than&lt;br&gt;
&lt;code&gt;OptBalanced&lt;/code&gt;, which is never larger than the plain encoding.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it buys you, measured
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj7sf7vc7bq34q9bsa4pq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj7sf7vc7bq34q9bsa4pq.png" alt="Wire size on an adalanche host dump: json 532 KB, msgpack 500 KB, qdf balanced 209 KB, qdf compression 127 KB" width="768" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On real telemetry batches (GitHub Actions &lt;code&gt;ubuntu-latest&lt;/code&gt;, Go 1.26), wire size&lt;br&gt;
versus protobuf:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;batch&lt;/th&gt;
&lt;th&gt;qdf balanced&lt;/th&gt;
&lt;th&gt;qdf compression&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OTLP traces&lt;/td&gt;
&lt;td&gt;−75%&lt;/td&gt;
&lt;td&gt;−77%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;logs&lt;/td&gt;
&lt;td&gt;−72%&lt;/td&gt;
&lt;td&gt;−72%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTB bids&lt;/td&gt;
&lt;td&gt;−25%&lt;/td&gt;
&lt;td&gt;−39%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;events&lt;/td&gt;
&lt;td&gt;−39%&lt;/td&gt;
&lt;td&gt;−39%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IoT floats&lt;/td&gt;
&lt;td&gt;−24%&lt;/td&gt;
&lt;td&gt;−29%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuo0skoacj9htm6xhm5z8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuo0skoacj9htm6xhm5z8.png" alt="Percent smaller than protobuf per batch, balanced vs compression tier" width="768" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The wins track the data: OTLP and logs are string-heavy and repetitive, so&lt;br&gt;
interning + columnar string codecs dominate; RTB and IoT are less repetitive, so&lt;br&gt;
the numeric codecs do the work and the margins are smaller. That's the honest&lt;br&gt;
shape of it — the codec picker is only as good as the redundancy in your data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The discipline behind the menu
&lt;/h2&gt;

&lt;p&gt;The codec list above is the survivors. The measure-first process that picked&lt;br&gt;
per-column codecs also &lt;em&gt;killed&lt;/em&gt; a lot of ideas that looked good on paper:&lt;br&gt;
GPU-offloaded rANS (only wins on multi-MB single bodies — qdf messages are KB),&lt;br&gt;
SIMD-gathered rANS (5× slower than scalar interleaved pre-AVX512),&lt;br&gt;
multicore columnar encode (memory-bandwidth-bound, ~1.0×), and a learned&lt;br&gt;
ScaNN-style vector quantizer (measured under 1pp recall gain). Every codec in&lt;br&gt;
the menu earned its slot on a benchmark, and none of them can make your output&lt;br&gt;
bigger. That's the whole design in one sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/alex60217101990/qdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// or OptCompression&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Record&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runnable examples (telemetry, query-the-bytes, embeddings, streaming,&lt;br&gt;
zero-alloc decode) are in&lt;br&gt;
&lt;a href="https://github.com/alex60217101990/qdf/tree/main/examples" rel="noopener noreferrer"&gt;&lt;code&gt;examples/&lt;/code&gt;&lt;/a&gt;, and&lt;br&gt;
the per-codec details live in the repo.&lt;/p&gt;

&lt;p&gt;If you find a payload where a codec loses that it shouldn't — there's an issue&lt;br&gt;
template for exactly that. Measured beats anecdotal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/alex60217101990/qdf" rel="noopener noreferrer"&gt;https://github.com/alex60217101990/qdf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>performance</category>
      <category>serialization</category>
      <category>compression</category>
    </item>
    <item>
      <title>Shrinking AI embeddings on the wire — a lossy vector codec that beats Google's TurboQuant at equal recall</title>
      <dc:creator>Aleksandr Yershov</dc:creator>
      <pubDate>Sat, 27 Jun 2026 09:18:40 +0000</pubDate>
      <link>https://dev.to/alex_602/shrinking-ai-embeddings-on-the-wire-a-lossy-vector-codec-that-beats-googles-turboquant-at-equal-4hme</link>
      <guid>https://dev.to/alex_602/shrinking-ai-embeddings-on-the-wire-a-lossy-vector-codec-that-beats-googles-turboquant-at-equal-4hme</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A developer's walk-through of &lt;a href="https://github.com/alex60217101990/qdf" rel="noopener noreferrer"&gt;&lt;code&gt;qdf&lt;/code&gt;&lt;/a&gt;'s opt-in lossy vector codec: what it does,&lt;br&gt;
why it lands within a hair of the information-theoretic floor, and how it&lt;br&gt;
measures up against Google's TurboQuant on a reproducible benchmark.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The problem nobody budgets for
&lt;/h2&gt;

&lt;p&gt;A single 768-dimensional &lt;code&gt;float32&lt;/code&gt; embedding is &lt;strong&gt;3,072 bytes&lt;/strong&gt;. That sounds&lt;br&gt;
harmless until you have a few million of them. A 10M-document RAG index is&lt;br&gt;
~30 GB of &lt;em&gt;just vectors&lt;/em&gt; — before metadata, before the ANN graph, before&lt;br&gt;
replication. Embeddings are quietly the dominant storage and bandwidth line item&lt;br&gt;
of every vector database and every retrieval pipeline.&lt;/p&gt;

&lt;p&gt;Here's the thing: &lt;strong&gt;embeddings are not telemetry that must round-trip&lt;br&gt;
bit-for-bit.&lt;/strong&gt; Nobody cares whether coordinate 412 comes back as &lt;code&gt;0.0193847&lt;/code&gt; or&lt;br&gt;
&lt;code&gt;0.0193851&lt;/code&gt;. What you care about is that nearest-neighbour search returns &lt;em&gt;the&lt;br&gt;
same neighbours&lt;/em&gt; — i.e. that cosine similarity is preserved to a few decimal&lt;br&gt;
places. That is the exact regime where lossy quantization is free money, and&lt;br&gt;
it's why &lt;code&gt;qdf&lt;/code&gt; ships an &lt;strong&gt;opt-in&lt;/strong&gt; lossy codec for &lt;code&gt;[]float32&lt;/code&gt; / &lt;code&gt;[]float64&lt;/code&gt;&lt;br&gt;
fields (&lt;code&gt;OptLossyVec&lt;/code&gt;). Off by default, so no exact workload is ever silently&lt;br&gt;
approximated; one flag flip when you want it.&lt;/p&gt;

&lt;p&gt;The part I find genuinely nice as an application developer: you don't bolt on a&lt;br&gt;
second system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnngm2xlt4qsw413hrhv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnngm2xlt4qsw413hrhv8.png" alt="One self-describing blob, not two stores" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You serialize your &lt;code&gt;[]struct{ ID, Text, Emb []float32 }&lt;/code&gt; with the same&lt;br&gt;
&lt;code&gt;Marshal&lt;/code&gt;/&lt;code&gt;Unmarshal&lt;/code&gt; you already use. The scalar and string fields stay&lt;br&gt;
bit-exact; the vector field is batched into one lossy column; the blob is&lt;br&gt;
self-describing, so &lt;code&gt;Unmarshal&lt;/code&gt; rebuilds the records with &lt;strong&gt;no flag and no side&lt;br&gt;
schema&lt;/strong&gt;. Metadata store and vector store collapse into one blob with one write&lt;br&gt;
path. (See &lt;code&gt;Example_aiEmbeddingStore&lt;/code&gt; in the package docs.)&lt;/p&gt;
&lt;h2&gt;
  
  
  What the codec actually does
&lt;/h2&gt;

&lt;p&gt;For each float-vector column the encoder runs a four-idea pipeline. Three of the&lt;br&gt;
four are things a CPU serializer can do that a fixed-width GPU codebook cannot —&lt;br&gt;
and that's exactly where the size edge comes from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgmqa0rh6fxq112mzm9ay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgmqa0rh6fxq112mzm9ay.png" alt="OptLossyVec encode pipeline" width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Randomized Hadamard rotation&lt;/strong&gt; — &lt;code&gt;R = (1/√n)·H·D&lt;/code&gt;, a seed-driven sign-flip
diagonal &lt;code&gt;D&lt;/code&gt; composed with the Walsh–Hadamard transform &lt;code&gt;H&lt;/code&gt;. It spreads
per-coordinate outliers evenly so the data becomes approximately Gaussian —
the ideal shape for low-bit quantization — at &lt;code&gt;O(n·log n)&lt;/code&gt; cost and with &lt;strong&gt;no
stored matrix&lt;/strong&gt;: just a &lt;code&gt;uint64&lt;/code&gt; seed on the wire. This is the same idea
Google's TurboQuant uses for KV-cache quantization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A lattice, not a grid.&lt;/strong&gt; The scalar quantizer snaps each coordinate to the
nearest multiple of a step &lt;code&gt;δ&lt;/code&gt; (the &lt;code&gt;Z&lt;/code&gt; lattice — a cube). The &lt;strong&gt;E8&lt;/strong&gt;
quantizer groups coordinates into 8-D blocks and snaps each to the nearest
point of E8, the densest packing in 8 dimensions. E8's Voronoi cell is
&lt;em&gt;rounder&lt;/em&gt; than the cube, so it spends fewer bits for the same distortion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy-code the indices.&lt;/strong&gt; After the rotation the quantization indices are
near-Gaussian — a peaked distribution. A fixed-width code wastes bits on that;
an order-0 &lt;strong&gt;rANS&lt;/strong&gt; pass (the same entropy stage the rest of &lt;code&gt;qdf&lt;/code&gt; uses)
recovers them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never-worse.&lt;/strong&gt; The encoder builds &lt;em&gt;both&lt;/em&gt; quantizers and the plain lossless
float encoding, and keeps whichever is smallest. &lt;code&gt;OptLossyVec&lt;/code&gt; is a hint, never
a commitment to inflate — an incompressible or exception-heavy column silently
falls back to lossless.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;NaN&lt;/code&gt;/&lt;code&gt;±Inf&lt;/code&gt; are pulled into an exception list before quantization and written&lt;br&gt;
back bit-exactly on decode, so non-finite values survive any budget untouched.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this is close to the performance ceiling
&lt;/h2&gt;

&lt;p&gt;This is the claim worth defending, so let me be precise about &lt;em&gt;which&lt;/em&gt; ceiling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distortion-rate.&lt;/strong&gt; For a fixed quantizer, the bits you must spend at a target&lt;br&gt;
distortion are bounded below by the source entropy after the optimal transform.&lt;br&gt;
The pipeline attacks every term of that bound:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Hadamard rotation &lt;strong&gt;decorrelates and Gaussianizes&lt;/strong&gt; the coordinates. Rate-
distortion theory says the Gaussian is the worst case for a &lt;em&gt;fixed&lt;/em&gt; coder but
the &lt;em&gt;best-understood&lt;/em&gt; case for an optimal one — and crucially the rotation
makes the per-coordinate distribution uniform, so a single step &lt;code&gt;δ&lt;/code&gt; is near-
optimal for every coordinate instead of being dragged around by outliers.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;E8 lattice&lt;/strong&gt; captures the space-filling (granular) gain. Its normalized
second moment is &lt;code&gt;G ≈ 0.0717&lt;/code&gt; versus the scalar cube's &lt;code&gt;1/12 ≈ 0.0833&lt;/code&gt; — a
&lt;strong&gt;~0.65 dB coding gain&lt;/strong&gt;, which is most of the gain available in 8 dimensions
short of an impractically large vector quantizer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;rANS&lt;/strong&gt; captures the entropy (coding) gain — the bits a fixed-width index
leaves on the table once the distribution is peaked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Granular gain + entropy gain are the two levers a &lt;em&gt;practical&lt;/em&gt; quantizer has.&lt;br&gt;
&lt;code&gt;qdf&lt;/code&gt; pulls both. The only thing left on the table is a higher-dimensional&lt;br&gt;
lattice (Leech in 24-D buys a further fraction of a dB) — which was prototyped&lt;br&gt;
and &lt;strong&gt;measured-killed&lt;/strong&gt;: the extra coset bookkeeping cost more than the packing&lt;br&gt;
saved at these rates. That's the signature of being near the practical floor — the next idea&lt;br&gt;
&lt;em&gt;loses&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implementation.&lt;/strong&gt; Separate from the bits-on-the-wire ceiling, the encoder is&lt;br&gt;
allocation-bound, not algorithm-bound, in steady state. Reusing scratch across&lt;br&gt;
calls (the pooled &lt;code&gt;Marshal&lt;/code&gt; path) takes a 256×768 batch from &lt;strong&gt;13,855 → 1,308&lt;br&gt;
allocs/op&lt;/strong&gt; and &lt;strong&gt;21.2 MB → 2.0 MB/op&lt;/strong&gt; — ~10× each — with byte-identical&lt;br&gt;
output. Profiling past that point shows the encoder is output-bound: there's no&lt;br&gt;
hot loop left to shave.&lt;/p&gt;
&lt;h2&gt;
  
  
  The benchmark: vs Google's TurboQuant (and naive, and PQ)
&lt;/h2&gt;

&lt;p&gt;All methods compared on the &lt;strong&gt;same&lt;/strong&gt; synthetic Gaussian corpus&lt;br&gt;
(2,000 vectors × 256 dims), each with pre-built, buffer-reusing scratch so the&lt;br&gt;
timing is apples-to-apples. Reproduce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run github.com/alex60217101990/qdf/cmd/qdf-vecbench@latest &lt;span class="nt"&gt;-synthetic&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 2000 &lt;span class="nt"&gt;-dim&lt;/span&gt; 256
&lt;span class="c"&gt;# raw rows live in cmd/qdf-vecbench/rd.csv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The money chart is recall-vs-size. A method is better when its curve sits to the&lt;br&gt;
&lt;strong&gt;left&lt;/strong&gt; — fewer bytes at the same recall.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9gav34quaxgv0zzw05m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9gav34quaxgv0zzw05m.png" alt="Recall@10 vs bytes per vector" width="799" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;qdf-lossy&lt;/code&gt; is Pareto-better than both scalar baselines across the whole useful&lt;br&gt;
recall band. Read off the iso-recall line at &lt;strong&gt;recall ≈ 0.90&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;bytes / vector&lt;/th&gt;
&lt;th&gt;recall@10&lt;/th&gt;
&lt;th&gt;notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;qdf-lossy&lt;/strong&gt; (knob 0.05)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;170.4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.931&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;smaller &lt;em&gt;and&lt;/em&gt; higher recall&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;naive scalar (5-bit)&lt;/td&gt;
&lt;td&gt;176.0&lt;/td&gt;
&lt;td&gt;0.901&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TurboQuant rotated-scalar (5-bit)&lt;/td&gt;
&lt;td&gt;184.0&lt;/td&gt;
&lt;td&gt;0.903&lt;/td&gt;
&lt;td&gt;rotation, but no entropy/lattice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At ~the same byte budget, &lt;code&gt;qdf&lt;/code&gt; delivers higher recall; at ~the same recall, it&lt;br&gt;
spends fewer bytes. &lt;code&gt;docs/LOSSY-VECTOR.md&lt;/code&gt; quotes the headline as&lt;br&gt;
&lt;strong&gt;≈17–22 % smaller at equal reconstruction quality&lt;/strong&gt; (−18.8 % vs naive, −22.3 %&lt;br&gt;
vs TurboQuant at the &lt;code&gt;rel ≈ 0.05&lt;/code&gt; operating point), and the win widens to&lt;br&gt;
−21 % at looser budgets.&lt;/p&gt;

&lt;p&gt;Notice TurboQuant lands &lt;em&gt;between&lt;/em&gt; naive and qdf: the rotation alone helps (it's&lt;br&gt;
why TurboQuant beats naive at high recall), but without the lattice and the&lt;br&gt;
entropy stage it can't reach the qdf curve. That gap is the entropy + granular&lt;br&gt;
gain, made visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about Product Quantization?&lt;/strong&gt; PQ is on the same chart's data&lt;br&gt;
(&lt;code&gt;rd.csv&lt;/code&gt;) and it's a fair question. The honest answer: on this corpus at&lt;br&gt;
comparable &lt;em&gt;quality&lt;/em&gt; it doesn't compete. PQ hits tiny sizes (2–16 B/vec) but&lt;br&gt;
recall@10 collapses to &lt;strong&gt;0.02–0.11&lt;/strong&gt; at those rates — it needs a trained&lt;br&gt;
codebook and many more subspaces to approach 0.9 recall, which is a different&lt;br&gt;
operating regime (and a separate training step). For a drop-in, training-free,&lt;br&gt;
self-describing serializer codec, the scalar/lattice family is the right&lt;br&gt;
comparison, and qdf wins it.&lt;/p&gt;
&lt;h3&gt;
  
  
  The honest trade
&lt;/h3&gt;

&lt;p&gt;Smaller wire is not free. &lt;code&gt;qdf&lt;/code&gt; does strictly more work per vector — a rotation&lt;br&gt;
and an entropy-decode on the read path, plus a verify-loop on encode — than a&lt;br&gt;
bare scalar quantizer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;enc MB/s&lt;/th&gt;
&lt;th&gt;dec MB/s&lt;/th&gt;
&lt;th&gt;enc allocs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;qdf-lossy&lt;/td&gt;
&lt;td&gt;174&lt;/td&gt;
&lt;td&gt;526&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;naive scalar&lt;/td&gt;
&lt;td&gt;993&lt;/td&gt;
&lt;td&gt;4054&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TurboQuant rotated-scalar&lt;/td&gt;
&lt;td&gt;543&lt;/td&gt;
&lt;td&gt;949&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(warm, buffer-reusing; from &lt;code&gt;docs/LOSSY-VECTOR.md&lt;/code&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So if your bottleneck is raw quantization throughput, a naive scalar codec is&lt;br&gt;
faster. &lt;code&gt;qdf&lt;/code&gt;'s codec is built for the &lt;strong&gt;write-once, read-many&lt;/strong&gt; embedding store&lt;br&gt;
where storage and bandwidth dominate the bill and a few hundred MB/s of encode&lt;br&gt;
is irrelevant next to a 20 % smaller index replicated across a fleet. Pick the&lt;br&gt;
tool for the bottleneck you actually have.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this instead of the usual stacks
&lt;/h2&gt;

&lt;p&gt;The recall-vs-size chart settles &lt;em&gt;how small&lt;/em&gt; qdf goes. But "use qdf" is an&lt;br&gt;
architecture decision, not just a codec choice, so here's the honest comparison&lt;br&gt;
against the four things you'd reach for otherwise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfl1p34pafn31eg5us5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftfl1p34pafn31eg5us5k.png" alt="Why qdf instead of the usual stacks" width="799" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A dedicated vector DB (FAISS / pgvector) with Product Quantization.&lt;/strong&gt; This is
the heavyweight answer, and it's the right one once you need a &lt;em&gt;served, indexed,
updatable&lt;/em&gt; ANN system at scale. But it's two systems — a vector store next to
your metadata store — that you keep in sync, and PQ needs a &lt;strong&gt;trained codebook&lt;/strong&gt;
(a separate fit step, re-fit when the embedding model changes). qdf is the
opposite trade: no training, no second store, no index to rebuild — a single
file you &lt;code&gt;Marshal&lt;/code&gt; once and &lt;code&gt;Unmarshal&lt;/code&gt; anywhere. Use the vector DB when you've
outgrown a flat scan; use qdf for the store &lt;em&gt;underneath&lt;/em&gt; it, or for the very
common case where a brute-force cosine scan over a few hundred thousand vectors
is already fast enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protobuf / msgpack with raw &lt;code&gt;float32&lt;/code&gt;.&lt;/strong&gt; This is what most pipelines actually
ship today, and it's exact — but it stores the full 1,024 bytes per 256-dim
vector and copies every field on decode. You get correctness and a familiar
format; you pay 6–7× the bytes of qdf-lossy and a per-field allocation on every
read. If your vectors genuinely must be bit-exact, this is correct (and so is
qdf with the flag &lt;em&gt;off&lt;/em&gt;). If they're search vectors, you're paying for exactness
nobody consumes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roll-your-own scalar quantization (int8 + glue code).&lt;/strong&gt; The DIY path: quantize
to int8, stuff it into msgpack, write a decoder. It works and it's small-ish
(~176 B at 5-bit), but now &lt;em&gt;you&lt;/em&gt; own a wire format, a dequantizer, and the
edge cases (NaN/Inf, varying norms, the "is this column even worth quantizing"
decision). qdf gives you the rotation + lattice + entropy stack, the
&lt;strong&gt;never-worse&lt;/strong&gt; guarantee, and NaN/Inf survival for free — and it's
self-describing, so the reader needs no out-of-band schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The one-line version: &lt;strong&gt;qdf is the training-free, single-blob, self-describing&lt;br&gt;
option.&lt;/strong&gt; It won't beat a tuned PQ index on raw bytes, and it won't beat raw&lt;br&gt;
&lt;code&gt;float32&lt;/code&gt; on encode speed — but it's the only one of the four where the metadata&lt;br&gt;
and the vector live in one &lt;code&gt;Marshal&lt;/code&gt;/&lt;code&gt;Unmarshal&lt;/code&gt; you already know, with a&lt;br&gt;
correctness floor (never-worse, exact-by-default) baked in.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where it's useful
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Use it?&lt;/th&gt;
&lt;th&gt;Budget knob&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embedding store / RAG index (ANN search)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; — headline use case&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MinCosine(0.999)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandwidth-bound embedding transfer&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MinCosine&lt;/code&gt; or &lt;code&gt;MaxRelError(0.01)&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model weight / activation tensors&lt;/td&gt;
&lt;td&gt;Yes, with care&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MaxRelError&lt;/code&gt; / &lt;code&gt;TargetSNR&lt;/code&gt;, validate downstream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exact scientific / financial floats&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;No&lt;/strong&gt; — leave the flag off&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short vectors (&amp;lt; 32) or scalar float fields&lt;/td&gt;
&lt;td&gt;n/a — won't fire&lt;/td&gt;
&lt;td&gt;stays lossless automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The budget API speaks in the metric you actually reason about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoderWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptLossyVec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetVectorBudget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinCosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.999&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// keep cosine similarity &amp;gt;= 0.999&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;EmbedRow&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// no flag needed; the 0xFD tag self-describes&lt;/span&gt;
&lt;span class="c"&gt;// out[i].Emb approximates rows[i].Emb with cosine &amp;gt;= 0.999&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MinCosine&lt;/code&gt; bounds the dot-product metric ANN relies on; &lt;code&gt;MaxRelError(eps)&lt;/code&gt;&lt;br&gt;
bounds per-vector L2 error directly; &lt;code&gt;TargetSNR(db)&lt;/code&gt; suits signal-style data.&lt;br&gt;
Looser budget ⇒ smaller and faster — pick the loosest your downstream task&lt;br&gt;
tolerates and verify recall on a held-out query set.&lt;/p&gt;
&lt;h2&gt;
  
  
  Production best practices
&lt;/h2&gt;

&lt;p&gt;The codec is only half the win. The other half is decoding it without throwing&lt;br&gt;
the size advantage away on allocations — embedding decode is &lt;strong&gt;allocation-bound,&lt;br&gt;
not CPU-bound&lt;/strong&gt;, so where the bytes land matters as much as how few there are.&lt;br&gt;
This section is the part the API docs assume you'll figure out.&lt;/p&gt;
&lt;h3&gt;
  
  
  Write path: reuse one encoder, batch the column
&lt;/h3&gt;

&lt;p&gt;Two habits make the encode side cheap:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reuse a &lt;code&gt;*qdf.Encoder&lt;/code&gt; across calls.&lt;/strong&gt; &lt;code&gt;qdf.Marshal&lt;/code&gt; allocates a fresh
encoder state per call; a long-lived encoder reuses its rotation, coordinate,
widen, and rANS scratch. On a 256×768 batch that's the &lt;strong&gt;13,855 → 1,308
allocs/op&lt;/strong&gt; (21.2 MB → 2.0 MB/op) difference — ~10× — with byte-identical
output.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;   &lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoderWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptLossyVec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetVectorBudget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinCosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.999&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;batches&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// scratch reused across iterations&lt;/span&gt;
       &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Marshal the whole &lt;code&gt;[]struct&lt;/code&gt;, not vector-by-vector.&lt;/strong&gt; When the element has a
&lt;code&gt;[]float32&lt;/code&gt;/&lt;code&gt;[]float64&lt;/code&gt; field, qdf gathers &lt;em&gt;every row's&lt;/em&gt; vector into &lt;strong&gt;one&lt;/strong&gt;
count-&lt;code&gt;N&lt;/code&gt; column block (wire tag &lt;code&gt;0xFE&lt;/code&gt;) instead of one block per row. That
amortizes the block header &lt;em&gt;and&lt;/em&gt; the rANS frequency framing across the batch —
the per-row form costs ~290 B/vec vs ~176 B/vec batched on a 256-dim corpus.
So the headline numbers are the ones you actually get in production, &lt;em&gt;because&lt;/em&gt;
you marshal the batch. (Needs ≥ 16 rows with the same vector length.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you re-encode the same string-column shape repeatedly (same URL space, same log&lt;br&gt;
format alongside the vectors), train an &lt;code&gt;FSSTDict&lt;/code&gt; once and reuse it — it skips&lt;br&gt;
the per-batch symbol-table training, ~5× faster encode.&lt;/p&gt;
&lt;h3&gt;
  
  
  Read path: three ways to decode, pick by buffer ownership
&lt;/h3&gt;

&lt;p&gt;This is the lever most people miss. The default &lt;code&gt;Unmarshal&lt;/code&gt; copies each string&lt;br&gt;
field into its own heap allocation — always correct, but a record with seven&lt;br&gt;
string fields pays seven allocations and the GC then scans seven objects. There&lt;br&gt;
are two cheaper paths, and which one is safe depends entirely on &lt;strong&gt;who owns the&lt;br&gt;
wire buffer and how long it lives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F761k7kntawmfk1mfmy3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F761k7kntawmfk1mfmy3l.png" alt="Three decode paths" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;WithArena&lt;/code&gt; — copy once, packed.&lt;/strong&gt; Bump-appends every decoded string into one
contiguous block per epoch instead of N separate allocations. The strings are
byte-identical; only &lt;em&gt;where they live&lt;/em&gt; changes. Across a batch the block
amortizes to ~0 allocations, the strings sit cache-adjacent, and the GC walks
one object instead of N. Measured &lt;strong&gt;−26…−35 %&lt;/strong&gt; decode time on string-heavy
corpora (4,856 → 605 allocs/op on an AD-style export). It is &lt;strong&gt;safe with a
recycled wire buffer&lt;/strong&gt; — because it copies the strings &lt;em&gt;out&lt;/em&gt;, you can hand the
buffer straight back to a pool. This is the right default for a server handler
or a streaming consumer.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewArena&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Doc&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithArena&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="n"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// only after every value from the last decode is dead&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Reset&lt;/code&gt; is a &lt;em&gt;manual&lt;/em&gt; use-after-free contract — call it only once everything&lt;br&gt;
  decoded since the last reset is dead. If you can't reason about that, drop the&lt;br&gt;
  arena and &lt;code&gt;NewArena()&lt;/code&gt; again; never-&lt;code&gt;Reset&lt;/code&gt; is always safe (the block is plain&lt;br&gt;
  GC memory).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;WithNoCopy&lt;/code&gt; — zero copy.&lt;/strong&gt; Decoded strings/&lt;code&gt;[]byte&lt;/code&gt; &lt;strong&gt;alias the input buffer&lt;/strong&gt;
directly: zero copies, zero allocations, ~1.7× faster. The catch is the
lifetime — the values are valid only while the input stays alive and unmodified.
Use it on &lt;strong&gt;owned, long-lived, read-only&lt;/strong&gt; input. Never on a pooled/recycled
buffer (a server request body): the aliased values become silent garbage when
the buffer is reused — a use-after-free the race detector won't catch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The decision is mechanical: &lt;strong&gt;recycled buffer → &lt;code&gt;WithArena&lt;/code&gt;; owned long-lived&lt;br&gt;
buffer → &lt;code&gt;WithNoCopy&lt;/code&gt;; unsure → default copy.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  The flagship pattern: an mmap'd, zero-copy embedding store
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;WithNoCopy&lt;/code&gt;'s "owned, long-lived, read-only" requirement is &lt;em&gt;exactly&lt;/em&gt; what an&lt;br&gt;
&lt;code&gt;mmap&lt;/code&gt;'d file is — which makes it the natural backing for a write-once / read-many&lt;br&gt;
embedding index. You marshal the whole corpus into one self-describing &lt;code&gt;.qdf&lt;/code&gt;&lt;br&gt;
file once; readers &lt;code&gt;mmap&lt;/code&gt; it and &lt;code&gt;Unmarshal&lt;/code&gt; with &lt;code&gt;WithNoCopy&lt;/code&gt;, serving vectors&lt;br&gt;
straight out of the page cache with &lt;strong&gt;no per-read allocation and no copy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwychg3mbsfawmvoyd6l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwychg3mbsfawmvoyd6l1.png" alt="Write-once / read-many zero-copy store" width="799" height="298"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Writer — once, offline.&lt;/span&gt;
&lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoderWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptLossyVec&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetVectorBudget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinCosine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.999&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;corpus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c"&gt;// []Doc{ID, Title, Emb []float32}&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"index.qdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="n"&gt;o644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Reader — many times, hot.&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"index.qdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fd&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PROT_READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MAP_SHARED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Munmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Doc&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithNoCopy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c"&gt;// strings alias the mmap; vectors materialize&lt;/span&gt;
&lt;span class="c"&gt;// docs[i].Emb is the approximated vector; scan / ANN over it directly.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The vector field itself is reconstructed (the lossy decode allocates the output&lt;br&gt;
slice — there's nothing to alias), but the &lt;code&gt;ID&lt;/code&gt;/&lt;code&gt;Title&lt;/code&gt; metadata and any other&lt;br&gt;
string columns cost zero. The whole index is one file, one mmap, one &lt;code&gt;Unmarshal&lt;/code&gt;&lt;br&gt;
— no second store, no schema sidecar. Keep the mmap mapped for as long as you&lt;br&gt;
read &lt;code&gt;docs&lt;/code&gt;; &lt;code&gt;Munmap&lt;/code&gt; only after they're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing and validating the budget
&lt;/h3&gt;

&lt;p&gt;The budget knob is the one parameter that actually matters, so don't guess it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You reason about…&lt;/th&gt;
&lt;th&gt;Knob&lt;/th&gt;
&lt;th&gt;Note&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ANN recall (cosine / dot-product)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MinCosine(0.999)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bounds the metric the index uses — start here for RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;reconstruction error directly&lt;/td&gt;
&lt;td&gt;&lt;code&gt;MaxRelError(0.01)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;per-vector L2; tighter &lt;code&gt;eps&lt;/code&gt; ⇒ more bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;signal-style data (audio, sensor)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TargetSNR(db)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;dB framing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A looser budget is smaller &lt;em&gt;and&lt;/em&gt; faster. The discipline: &lt;strong&gt;pick the loosest&lt;br&gt;
budget your downstream task tolerates, then verify recall@k on a held-out query&lt;br&gt;
set&lt;/strong&gt; — encode the corpus, decode it, and confirm the top-k neighbours of your&lt;br&gt;
eval queries are unchanged (the &lt;code&gt;Example_aiEmbeddingStore&lt;/code&gt; test does exactly this&lt;br&gt;
top-1 check). Tighten the budget only if recall actually drops. Because the codec&lt;br&gt;
is &lt;strong&gt;never-worse&lt;/strong&gt;, the failure mode of an over-tight budget is "no smaller than&lt;br&gt;
lossless," not "corrupt" — you lose the size win, not correctness.&lt;/p&gt;

&lt;h3&gt;
  
  
  A short checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;OptLossyVec&lt;/code&gt; &lt;strong&gt;only&lt;/strong&gt; on search/embedding vectors — never exact floats.&lt;/li&gt;
&lt;li&gt;[ ] Marshal the &lt;code&gt;[]struct&lt;/code&gt; batch (≥ 16 rows) so the vector column batches.&lt;/li&gt;
&lt;li&gt;[ ] Reuse a &lt;code&gt;*qdf.Encoder&lt;/code&gt; if you encode in a loop.&lt;/li&gt;
&lt;li&gt;[ ] Decode: &lt;code&gt;WithArena&lt;/code&gt; for pooled buffers, &lt;code&gt;WithNoCopy&lt;/code&gt; for mmap, copy if unsure.&lt;/li&gt;
&lt;li&gt;[ ] Verify recall@k on held-out queries; loosen the budget to the floor your task allows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A note on trust
&lt;/h2&gt;

&lt;p&gt;I deliberately sourced every figure from committed artifacts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pipeline &amp;amp; wire format → &lt;a href="https://github.com/alex60217101990/qdf/blob/main/docs/LOSSY-VECTOR.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/LOSSY-VECTOR.md&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;decode paths (arena / zero-copy) → &lt;a href="https://github.com/alex60217101990/qdf/blob/main/docs/ARENA.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/ARENA.md&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;rate-distortion / recall rows → &lt;code&gt;cmd/qdf-vecbench/rd.csv&lt;/code&gt;, generated by the &lt;a href="https://github.com/alex60217101990/qdf/tree/main/cmd/qdf-vecbench" rel="noopener noreferrer"&gt;&lt;code&gt;qdf-vecbench&lt;/code&gt; tool&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;runnable end-to-end → &lt;code&gt;Example_aiEmbeddingStore&lt;/code&gt; in &lt;a href="https://github.com/alex60217101990/qdf/blob/main/example_lossyvec_test.go" rel="noopener noreferrer"&gt;&lt;code&gt;example_lossyvec_test.go&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;reproduce → &lt;code&gt;go run github.com/alex60217101990/qdf/cmd/qdf-vecbench@latest -synthetic -n 2000 -dim 256&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The benchmark is synthetic Gaussian data, which is the &lt;em&gt;friendly&lt;/em&gt; case for every&lt;br&gt;
method here; the relative ordering (qdf &amp;lt; TurboQuant &amp;lt; naive at equal recall) is&lt;br&gt;
the structural result and it holds because it comes from the algorithm, not the&lt;br&gt;
corpus. On real embeddings the absolute bytes shift, but the entropy + lattice&lt;br&gt;
gain that puts qdf's curve to the left does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Embeddings dominate vector-DB storage and they don't need bit-exactness —
lossy quantization is the right tool, and it can live inside your serializer
instead of a second system.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;qdf&lt;/code&gt;'s codec pulls &lt;strong&gt;both&lt;/strong&gt; practical quantization levers (E8 granular gain +
rANS entropy gain) on top of the TurboQuant-style rotation — which is why it's
Pareto-better than rotated-scalar at equal recall, and why the &lt;em&gt;next&lt;/em&gt; idea
(Leech) measured worse.&lt;/li&gt;
&lt;li&gt;It's an honest CPU-for-size trade: lower throughput, smaller wire, near-zero
steady-state allocations. Right for write-once / read-many stores.&lt;/li&gt;
&lt;li&gt;The size win is only realized if you decode right: &lt;code&gt;WithArena&lt;/code&gt; for pooled
buffers, &lt;code&gt;WithNoCopy&lt;/code&gt; over an &lt;code&gt;mmap&lt;/code&gt;'d file for a zero-copy read-many store.
Decode is allocation-bound — where the bytes land matters as much as how few.&lt;/li&gt;
&lt;li&gt;Versus the alternatives it's the training-free, single-blob, self-describing
option: it won't beat a tuned PQ index on raw bytes or raw &lt;code&gt;float32&lt;/code&gt; on encode
speed, but it's the only one with metadata + vector in one &lt;code&gt;Marshal&lt;/code&gt;/&lt;code&gt;Unmarshal&lt;/code&gt;
and a never-worse / exact-by-default correctness floor.&lt;/li&gt;
&lt;li&gt;One flag, one blob, no schema, never-worse. &lt;code&gt;qdf.OptLossyVec&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>go</category>
      <category>performance</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>qdf: a Go serializer that decodes less, packs harder, and lets you query the bytes</title>
      <dc:creator>Aleksandr Yershov</dc:creator>
      <pubDate>Wed, 03 Jun 2026 12:02:53 +0000</pubDate>
      <link>https://dev.to/alex_602/qdf-a-go-serializer-that-decodes-less-packs-harder-and-lets-you-query-the-bytes-2a39</link>
      <guid>https://dev.to/alex_602/qdf-a-go-serializer-that-decodes-less-packs-harder-and-lets-you-query-the-bytes-2a39</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR for the impatient.&lt;/strong&gt; &lt;code&gt;qdf&lt;/code&gt; is a schemaless Go serializer (struct tags, no &lt;code&gt;.proto&lt;/code&gt;). On real batches it's up to &lt;strong&gt;68% smaller than protobuf&lt;/strong&gt;, decodes &lt;strong&gt;4–9× faster than &lt;code&gt;encoding/json&lt;/code&gt;&lt;/strong&gt;, ships hand-written &lt;strong&gt;AVX2/NEON&lt;/strong&gt; bit-packing at ~50 GB/s, and does one thing no other mainstream Go serializer does: it can run &lt;code&gt;SELECT … WHERE …&lt;/code&gt; over a &lt;code&gt;[]byte&lt;/code&gt; and &lt;strong&gt;decode only the columns and rows you asked for&lt;/strong&gt;. Pure Go, zero dependencies. &lt;a href="https://github.com/alex60217101990/qdf" rel="noopener noreferrer"&gt;&lt;code&gt;github.com/alex60217101990/qdf&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the engineering deep-dive, not the marketing page. We're going to look at actual hexdumps, the codec picker's never-larger guarantee, the twin-bitmask three-valued predicate engine, and a profiler-driven argument about why your decode path is slow for a reason you probably haven't measured. If you write Go services that serialize the same five shapes forever — logs, events, metrics, RTB bids, OTLP spans — this is for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem nobody's format actually solves
&lt;/h2&gt;

&lt;p&gt;Every binary serializer makes you pick two of three:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;schemaless&lt;/th&gt;
&lt;th&gt;small wire&lt;/th&gt;
&lt;th&gt;fast / cheap&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;encoding/json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (allocates a mountain)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;msgpack&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ (per-record)&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;protobuf / flatbuffers&lt;/td&gt;
&lt;td&gt;❌ (&lt;code&gt;.proto&lt;/code&gt; + codegen)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;JSON is universal and schemaless and burns CPU and GC like it's free. msgpack is smaller but you still decode the &lt;em&gt;whole&lt;/em&gt; blob to read one field. protobuf and flatbuffers are fast and compact — right up until you're maintaining &lt;code&gt;.proto&lt;/code&gt; files and a codegen step for what used to be a plain struct.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;qdf&lt;/code&gt; is an attempt to refuse the tradeoff: &lt;strong&gt;self-describing wire&lt;/strong&gt; (decode straight into a struct, no schema), &lt;strong&gt;protobuf-class sizes on batches&lt;/strong&gt;, genuinely extreme decode speed, &lt;strong&gt;and&lt;/strong&gt; a columnar mode you can query. Let's see how, byte by byte.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TS&lt;/span&gt;    &lt;span class="kt"&gt;int64&lt;/span&gt;  &lt;span class="s"&gt;`qdf:"ts"`&lt;/span&gt;
    &lt;span class="n"&gt;Level&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`qdf:"level"`&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt;  &lt;span class="kt"&gt;int32&lt;/span&gt;  &lt;span class="s"&gt;`qdf:"code"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// []Event -&amp;gt; []byte&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Struct tags name fields, exactly like &lt;code&gt;json:&lt;/code&gt;. No registry, no generated types to keep in sync. &lt;strong&gt;The decoder figures out mode, codecs and compression from the wire itself&lt;/strong&gt; — you never pass options to &lt;code&gt;Unmarshal&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The wire format in one look
&lt;/h2&gt;

&lt;p&gt;A qdf buffer is a &lt;strong&gt;5-byte header + a tagged body&lt;/strong&gt;. That's the whole envelope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;51 44 46   01    XX        [ tagged body … ]
'Q' 'D''F' ver  flags       bytes 5 … N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumzq102nhrqcv9068jis.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumzq102nhrqcv9068jis.png" alt="qdf wire format: 5-byte header + tagged body" width="799" height="108"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flags byte is a tiny bitmap telling the decoder which &lt;em&gt;dialect&lt;/em&gt; the body speaks, so it can fast-path or reject before parsing a single value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FlagDense&lt;/code&gt; (&lt;code&gt;0x01&lt;/code&gt;) — body uses the Dense intern dialect (back-reference tags).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FlagQPack&lt;/code&gt; (&lt;code&gt;0x02&lt;/code&gt;) — body may carry the QPack numeric/bool codec tags.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FlagRANS&lt;/code&gt; (&lt;code&gt;0x04&lt;/code&gt;) — body is rANS-compressed; decompress first.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FlagColIndex&lt;/code&gt; (&lt;code&gt;0x08&lt;/code&gt;) — a columnar payload carries a per-column length index (this is what makes selective decode an O(1) skip).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;base tag space is msgpack-shaped&lt;/strong&gt; — fixint, fixstr, fixarr, typed scalars, str/bin/arr/map in 8/16/32 widths, negfixint. On top of that sit the Dense back-reference tags and the QPack codec tags. That base layer is why a Fast-mode qdf buffer is about as small as msgpack and just as quick; the extra tags are where qdf pulls ahead on batches.&lt;/p&gt;

&lt;h3&gt;
  
  
  An actual buffer, byte for byte
&lt;/h3&gt;

&lt;p&gt;Encode one &lt;code&gt;&amp;amp;Event{TS:7, Level:"ERR", Code:500}&lt;/code&gt; with &lt;code&gt;OptSpeed&lt;/code&gt; → &lt;strong&gt;29 bytes&lt;/strong&gt;, every one accounted for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;51 44 46 01 00              QDF, ver 1, flags 0x00 (Fast)
d5 03                       map, 3 fields
82 74 73 07                 "ts"  -&amp;gt; fixint 7
85 6c 65 76 65 6c 83 45 52 52   "level" -&amp;gt; fixstr "ERR"
84 63 6f 64 65 c4 f4 01     "code" -&amp;gt; uint16 0x01F4 (500)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details that tell you how the encoder thinks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It picked the narrowest tag that holds the value.&lt;/strong&gt; &lt;code&gt;500&lt;/code&gt; went out as a 2-byte &lt;code&gt;uint16&lt;/code&gt;, not a 4-byte &lt;code&gt;int32&lt;/code&gt;. The picker always reaches for the smallest tag, per value.&lt;/li&gt;
&lt;li&gt;There's &lt;strong&gt;no schema anywhere&lt;/strong&gt;. The keys &lt;code&gt;ts&lt;/code&gt;/&lt;code&gt;level&lt;/code&gt;/&lt;code&gt;code&lt;/code&gt; are in the bytes. That's the cost of being schemaless on a single message — and exactly what Dense mode erases on a batch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Flip to &lt;code&gt;OptBalanced&lt;/code&gt; on a slice of these and the repeated keys (&lt;code&gt;ts&lt;/code&gt;/&lt;code&gt;level&lt;/code&gt;/&lt;code&gt;code&lt;/code&gt;) and repeated values (&lt;code&gt;"ERR"&lt;/code&gt;) collapse to 1-byte back-references after first sight. Which brings us to the encoder.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Encode: it measures, then packs
&lt;/h2&gt;

&lt;p&gt;qdf doesn't pick one scheme and pray. The encode pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;value → typeDesc cache → columnar transpose → per-column codec picker
      → Dense intern → rANS (opt-in) → []byte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fte15b5lmq5qaeaobvsd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fte15b5lmq5qaeaobvsd6.png" alt="qdf encode pipeline stages" width="800" height="1948"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reflection runs once per type, ever.&lt;/strong&gt; The first call for a type builds a &lt;em&gt;type descriptor&lt;/em&gt; — a flat array of encode/decode closures over &lt;code&gt;unsafe&lt;/code&gt; field offsets — and caches it in a &lt;code&gt;sync.Map&lt;/code&gt;. Every later call touches only those closures: no &lt;code&gt;reflect.Value&lt;/code&gt; churn, no per-field type switch on the hot path.&lt;/p&gt;

&lt;h3&gt;
  
  
  The codec picker and the never-larger rule
&lt;/h3&gt;

&lt;p&gt;For every numeric/bool slice the encoder runs a &lt;strong&gt;cheap bounded probe&lt;/strong&gt; and emits the smallest of a family. The comparison &lt;strong&gt;includes the raw form&lt;/strong&gt;, so if nothing wins it falls back — &lt;em&gt;turning compression on can never inflate a slice.&lt;/em&gt; This "never-larger by construction" property is the whole reason you can flip &lt;code&gt;OptBalanced&lt;/code&gt; on blindly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;codec&lt;/th&gt;
&lt;th&gt;idea&lt;/th&gt;
&lt;th&gt;wins on&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FOR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;store &lt;code&gt;value − min&lt;/code&gt;, bit-pack to width of &lt;code&gt;max−min&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;bounded ranges (HTTP codes 200–504 → ~10 bits, not 32)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delta+FOR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FOR over consecutive differences&lt;/td&gt;
&lt;td&gt;monotonic-ish columns: timestamps, IDs, offsets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RLE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(value, run-length)&lt;/code&gt; pairs&lt;/td&gt;
&lt;td&gt;long runs: status, enum, sparse flags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dictionary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;distinct table + bit-packed indices (&lt;code&gt;ceil(log2 d)&lt;/code&gt; bits/row)&lt;/td&gt;
&lt;td&gt;low cardinality, incl. string columns (level, region)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Patched FOR&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FOR + an exception list for outliers&lt;/td&gt;
&lt;td&gt;mostly-narrow columns with a few spikes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzynszovh6hu1y2edwlr8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzynszovh6hu1y2edwlr8.png" alt="QPack codec family and the never-larger picker" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Delta+FOR, with the actual bytes
&lt;/h4&gt;

&lt;p&gt;Take &lt;code&gt;[]int64{1000, 1001, …, 1009}&lt;/code&gt; — ten 8-byte integers, &lt;strong&gt;80 bytes raw&lt;/strong&gt;. &lt;code&gt;Marshal(ints, OptQPack)&lt;/code&gt; gives &lt;strong&gt;12 bytes total&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00000000  51 44 46 01 02 e6 07 00  d0 0f 02 0a   |QDF.........|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Header is 5 bytes (&lt;code&gt;flags 0x02&lt;/code&gt; = QPack), so the body is &lt;strong&gt;7 bytes for ten int64s&lt;/strong&gt;. Codec &lt;code&gt;0xE6&lt;/code&gt; = Delta+FOR: it stored the first value, the minimum delta, and the residual deltas bit-packed. Since every delta is exactly &lt;code&gt;1&lt;/code&gt;, the residuals collapse to almost nothing.&lt;/p&gt;

&lt;p&gt;That's the mechanism behind the headline &lt;strong&gt;512× compression on monotonic timestamp vectors&lt;/strong&gt; — a clock column is the perfect case: large absolute values, tiny constant deltas.&lt;/p&gt;

&lt;h3&gt;
  
  
  SIMD bit-packing — same wire, faster code
&lt;/h3&gt;

&lt;p&gt;The bit-pack/unpack kernels are &lt;strong&gt;hand-written assembly: AVX2 on amd64, NEON on arm64&lt;/strong&gt;, and they emit &lt;strong&gt;byte-identical output to the scalar path&lt;/strong&gt;. Tests assert &lt;code&gt;scalar ≡ SIMD&lt;/code&gt; bit-for-bit. So &lt;code&gt;-tags qdf_simd&lt;/code&gt; is purely faster, never a different wire — runtime CPUID gate, scalar fallback on anything without AVX2.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;22–53× over scalar&lt;/strong&gt; at byte-aligned widths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~50 GB/s&lt;/strong&gt; unpack (memory-bound there, not compute-bound)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run &lt;code&gt;OptBalanced&lt;/code&gt;/&lt;code&gt;OptCompression&lt;/code&gt; over numeric data, this build tag is free money:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go build &lt;span class="nt"&gt;-tags&lt;/span&gt; qdf_simd ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Implementation note for the SIMD-curious: the decode kernels lean on &lt;code&gt;VPMOVZX&lt;/code&gt; widen-loads and &lt;code&gt;VPBROADCASTQ&lt;/code&gt;+&lt;code&gt;VPSRLVQ&lt;/code&gt; variable-per-lane shifts (a per-offset shift table picks the bit offset for each lane); encode uses &lt;code&gt;VPSHUFB&lt;/code&gt; byte-gather and &lt;code&gt;VPSLLVQ&lt;/code&gt;+lane-OR. On arm64, several of those have no direct Plan9 mnemonic and get hand-encoded via &lt;code&gt;WORD&lt;/code&gt;. It's the kind of code where "byte-identical to scalar" is a property you &lt;em&gt;test&lt;/em&gt;, not hope for.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3x0n8y5lf2kyb57s4gc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3x0n8y5lf2kyb57s4gc.png" alt="qdf_simd build tag: AVX2 (amd64) and NEON (arm64) kernels per operation, with a pure-Go scalar fallback" width="800" height="855"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The four-layer Dense dialect (strings &amp;amp; structure)
&lt;/h3&gt;

&lt;p&gt;Repeated strings and field names are where batch formats bleed. Dense mode stacks four mechanisms so the &lt;em&gt;second&lt;/em&gt; occurrence of a value is nearly free. Take &lt;code&gt;[]string{"eu-west-1","eu-west-1","eu-west-1"}&lt;/code&gt; under &lt;code&gt;OptBalanced&lt;/code&gt; — &lt;strong&gt;19 bytes&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;00000000  51 44 46 01 03 a3 e0 09  65 75 2d 77 65 73 74 2d  |QDF.....eu-west-|
00000010  31 e8 e8                                          |1..|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;bytes&lt;/th&gt;
&lt;th&gt;meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;51 44 46 01 03&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;header, flags &lt;code&gt;0x03&lt;/code&gt; (Dense | QPack)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;fixarr, 3 elements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;e0 09 65…31&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1st value: intern declaration — tag + len 9 + &lt;code&gt;"eu-west-1"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;e8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2nd value: one-byte back-reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;e8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3rd value: one byte again&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbylfelh6i5o27qpbawax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbylfelh6i5o27qpbawax.png" alt="Dense interning: first sight stored, repeats become 1-byte back-references" width="800" height="1545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First &lt;code&gt;"eu-west-1"&lt;/code&gt; costs 11 bytes; each repeat costs &lt;strong&gt;1&lt;/strong&gt;. That's the whole game on telemetry, where &lt;code&gt;region&lt;/code&gt;/&lt;code&gt;service&lt;/code&gt;/&lt;code&gt;level&lt;/code&gt; repeat across thousands of rows. The four layers producing those one-byte refs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Intern table&lt;/strong&gt; — first sight stored, assigned an id; later sights become a varint reference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move-to-front&lt;/strong&gt; — the hot set resolves in 1–2 bytes via a small MRU ring (recent values get the shortest codes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markov-0 "same as last"&lt;/strong&gt; — a value equal to the previous one is a single repeat tag (the &lt;code&gt;e8&lt;/code&gt; above).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markov-1 pair predictor&lt;/strong&gt; — if &lt;code&gt;"GET"&lt;/code&gt; is usually followed by &lt;code&gt;"/health"&lt;/code&gt;, the predicted successor collapses too.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jr2psjulj4j0fp7j4l2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jr2psjulj4j0fp7j4l2.png" alt="The four Dense reference predictors, tried in order: Markov-0 repeat, Markov-1 pair, MTF rank, raw state-ref" width="800" height="2467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Floats get &lt;strong&gt;Gorilla&lt;/strong&gt; (lossless XOR coding over &lt;code&gt;math.Float64bits&lt;/code&gt; — bit-exact for &lt;code&gt;NaN&lt;/code&gt;/&lt;code&gt;±Inf&lt;/code&gt;/&lt;code&gt;−0.0&lt;/code&gt;, never &lt;code&gt;==&lt;/code&gt;) and &lt;strong&gt;ALP&lt;/strong&gt; (decimal-mantissa for quantized metrics/prices, with an exception list for anything that doesn't round-trip exactly). The opt-in order-0 &lt;strong&gt;rANS&lt;/strong&gt; pass is the final never-larger squeeze for cold storage.&lt;/p&gt;

&lt;h3&gt;
  
  
  The structural win (and the gotcha)
&lt;/h3&gt;

&lt;p&gt;Here's why qdf lands smaller than protobuf on real batches: &lt;strong&gt;it dedups and compresses &lt;em&gt;across&lt;/em&gt; records.&lt;/strong&gt; protobuf, msgpack, json and flatbuffers encode each record independently, so a repeated string or a smooth float series re-pays its cost every single row. qdf pays once per batch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha #1:&lt;/strong&gt; that cross-record win &lt;em&gt;needs a batch&lt;/em&gt;. On a single small message there's nothing to dedup, so &lt;code&gt;OptBalanced ≈ OptSpeed ≈ msgpack&lt;/code&gt; in size — use &lt;code&gt;OptSpeed&lt;/code&gt; there and skip the Dense bookkeeping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gotcha #2:&lt;/strong&gt; the Dense wire embeds intern/shape ids that depend on &lt;strong&gt;emission order&lt;/strong&gt;, so two semantically-equal payloads can differ byte-for-byte. If you hash or sign the bytes, encode with &lt;code&gt;OptSpeed&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The headline: read less than the whole message
&lt;/h2&gt;

&lt;p&gt;Hand qdf a &lt;code&gt;[]struct&lt;/code&gt; and it &lt;strong&gt;transposes&lt;/strong&gt; rows into columns — think Parquet, but automatic and still self-describing. Each column then gets the codec that fits it: timestamps go Delta+FOR, an enum-ish &lt;code&gt;level&lt;/code&gt; goes dictionary, a run-heavy &lt;code&gt;code&lt;/code&gt; goes RLE.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rows ([]Event)              columns (each its own codec)
┌────┬───────┬──────┐       ┌──────────┬────────┬──────┐
│ ts │ level │ code │  →    │ ts ts ts │ level… │ code…│
│ …  │  …    │  …   │       │ Delta+FOR│  dict  │ RLE  │
└────┴───────┴──────┘       └──────────┴────────┴──────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i2pqt2lmefqfuxmum9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i2pqt2lmefqfuxmum9e.png" alt="Transpose: []struct rows become per-column codecs plus a length index" width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;OptColumnIndex&lt;/code&gt; the encoder also writes, right after the shape declaration, a &lt;strong&gt;fixed-width index: one &lt;code&gt;uint32&lt;/code&gt; byte-length per column.&lt;/strong&gt; That index is the key — it lets the decoder compute each column's start offset and &lt;strong&gt;jump straight past any column it doesn't need&lt;/strong&gt;, without parsing a byte of it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fas9p58a3l73ojqdocyv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fas9p58a3l73ojqdocyv3.png" alt="tagColStruct body layout: row count, shape decl, optional column-length index, then column bodies" width="800" height="2102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying the bytes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptColumnIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// "SELECT ts, code WHERE level='ERROR' AND code&amp;gt;=500" — over a []byte.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Hot&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TS&lt;/span&gt;   &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="s"&gt;`qdf:"ts"`&lt;/span&gt;
    &lt;span class="n"&gt;Code&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="s"&gt;`qdf:"code"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hot&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Hot&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"ERROR"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the decoder actually does, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the shape + column index.&lt;/strong&gt; Now it knows where every column starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter columns&lt;/strong&gt; — decode &lt;em&gt;only&lt;/em&gt; the columns named in a predicate (&lt;code&gt;level&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt;). Run each predicate across its whole column to produce a per-row bitmask.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine the masks&lt;/strong&gt; (AND here) into the surviving-row set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project&lt;/strong&gt; — for the columns &lt;code&gt;Hot&lt;/code&gt; wants (&lt;code&gt;ts&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt;), materialize values only at the surviving rows. &lt;code&gt;level&lt;/code&gt; was read to filter, then &lt;strong&gt;dropped&lt;/strong&gt; because &lt;code&gt;Hot&lt;/code&gt; doesn't contain it. Every other column is &lt;strong&gt;skipped via the index&lt;/strong&gt; — its bytes are never parsed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ag0d9ljup4ukr9k52c6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ag0d9ljup4ukr9k52c6.png" alt="Selective decode: read shape + index, one forward pass, decode only predicate/projected columns, scatter matched rows" width="800" height="1947"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The predicate engine: twin bitmasks + SQL three-valued logic
&lt;/h3&gt;

&lt;p&gt;It isn't just AND-of-equals. &lt;code&gt;And&lt;/code&gt;, &lt;code&gt;Or&lt;/code&gt;, &lt;code&gt;Not&lt;/code&gt; compose into a real predicate tree — and the tricky part is &lt;strong&gt;nullable columns&lt;/strong&gt;: in SQL, a comparison against &lt;code&gt;NULL&lt;/code&gt; is neither true nor false, it's &lt;code&gt;UNKNOWN&lt;/code&gt;. qdf gets this right with &lt;strong&gt;twin bitmasks per node&lt;/strong&gt;: a &lt;code&gt;T&lt;/code&gt; mask (rows definitely true) and an &lt;code&gt;F&lt;/code&gt; mask (rows definitely false). Anything in neither is &lt;code&gt;UNKNOWN&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Leaf:&lt;/strong&gt; run the predicate per present row → fills &lt;code&gt;T&lt;/code&gt;; &lt;code&gt;F = present &amp;amp;^ T&lt;/code&gt; (present-but-not-true). Absent (&lt;code&gt;nil&lt;/code&gt;) rows land in neither — &lt;code&gt;UNKNOWN&lt;/code&gt;, for free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AND:&lt;/strong&gt; &lt;code&gt;T = T₁ &amp;amp; T₂&lt;/code&gt;, &lt;code&gt;F = F₁ | F₂&lt;/code&gt; (false if any child is false — even if another is unknown).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OR:&lt;/strong&gt; &lt;code&gt;T = T₁ | T₂&lt;/code&gt;, &lt;code&gt;F = F₁ &amp;amp; F₂&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NOT:&lt;/strong&gt; swap &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;F&lt;/code&gt; (unknown stays unknown).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby036vzamombgljl6usa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby036vzamombgljl6usa.png" alt="Twin-bitmask predicate tree evaluating AND/OR/NOT with SQL three-valued logic" width="799" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final result keeps only rows in the &lt;strong&gt;root &lt;code&gt;T&lt;/code&gt; mask&lt;/strong&gt; — TRUE, never FALSE, never UNKNOWN — which is exactly SQL &lt;code&gt;WHERE&lt;/code&gt; semantics.&lt;/p&gt;

&lt;p&gt;A neat optimization: a subtree with &lt;strong&gt;no nullable leaves can't produce UNKNOWN&lt;/strong&gt;, so qdf skips materializing its &lt;code&gt;F&lt;/code&gt; mask entirely and treats "not true" as the complement — one fewer pass over the rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"ERROR"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
            &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"DEBUG"&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The predicate is called &lt;strong&gt;once per row against the native typed value&lt;/strong&gt; — &lt;code&gt;func(int32) bool&lt;/code&gt;, &lt;code&gt;func(string) bool&lt;/code&gt; — with &lt;strong&gt;zero interface boxing&lt;/strong&gt;. Pure projection without a filter is just &lt;code&gt;Select("ts","code")&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;No mainstream Go serializer does this.&lt;/strong&gt; json, msgpack, protobuf, gob — all decode the whole message before you can read one field. For "store a wide batch, read a few columns or filter rows later," qdf is the only one that reads &lt;em&gt;less than everything&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Concretely, on a wide batch at low selectivity (i7-9750H):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~5× faster&lt;/strong&gt; than full decode (projection)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~5× less memory&lt;/strong&gt; than full decode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~2.5× faster&lt;/strong&gt; than decode-everything-then-filter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When it applies: you need &lt;code&gt;OptColumnIndex&lt;/code&gt; at encode time, a &lt;code&gt;[]struct&lt;/code&gt; batch, and flat-ish fields. The bigger and wider the batch and the more selective the query, the larger the win. It's the columnar-warehouse pattern brought to a plain Go &lt;code&gt;[]byte&lt;/code&gt; — no database, no schema. (It is &lt;em&gt;not&lt;/em&gt; for single messages or streaming — that's the row-by-row half of the design.)&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Decode: the fastest work is the work you skip
&lt;/h2&gt;

&lt;p&gt;Here's the claim that should change how you think about serializer performance:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Profile any serializer's decode and the truth is the same: it's allocation-bound, not CPU-bound.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Run &lt;code&gt;go test -memprofile&lt;/code&gt; on a string-heavy decode and look at &lt;code&gt;-alloc_objects&lt;/code&gt;. On qdf's row path it's almost entirely &lt;strong&gt;one call: &lt;code&gt;(*Decoder).ReadString&lt;/code&gt;&lt;/strong&gt; — copying string bodies out of the buffer into owned Go strings. Tag walking, bounds checks, type dispatch — rounding error. So the levers that matter aren't clever ALU tricks. They're &lt;strong&gt;don't allocate&lt;/strong&gt; and &lt;strong&gt;don't decode&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 1 · Zero-copy decode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithNoCopy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c"&gt;// strings alias data, no copy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;WithNoCopy&lt;/code&gt; returns strings and byte slices that point &lt;em&gt;into&lt;/em&gt; &lt;code&gt;data&lt;/code&gt; instead of copying out. On a string-heavy batch: &lt;strong&gt;~1.7× faster, 7000+ allocations collapse to 3&lt;/strong&gt; (the only one left is the output slice). The decoder is already pooled and its scratch buffers reused, so with aliasing there's essentially nothing left to allocate per value.&lt;/p&gt;

&lt;p&gt;The catch is honest and it's in the name. &lt;strong&gt;The returned values are valid only while &lt;code&gt;data&lt;/code&gt; stays alive and unmodified.&lt;/strong&gt; The footgun:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// recycled!&lt;/span&gt;
    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;Msg&lt;/span&gt;
    &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithNoCopy&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="c"&gt;// msg.Field aliases buf … which is about to be reused → garbage&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a &lt;strong&gt;use-after-free the race detector won't catch&lt;/strong&gt; (it's not a data race — it's manual memory). So &lt;code&gt;WithNoCopy&lt;/code&gt; is opt-in by design: perfect for read-and-discard over a buffer you own (a file, an mmap, a batch you process then drop), wrong for a pooled request body that outlives the call. Works on the reflection path, codegen, and streams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 2 · Decode in struct order
&lt;/h3&gt;

&lt;p&gt;The encoder writes fields in struct-declaration order, so on decode the next wire field is almost always the next struct field. The decoder keeps a &lt;strong&gt;cursor and tries the expected field first — one string compare — before falling back to a map lookup.&lt;/strong&gt; A profile of a wide-struct decode had &lt;strong&gt;~40% of time in &lt;code&gt;mapaccess1_faststr&lt;/code&gt; + the hash&lt;/strong&gt;; the cursor removes that on the common path. The map stays as the fallback, so out-of-order, partial, and unknown fields still decode correctly — you just pay the lookup for the ones that actually arrive out of order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 3 · Lazy, pooled state
&lt;/h3&gt;

&lt;p&gt;Decoders come from a &lt;code&gt;sync.Pool&lt;/code&gt;, and their machinery — the intern table, scratch slices — allocates only on &lt;strong&gt;first use&lt;/strong&gt;. A plain struct decode never touches the intern table, so it never pays for it. (Concretely: moving that table behind a lazily-allocated pointer cut a chunk of per-call overhead, because the codegen path builds a fresh decoder per nested value and was zeroing ~4 KiB of table it never used.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Lever 4 · The biggest win: don't decode at all
&lt;/h3&gt;

&lt;p&gt;Everything from §3 lands here too. Selective decode skips whole columns via the index and never rebuilds filtered rows. If your read pattern is "a few columns of a big batch," the fastest qdf decode is the one that touches almost none of the bytes. No micro-optimization beats not doing the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  For the last drop: codegen
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//go:generate qdfgen -type Event,Batch .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;qdfgen&lt;/code&gt; emits concrete methods using &lt;strong&gt;only the public API&lt;/strong&gt; — no reflect at runtime, no descriptor lookup. The generated decoder is a flat key switch (and it threads &lt;code&gt;noCopy&lt;/code&gt;, so zero-copy works on generated types too):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Sample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UnmarshalQDFOpts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noCopy&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoderOnBuf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;noCopy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetNoCopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMapHeader&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;// …&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadStringBytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// no alloc: compiler special-cases switch string([]byte)&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"age"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadInt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c"&gt;// …&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a fixed schema that's &lt;strong&gt;up to 8.5× faster decode than &lt;code&gt;encoding/json&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And on encode, &lt;code&gt;AppendMarshal&lt;/code&gt; hands you buffer ownership for zero per-call allocation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppendMarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OptBalanced&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// reuse your own buffer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The mental model:&lt;/strong&gt; encode allocations are constant (a flat 3, output buffer pooled); decode allocations scale with how much you ask for. So the two levers that matter are &lt;em&gt;alias-instead-of-copy&lt;/em&gt; (&lt;code&gt;WithNoCopy&lt;/code&gt;) and &lt;em&gt;ask-for-less&lt;/em&gt; (selective decode).&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Benchmarks, and how they're measured
&lt;/h2&gt;

&lt;p&gt;2019 i7-9750H, Go 1.26. Wire sizes are deterministic. Latencies are median of 6 runs; throughput claims use &lt;code&gt;benchstat&lt;/code&gt; over ≥10 interleaved runs so a single warm/cold run can't lie. Everything reproducible from the &lt;code&gt;bench/&lt;/code&gt; module — a &lt;em&gt;separate&lt;/em&gt; module so competitor deps (protobuf, &lt;code&gt;vmihailenco/msgpack&lt;/code&gt;, flatbuffers) stay out of the core, which has &lt;strong&gt;zero dependencies&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;bench
go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'^$'&lt;/span&gt; &lt;span class="nt"&gt;-bench&lt;/span&gt; Decode &lt;span class="nt"&gt;-benchmem&lt;/span&gt; &lt;span class="nt"&gt;-count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10 | &lt;span class="nb"&gt;tee &lt;/span&gt;new.txt
benchstat old.txt new.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wire size vs the field (bytes, lower is better)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;fixture&lt;/th&gt;
&lt;th&gt;json&lt;/th&gt;
&lt;th&gt;msgpack&lt;/th&gt;
&lt;th&gt;protobuf&lt;/th&gt;
&lt;th&gt;qdf balanced&lt;/th&gt;
&lt;th&gt;qdf compress&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OTLP 4×512&lt;/td&gt;
&lt;td&gt;1 027 033&lt;/td&gt;
&lt;td&gt;793 192&lt;/td&gt;
&lt;td&gt;561 860&lt;/td&gt;
&lt;td&gt;240 686&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;179 181&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logs 1024&lt;/td&gt;
&lt;td&gt;245 037&lt;/td&gt;
&lt;td&gt;193 476&lt;/td&gt;
&lt;td&gt;156 479&lt;/td&gt;
&lt;td&gt;89 631&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;62 149&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RTB 1024&lt;/td&gt;
&lt;td&gt;559 294&lt;/td&gt;
&lt;td&gt;428 404&lt;/td&gt;
&lt;td&gt;327 700&lt;/td&gt;
&lt;td&gt;258 167&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;203 360&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Events 1024&lt;/td&gt;
&lt;td&gt;122 857&lt;/td&gt;
&lt;td&gt;84 712&lt;/td&gt;
&lt;td&gt;64 978&lt;/td&gt;
&lt;td&gt;39 650&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;39 639&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IoT 32×256&lt;/td&gt;
&lt;td&gt;469 058&lt;/td&gt;
&lt;td&gt;224 534&lt;/td&gt;
&lt;td&gt;207 562&lt;/td&gt;
&lt;td&gt;158 474&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;148 177&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Smaller than protobuf on &lt;strong&gt;every&lt;/strong&gt; batch: OTLP −68%, Logs −60%, Events −39%, RTB −38%, IoT −29%. Because qdf compresses across records and protobuf doesn't. That's the entire gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throughput
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;workload&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decode vs &lt;code&gt;encoding/json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;4–9× faster&lt;/strong&gt; across payloads (2–7× vs msgpack)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Numeric/bool slices (QPack)&lt;/td&gt;
&lt;td&gt;5× smaller than json, &lt;strong&gt;21× faster encode, 80× faster decode&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIMD bit-unpack (AVX2/NEON)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;22–53× over scalar&lt;/strong&gt;, ~50 GB/s (memory-bound)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~150 MiB realistic payload (Dense)&lt;/td&gt;
&lt;td&gt;7.5× faster encode, &lt;strong&gt;8.1× faster decode&lt;/strong&gt; than json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encode (Fast, pooled)&lt;/td&gt;
&lt;td&gt;~1.1 GB/s, &lt;strong&gt;3 allocs/op&lt;/strong&gt; — vs ~1000 allocs/op for json &amp;amp; msgpack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Zero-copy decode (string batch)&lt;/td&gt;
&lt;td&gt;7002 → &lt;strong&gt;3 allocs&lt;/strong&gt;, −38% B/op, ~1.7× faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codegen decode&lt;/td&gt;
&lt;td&gt;up to &lt;strong&gt;8.5× over json&lt;/strong&gt; on a fixed schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selective decode (few columns)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;~5× faster &amp;amp; ~5× less memory&lt;/strong&gt; than full decode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm49rplojbqzb9akrvg3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm49rplojbqzb9akrvg3u.png" alt="Where qdf's wins come from, grouped by what each saves: CPU time, memory/allocs, wire size" width="799" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note the asymmetry: encode is a flat 3 allocations no matter the payload; decode allocations scale with how much you ask for — which is exactly why &lt;code&gt;WithNoCopy&lt;/code&gt; and selective decode matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Which knob, when
&lt;/h2&gt;

&lt;p&gt;One &lt;code&gt;Options&lt;/code&gt; bitmask on the &lt;strong&gt;encode&lt;/strong&gt; side. You never pass options to &lt;code&gt;Unmarshal&lt;/code&gt; — it reads the header and handles whatever it gets.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Reach for it when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OptSpeed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hot path, single messages, sub-µs latency. msgpack-shaped. The drop-in &lt;code&gt;encoding/json&lt;/code&gt; replacement. Also: use it if you hash/sign the bytes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OptBalanced&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Default for batches:&lt;/strong&gt; Dense interning + adaptive numeric codecs. Big wire win, still fast.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;`OptBalanced\&lt;/td&gt;
&lt;td&gt;OptColumnIndex`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OptCompression&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cold storage. Adds Gorilla/ALP + rANS. Smallest wire; encode slower — write-once-read-rarely.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WithNoCopy()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read-mostly over a buffer you own and won't mutate. Near-zero-alloc decode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AppendMarshal&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Own the output buffer for zero per-call allocation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;qdfgen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixed schema, every nanosecond counts — reflection-free generated methods.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The presets are just bundles of bits you'd compose by hand anyway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OptSpeed&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c"&gt;// Fast mode, nothing on&lt;/span&gt;
    &lt;span class="n"&gt;OptBalanced&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OptDense&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OptQPack&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OptShapeIntern&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OptPairPred&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OptMTF&lt;/span&gt;
    &lt;span class="n"&gt;OptCompression&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OptBalanced&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OptGorillaFloat&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;OptRANS&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One axis, left to right: &lt;strong&gt;lowest CPU → smallest bytes&lt;/strong&gt;. And every step is &lt;em&gt;never-larger&lt;/em&gt;, so moving right never inflates a buffer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OptSpeed  ──▶  OptBalanced  ──▶  OptCompression
fastest        −60% vs proto     smallest
≈ msgpack      still fast        slower encode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyufdhqo9omjro6jo3fub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyufdhqo9omjro6jo3fub.png" alt="Options axis: presets, the bits each turns on, and the CPU-vs-size tradeoff" width="799" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same Logs-1024 batch, measured: json &lt;strong&gt;245 KB&lt;/strong&gt; → msgpack 193 KB → protobuf 156 KB → &lt;code&gt;OptBalanced&lt;/code&gt; &lt;strong&gt;90 KB&lt;/strong&gt; → &lt;code&gt;OptCompression&lt;/code&gt; &lt;strong&gt;62 KB&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two build tags — free performance, off by default
&lt;/h3&gt;

&lt;p&gt;Orthogonal to &lt;code&gt;Options&lt;/code&gt;: these change the generated machine code, not the wire. Same bytes, faster processing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-tags qdf_simd&lt;/code&gt; — AVX2 (amd64) / NEON (arm64) bit-pack kernels, byte-identical output, runtime CPUID gate + scalar fallback. &lt;strong&gt;22–53× over scalar.&lt;/strong&gt; If you run &lt;code&gt;OptBalanced&lt;/code&gt;/&lt;code&gt;OptCompression&lt;/code&gt; on numeric data, turn it on — it's free.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-tags qdf_reflect2&lt;/code&gt; — swaps &lt;code&gt;reflect.MakeSlice&lt;/code&gt;/&lt;code&gt;MakeMapWithSize&lt;/code&gt;/&lt;code&gt;New&lt;/code&gt; for &lt;code&gt;modern-go/reflect2&lt;/code&gt; unsafe equivalents → smaller decode allocations on map/slice-heavy payloads. The one honesty note: this is the &lt;strong&gt;single opt-out from zero-dependency&lt;/strong&gt;. Worth it if your data is map/slice-dense and you're not on codegen.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go build &lt;span class="nt"&gt;-tags&lt;/span&gt; &lt;span class="s2"&gt;"qdf_simd qdf_reflect2"&lt;/span&gt; ./... // combine freely
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Streaming
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStreamEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;dec&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;qdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewStreamDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ev&lt;/span&gt; &lt;span class="n"&gt;Event&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The header is written once; the &lt;strong&gt;Dense intern table is shared across messages&lt;/strong&gt;, so a 10k-row log pays for each distinct key once (the second message's &lt;code&gt;"region":"eu-west-1"&lt;/code&gt; is a back-reference into the first). &lt;strong&gt;Each message is length-framed&lt;/strong&gt; — a uvarint byte-count precedes its body — so a message of &lt;em&gt;any&lt;/em&gt; size round-trips, even across a reader that hands you one byte per &lt;code&gt;Read&lt;/code&gt;, and &lt;code&gt;io.EOF&lt;/code&gt; marks the end cleanly. &lt;code&gt;SetNoCopy&lt;/code&gt; works here too; aliases stay valid for the stream's lifetime because the window is never compacted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;QDF hdr   │ len₁ · msg₁ │ len₂ · msg₂ │ … EOF
5B once   │ uvarint+body│ uvarint+body│
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F694axxa24ch36lo3x6n5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F694axxa24ch36lo3x6n5.png" alt="Stream framing: 5-byte header once, then each message length-delimited by a uvarint byte-count" width="776" height="2552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Streaming and columnar are the two halves of the design: &lt;strong&gt;streaming is row-by-row for unbounded feeds; columnar is a complete batch you can query.&lt;/strong&gt; So the whole-batch features — &lt;code&gt;OptColumnIndex&lt;/code&gt;, &lt;code&gt;Where&lt;/code&gt;/&lt;code&gt;Select&lt;/code&gt;, &lt;code&gt;OptRANS&lt;/code&gt; — aren't part of streaming, by design.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Where it doesn't win (the honest part)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OptSpeed&lt;/code&gt; wire ≈ msgpack — the speed tier skips columnar compression on purpose. Use &lt;code&gt;OptBalanced&lt;/code&gt; when you want the bytes back.&lt;/li&gt;
&lt;li&gt;The compression tier's encode is slower (Gorilla/ALP cost real CPU). It's a storage play, not a hot path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;protobuf and flatbuffers still win raw single-message decode and single-tiny-message size&lt;/strong&gt; — generated code and zero-copy field access are hard to beat when there's no batch to amortize over. Different tool for "one small message, decoded whole, hot."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;qdf's sweet spot is &lt;strong&gt;batches of structured records&lt;/strong&gt; you want small on the wire and partially readable later: telemetry, logging, metrics, analytics, event sourcing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/alex60217101990/qdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure Go, zero dependencies — nothing to vendor, no schema compiler in your pipeline. Swap it in where you use &lt;code&gt;encoding/json&lt;/code&gt;, flip a batch path to &lt;code&gt;OptBalanced|OptColumnIndex&lt;/code&gt;, read back just the columns you need — then go stare at your allocation graph.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/alex60217101990/qdf" rel="noopener noreferrer"&gt;github.com/alex60217101990/qdf&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Full API reference: &lt;a href="https://pkg.go.dev/github.com/alex60217101990/qdf@v0.0.1" rel="noopener noreferrer"&gt;pkg.go.dev/github.com/alex60217101990/qdf&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the query model or the codec picker is useful to you, a ⭐ on the repo helps others find it. And if you find a payload shape where qdf loses that it shouldn't — open an issue with the fixture. That's the most useful bug report there is.&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>serialization</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
