feat: add configurable FTS5 tokenizer for CJK text support#41810
feat: add configurable FTS5 tokenizer for CJK text support#41810carrotRakko wants to merge 2 commits into
Conversation
Add a `memorySearch.store.fts.tokenizer` config option that allows selecting the FTS5 tokenizer. Default remains `unicode61` (backward compatible). Setting `"trigram"` enables substring matching for CJK (Chinese, Japanese, Korean) text that unicode61 cannot tokenize. Changes: - Add `store.fts.tokenizer` to MemorySearchConfig type and Zod schema - Pass tokenizer to ensureMemoryIndexSchema for FTS table creation - Detect tokenizer changes in MemoryIndexMeta and trigger full reindex - Reset FTS table with DROP + re-CREATE on tokenizer change - Skip CJK bigram splitting in query-expansion when using trigram - Auto-apply `case_sensitive 0` when trigram is selected Known limitation: trigram does not match queries shorter than 3 characters via FTS MATCH. In hybrid mode, vector search covers these cases. ✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
Greptile SummaryThis PR adds a configurable FTS5 tokenizer ( Key issues found:
Confidence Score: 2/5
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4bb8da8539
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Chinese tokenization path was emitting individual characters (unigrams) in trigram mode, but SQLite FTS5 trigram tokenizer requires >= 3 chars per query term. Single characters silently return no results, breaking Chinese search entirely. Now mirrors the Japanese kanji path: pushes the whole contiguous CJK block as a single token. Also propagates ftsTokenizer option through expandQueryForFts and expandQueryWithLlm fallback paths. ✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
|
Addressing the two issues flagged by Greptile (both in "Comments Outside Diff"): 1. Chinese unigrams incompatible with trigram FTS5 (lines 699–710) Fixed in 92be66c. The Chinese tokenization path now mirrors the Japanese kanji path: in trigram mode, it pushes the whole contiguous CJK block as a single token instead of individual characters. SQLite FTS5 trigram tokenizer requires >= 3 characters per query term; single characters silently return no results. Before: 2. Fixed in 92be66c. Both ✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 92be66cd05
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Real-world validation from a heavy CJK userI've been running OpenClaw with Chinese memory for months and independently discovered the same FTS5 issue. Here's our production data: Before fix (unicode61 tokenizer)
Workaround we deployed (3 months ago)Since we couldn't wait for upstream, we applied a multi-layered fix:
After fix
Supporting this PRThe
Strong +1 for merging this. CJK users are effectively flying blind without it. 🦞 |
|
@laolin5564 Thank you for the detailed real-world validation — production data with before/after hit rates is exactly the kind of evidence that helps upstream maintainers evaluate a PR. Much appreciated. Responding to each suggestion: 1. Migration path: The code handles this automatically. 2. 3. Write-side space-separation as defense-in-depth: Your workaround was clever and effective under unicode61 constraints. With the trigram tokenizer, FTS5 handles sub-string matching natively, so the write-side trick becomes unnecessary. That said, the space-separated tags approach has independent value for readability — no reason to remove it if it is already in place. Your 0/7 → 7/7 hit rate improvement is a compelling data point. Thanks for sharing it here. ✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved) |
|
Maintainer follow-up: I pulled/rebased this locally, fixed the remaining short-CJK trigram gap, and verified the memory-search surface. I cannot update the PR branch directly because the PR head is on Commits prepared locally:
Suggested apply path from the PR branch: git fetch https://github.com/openclaw/openclaw.git feat/fts5-tokenizer-config
git cherry-pick 4d531fe78838b5a5f4daefa82f2d8273a91fe5bc 2e0d3e4219b2da7e3f96544e2ac012eecf1a25d0What this fixes:
Focused verification I ran: pnpm test -- extensions/memory-core/src/memory/manager-search.test.ts packages/memory-host-sdk/src/host/query-expansion.test.ts src/config/schema.base.generated.test.ts
pnpm config:schema:check
pnpm config:docs:checkNew/expanded regression coverage includes:
Refactor suggestion after landing:
Once those two commits are on this PR branch, the remaining behavior gap I found should be closed. |
|
Closing this as implemented after Codex review. Current What I checked:
So I’m closing this as already implemented rather than keeping a duplicate issue open. Review notes: reviewed against 7ac35b4f6900; fix evidence: release v2026.4.5. |
Summary
unicode61tokenizer, which tokenizes by word boundaries. CJK text (Chinese, Japanese, Korean) has no word boundaries — entire sentences become single tokens. BM25 ranking returns zero results for CJK queries.memorySearchis unusable for any agent handling CJK text. Memory entries in Japanese/Chinese/Korean cannot be found.store.fts.tokenizerallows selecting the FTS5 tokenizer. Setting it to"trigram"enables character n-gram tokenization that works for CJK. Query expansion logic adapted to handle trigram tokenizer behavior.unicode61for backward compatibility. Existing memory databases are not migrated automatically.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
New config field
store.fts.tokenizeraccepts"unicode61"(default) or"trigram". When set to"trigram",memorySearchworks with CJK text. Requires creating a new memory database (or deleting the existing FTS table) for the tokenizer change to take effect.Security Impact (required)
Repro + Verification
Environment
store.fts.tokenizer: "trigram"Steps
store.fts.tokenizer: "trigram"in configmemorySearchExpected
Actual
Evidence
New tests in
query-expansion.test.tsverify trigram tokenizer query generation and CJK text handling.Human Verification (required)
Review Conversations
N/A — fresh PR, no review conversations yet.
Compatibility / Migration
store.fts.tokenizerstore.fts.tokenizer: "trigram"in config, then delete the existing memory database or drop the FTS table to trigger recreation.Failure Recovery (if this breaks)
store.fts.tokenizerfrom config to revert tounicode61.src/memory/manager.ts,src/memory/memory-schema.tsRisks and Mitigations
✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)