GrooveSeek

Semantic search over a Markdown knowledge base, served over MCP.

View the Project on GitHub alphabet-h/grooveseek

2. Compile queries into per-token OR phrases for full-text search

Context and Problem Statement

kb-mcp’s hybrid search fuses two retrievers with Reciprocal Rank Fusion: a sqlite-vec KNN over embeddings, and SQLite FTS5 over a trigram tokenizer. Until v0.16.0 the FTS half received the user’s query wrapped in a single quoted phrase. Over a trigram tokenizer a quoted phrase is a contiguous-substring match, so that construction searched for the entire query verbatim.

For a keyword this behaves acceptably. For a sentence it matches nothing at all, because no document contains the question as written. Measured on the dogfood knowledge base (650 documents, 9,419 chunks), all ten natural-language golden queries returned zero FTS candidates, and of the 26 main golden queries only 16 had anything to fuse. On those queries the hybrid was not hybrid: RRF had one input, and the system had been running as vector-only retrieval while reporting itself as hybrid.

The defect is invisible from the outside. Nothing errors, no candidate count is surfaced to a user, and results still come back — worse ones, from one retriever. It survived fifteen releases, and the tests were structurally unable to catch it: every fusion test placed the FTS-matching chunk at the query vector, so the vector half alone satisfied the assertion.

The question this decision answers is how a query should be turned into an FTS5 MATCH expression, given a tokenizer that only matches substrings and a corpus that is mostly Japanese, where words are not separated by spaces.

Decision Drivers

Considered Options

  1. Status quo — one verbatim phrase per query.
  2. Morphological analysis — segment Japanese with a dictionary-backed tokenizer (lindera, vibrato) and emit one phrase per morpheme.
  3. Split at script boundaries — cut the query at separators, then at transitions between kanji, hiragana, katakana, and other word characters.
  4. Pass the query to FTS5 unquoted and let its own expression parser tokenize it.

Decision Outcome

Chosen option: 3 — split at script boundaries, because it recovers most of the benefit of segmentation at none of its cost, and because it is a pure function of the query string that can be tested exhaustively.

再ランキングの評価について compiles to "再ランキング" OR "ランキング" OR "の評価" OR "について". Script transitions are a coarse but real proxy for word boundaries in Japanese: compounds are typically kanji runs, loanwords katakana runs, and grammatical particles hiragana.

Measured on the dogfood corpus with the same scratch copy before and after (bge-m3, no reranker):

  before after
Golden queries where fusion has two inputs 16/26 26/26
MRR (main / binary golden) 0.955 / 0.939 0.962 / 0.955
recall@10 0.954 0.965
recall@5 0.926 0.906

Why the others were not chosen:

Interface changes

Two things became part of the contract with users and with stored data:

Consequences

Confirmation

More Information