feat(blog): add SQLite FTS5 + Dense hybrid retrieval article - #251
ishwar170695 wants to merge 9 commits into
Conversation
919d215 to
0e21673
Compare
Signed-off-by: Ishwar <ishwarcm@iitbhilai.ac.in>
0e21673 to
9e914a0
Compare
saiyam1814
left a comment
There was a problem hiding this comment.
Thanks for putting this together. I read through the article and the added assets. Overall, this is a strong technical draft: it has a clear retrieval problem, a concrete architecture, code snippets, benchmark numbers, screenshots, and a useful tradeoff section. I think it can fit the KubeSimplify audience well if we frame it as AI infrastructure / backend retrieval engineering rather than only as a generic RAG article.
A few changes I would suggest before publishing:
-
Use the architecture diagram in the article
The PR addspublic/img/blog/sqlite-fts5-dense-hybrid-retrieval/architecture.png, but the post currently shows the pipeline as an ASCII diagram. This topic benefits a lot from a visual architecture diagram, so I would embed the image in the Architecture Overview section and optionally keep the text explanation around it. -
Fix the author image
public/img/authors/ishwar.jpgappears to be the same file as the blogcover.jpg. That looks accidental. Please replace it with an actual author avatar or a suitable placeholder image. -
Add more context around the benchmark numbers
The reported improvements are compelling (466 msto12 ms,320 MBto48 MB,68%to91%Top-5 retrieval), but they need enough context to be credible and reproducible. Please add details such as corpus size, hardware, Node/SQLite versions, embedding model/vector dimension, how the 100-query benchmark was constructed, and how relevance was judged. -
Verify math rendering for the RRF formula
The post uses$$...$$for the RRF equation. Please verify this renders correctly in the KubeSimplify site. If math rendering is not enabled, convert it to a plain-text/code-block formula so readers do not see raw LaTeX. -
Make the KubeSimplify fit more explicit
I would add a short section on where this belongs operationally: local-first backends, edge apps, small/medium corpora, Kubernetes workloads with persistent storage, serverless constraints, and when teams should move to Qdrant/Milvus/Elasticsearch. This would connect the article more strongly with KubeSimplify’s cloud-native/infrastructure audience. -
Add a note on FTS5 table population/sync
The SQLite FTS5 external-content table example is useful, but readers may wonder howsections_ftsstays in sync withsections. A short ingestion snippet or note about triggers/rebuild flow would make the implementation more complete. -
Polish the style for KubeSimplify
Consider removing emojis from section headings and using a cleaner tutorial/deep-dive style. The current content is good, but simpler headings would make it feel more consistent with existing KubeSimplify technical posts.
Overall: this is close and worth publishing after the above polish. The idea is useful, the implementation is practical, and the performance/tradeoff framing is exactly the kind of detail readers will appreciate once the claims and visuals are tightened up.
|
@saiyam1814 Thanks for the detailed review. I've addressed all the suggested changes:
I also verified that the site builds successfully with these changes. Thanks again for the suggestions! |
|
Did you test this on real hardware? |
Yes. I tested everything on my local machine. |
|
for some reason I am not able to see the preview on cloud flare, let me pull in locally and check |
|
@saiyam1814 @ishwar170695 Here's the preview for the current state of the PR https://post-sqlite-fts5-dense-hybri.website-dab.pages.dev/sqlite-fts5-dense-hybrid-retrieval |
|
@shkatara can you add feedback for this blog? |
|
I'm writing this from my phone so keeping it short. Architecture diagram is not understandable at all to people who are new to this. So many flows and nodes make it confusing than clearer. Flow representation is also not clear. How does one query branch off to different endpoints to search. Where is this configured. FTS5. / BM25. I'm guessing searching something over text so full text search. People not working with db have no idea what this is. Avoid using short forms or at least write full form after them in () Synchronizing the FTS5 Virtual Table: this is worded in a way someone from not a db background would fail to understand. External content table ? What is that. What is a virtual table ? We load only the id (string) and the coordinate list—pre-processed into a compact Float32Array object—into memory: what id is this of ? What is in the float32 array Explain the sql queries in english Because the architecture or packet flow is not clear, I can't put a mental model of why memory usage comes down by 85% What is RRF. What is BM25. The problem statement is good. And one that makes sense. The answer goes into a lot of depth and jargons that makes it hard to follow. I had to try at least three times to read it and always I could not finish. The blog should focus on keeping it simple. Keeping in mind people have no idea what we are writing about and would need help at each layer to put a mental model. If they are fighting to understand what these short forms are, the purpose is defeated. It's better to give them ideas that something like this is possible if the topic is dense, and let them explore their own cases. |
|
@ishwar170695 can you work on the feedback from @shkatara |
… and mental model first
018a736 to
7d7b6d0
Compare
|
@saiyam1814 @shkatara Thanks for the feedback. I've reworked the article to make it more beginner-friendly by simplifying the diagrams, reducing jargon, introducing concepts before acronyms, and focusing on the mental model first. I'd appreciate another review when you have a chance. Sorry for the delay, and thanks for your patience. |
|
Thanks for the rework @ishwar170695, and no worries at all about the delay. The clarity pass really landed. The new pipeline diagram is exactly what @shkatara was asking for: one clean top-to-bottom flow instead of the earlier tangle. Putting the mental model up front before any code was the right call, the I then went through the article side by side with the LawDecoder repo, and a few things have drifted apart between the post and the code. I want to close those before we publish, mainly to protect you: a post like this attracts readers who will clone the repo and run your snippets, and it is much better if everything they find matches. Before we publish1. The FTS5 snippet does not match The post (lines 109-120) shows an external content table: CREATE VIRTUAL TABLE IF NOT EXISTS laws_fts USING fts5(
id UNINDEXED, title, content,
content='laws',
content_rowid='rowid'
);with the caption that Two ways to fix, either is fine:
Also, 2. The repo link promises benchmark scripts Line 228 says the benchmark scripts are on GitHub, but I could not find a harness in the repo, and 3. The reranker deserves its own honest paragraph In const isDocumentForgeryRelated = queryLower.includes('signature') || queryLower.includes('sign') || queryLower.includes('document');
// ... coin/stamp/currency matches: adjustedScore *= 0.01
// ... titles containing forgery/forged: adjustedScore *= 3.0Hardcoded guardrails like this are completely legitimate, plenty of production retrieval systems ship exactly this. The issue is presentation. Right now the article's hook is the one query this rule was written for, so a reader naturally credits FTS5 and RRF for turning counterfeit coins into forgery sections, when part of the credit belongs to the rule. Two options: run a quick ablation over your 100 queries (RRF only vs RRF plus reranker) and publish both numbers, or add a short paragraph saying the reranker is a deliberate domain guardrail for this query class rather than a general component. The ablation would be a great addition if you have the time, since "how much did each stage buy me" is the question every reader will have. One small bug while you are in there: 4. The methodology details from the last round got lost Your earlier reply mentioned the Ryzen 5 5600H, Node and SQLite versions, and the embedding model, but they are not in the current file, I think the rewrite dropped them. Worth putting back, especially the embedding model and dimension ( 5. The memory story needs a breakdown This is the one I got stuck on, and I think it is also what @shkatara meant when he said he could not build a mental model for the 85%. Running the arithmetic: 4,892 sections at 384 dims and 4 bytes each is roughly 7.5 MB for the entire vector cache, and the statutory text for 4,892 sections is maybe 10 to 20 MB. Neither of those explains a 270 MB drop. My guess is the heap is actually dominated by the transformers models ( If that is right, the fix is easy and the post gets more interesting, not less: show a rough heap breakdown, and say the win came from dropping a full JSON parse and keeping typed arrays instead of object graphs. If I have the wrong end of it, a couple of numbers in the section will settle it. 6. Name the real cause of the latency win The table labels v1 as a linear JSON scan, which is honest, but the surrounding narrative lets the reader attribute 466 ms to 12 ms to hybrid retrieval. Most of that gap is really "we stopped re-parsing a JSON file on every query" and would have shown up even without FTS5 or RRF. One sentence saying so keeps the claim solid, and the hybrid architecture still has plenty to stand on with the accuracy result. Polish
Where that leaves usThe 6 items in the first section are what I would like fixed before we merge, and 1, 2, and 3 are the important ones since they are what a reader would notice when they open the repo. The polish list is quick and mostly mechanical. To be clear about the overall read: the idea is good, the engineering is real, and the writing is a big step up from the first draft. This is worth publishing once the post and the code tell the same story. Ping me when you have pushed and I will do another pass. |
…efresh citation screenshot
|
Updated the article and LawDecoder implementation based on the latest review. The current version now:
The benchmark and article now use the same measured results and methodology. |
|
Thanks @ishwar170695, and thanks for the patience on the long review cycle. Fresh preview is rebuilding here: https://post-sqlite-fts5-dense-hybri.website-dab.pages.dev/sqlite-fts5-dense-hybrid-retrieval cc @shkatara I went through the post against the LawDecoder repo again and test-merged the branch onto current
Every number re-checks: 161 / 7.8 is about 20x, 438 to 16 MB is 96%, 507 to 218 is 57%, 60 to 90 is +30 percentage points and you used "percentage points". The BSA citation is fixed, the corpus list matches the README, the screenshot order now matches the table, and the title is flatter. Good pass. One blocker left, and it is outside the post. The README contradicts the article on every headline number"Code & Repository" sends readers straight to the repo. The README there still carries the pre-review figures:
A reader who follows the link gets two different stories about the same system, and the older one is the one you and I agreed was overstated. That was the whole point of the last round, so please carry the corrected numbers and the 10-query methodology into the README before this goes out. While you are there, the README footnote points at Related, and quick: Fix in the post
Polish
Where that leaves usThe article itself is basically ready. The blocker is the README, and it is a fifteen-minute fix: copy the corrected numbers and the 10-query methodology across so the post and the repo say the same thing, then the LaTeX, the version string, the images, and the LawDecoder intro. Worth saying plainly, this went from a post I was not sure about to one I am glad we are running. The thing that turned it was you measuring the reranker and publishing the number that made your own feature look unnecessary. That is rarer than it should be, and it is why the rest of the numbers in here are believable. |
…nd assets Signed-off-by: Ishwar <ishwarcm@iitbhilai.ac.in>
Signed-off-by: Ishwar <ishwarcm@iitbhilai.ac.in>
Signed-off-by: Ishwar <ishwarcm@iitbhilai.ac.in>
…diagram pipeline with 50-20-5 funnel Signed-off-by: Ishwar <ishwarcm@iitbhilai.ac.in>
…est harness scope Signed-off-by: Ishwar <ishwarcm@iitbhilai.ac.in>
|
@saiyam1814 Thanks again for the detailed review and for being patient with all the back and forth. I’ve addressed the remaining feedback across the article and LawDecoder repo, including the benchmark methodology, FTS5 implementation details, 50 → 20 → 5 architecture diagram, updated dashboard/screenshots, and asset cleanup. I also did a fresh-clone check and corrected the benchmark instructions so they accurately reflect the local dataset scope. Also confirmed, I’m fine with the Signed-off-by from 9e914a0 standing for the whole squash on merge. This is my first time taking a technical blog through a review process like this, so I really appreciate the detailed feedback. It helped me catch quite a few things I would have otherwise missed. Please take another look when you get a chance. |
|
Thanks @ishwar170695. I went through the post against the LawDecoder repo again and checked the built assets rather than just reading the diff. The README blocker is closed, and closed properly. cc @shkatara Confirmed fixedThe README now carries the corrected numbers end to end: The rest of the list is done too, and I checked each one on the branch rather than taking it on trust:
The diagram did all three things I asked for and is genuinely good now. One thing leftThe article still promises a benchmark a fresh clone cannot run.
"Code & Repository" still reads: cd backend
npm install
npm run benchmark # Runs the 4-stage ablation and latency evaluation against the benchmark datasetSomeone who clones and follows that gets a crash on a missing file, and "the benchmark harness can be run directly from the backend directory" is the sentence that sent them there. Same fix as the README, one line under the block:
Committing Two nits while you are in there
Where that leaves usOne line in the post and the em dashes, and I will merge this. Sign-off from And for a first time through a review process this long, you handled it well. The thing I keep coming back to is that you measured the reranker and published the number that made your own feature look unnecessary, then explained why it still earns its place. That is the paragraph that makes the rest of the numbers in the post believable, and most people would have quietly dropped the ablation instead. |
Changes proposed
Adds a new, technical, practitioner-led article to the Kubesimplify blog focusing on hybrid retrieval architectures in local RAG systems.
content/blog/sqlite-fts5-dense-hybrid-retrieval.md— Deep-dive into sparse vs. dense search limitations, SQLite FTS5 BM25 configurations, Reciprocal Rank Fusion (RRF), deterministic domain reranking, and vector cache memory footprints.public/img/blog/sqlite-fts5-dense-hybrid-retrieval/— Static assets (architecture diagrams, benchmarks, UI screenshots).content/authors.json— Add author profile entry forishwar.public/img/authors/ishwar.jpg— Author avatar placeholder.No other changes are made to the site's code.
Note to reviewers
This post focuses on systems-level search engineering and database schemas (SQLite), which is well-suited for KubeSimplify's backend, cloud-native, and infrastructure audience.