docs(search-semantic): correct the boundary-aware chunker settings - #478
Merged
Conversation
codelibs/fess#3211 makes the length chunker move each cut to a sensible text boundary and adds three settings for it. The 15.8 semantic search page did not mention them, and one existing row became wrong. content_chunker.length.chunk_size was described as "Number of characters per chunk". It is now a target rather than a hard limit: a chunk may be up to lookback_percent of it shorter and up to max(lookahead, 32) characters longer, so 640 to 840 characters with the shipped defaults. That matters to anyone who sized it against an embedding model's token budget. content_chunker.length.overlap now also snaps its restart point to a boundary, and snapping can only move it earlier, so the effective overlap is between the configured value and twice it. content_chunker.max_chunks_per_document now notes that boundary-aware splitting yields roughly 3% to 25% more chunks per document, and that a document crossing the cap is marked skipped and receives no embeddings at all. Added rows for content_chunker.length.boundary.enabled, .lookback_percent and .lookahead_percent, plus a note that disabling the feature -- or setting both percentages to 0 -- reproduces the previous fixed-length behaviour exactly, and that a change only affects documents chunked afterwards. All seven languages. Verified: every list-table still has 22 rows and 44 cells in each language, all three keys are present in each, and docutils reports no non-Sphinx diagnostics for any of the seven files.
The boundary settings landed on master in the meantime, so both sides edited the same content_chunker table and added a note about it in all seven languages. Resolved by keeping master's text and folding this branch's corrections into it, then merging the two overlapping notes into one. Corrections kept from this branch, all checked against LengthChunker and ChunkVectorHelper: - The worst case is 840 characters, not "about 841". The bound is chunk_size + max(lookahead, 2 * ChunkBoundaryFinder.MAX_CLUSTER_ADJUST), i.e. 800 + max(40, 32); the further "+ 1" branch in findChunkEnd requires ideal to equal start + 1, which MIN_CHUNK_SIZE makes unreachable from LengthChunker. The floor, 800 - 160, was not stated at all, so the table now gives the full range of 640 to 840 characters. - A cut does not move to "the nearest suitable break, preferring" one kind over another. Candidates are tiered and the nearest candidate of the highest tier present wins: a line break or sentence end beats any clause separator or space no matter how much farther back it is, and those beat a writing-system change. - content_chunker.length.overlap snaps its restart point to a boundary as well. snapOverlapStart only ever moves it earlier and its window is capped at the configured overlap, so the effective overlap is between the configured value and twice that value. - content_chunker.max_chunks_per_document: a document over the cap is marked skipped and receives no embeddings, so it stays keyword-searchable but drops out of semantic search. Boundary-aware splitting also yields roughly 3% to 25% more chunks per document, which makes the cap easier to reach. - Changing any of these settings only affects documents chunked afterwards: a document already stored as a chunk array keeps its boundaries until it is re-crawled. Kept from master: the guarantee that only the cut point moves so concatenating a document's chunks still reproduces its content exactly, and the description of the grapheme-cluster overshoot. Verified: table shape (23 rows / 69 cells) and note count unchanged from master in every language, all three keys present in each, every line within each file's pre-existing 123-column display width, and docutils reports a diagnostic set identical to master for all seven files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documents the boundary-aware chunker from codelibs/fess#3211. Tracked as codelibs/fess#3231 (filed there because issues are disabled on this repository).
Rebased onto the current
master. #475 landed the same three settings while this was open, so this PR is now a correction and extension of that text rather than the original addition. The overlapping notes the two branches each added are merged into one.Corrections to what #475 landed
All three checked against
LengthChunker/ChunkBoundaryFinder/ChunkVectorHelper.1. The worst case is 840 characters, not "about 841". The bound is
chunk_size + max(lookahead, 2 * ChunkBoundaryFinder.MAX_CLUSTER_ADJUST)=800 + max(40, 32). The further+ 1branch infindChunkEndrequiresideal == start + 1, whichMIN_CHUNK_SIZEmakes unreachable fromLengthChunker. The floor —800 - 160— was not stated at all, so the table now gives the full range: 640 to 840 characters. That matters to anyone who sizedchunk_sizeagainst an embedding model's token budget.2. A cut does not move to "the nearest suitable break … preferring" one kind over another. Candidates are tiered, and the nearest candidate of the highest tier present wins: a line break or sentence end beats any clause separator or space no matter how much farther back it is, and those beat a writing-system change. This is the part the upstream PR got wrong three times in its own prose.
3.
content_chunker.length.overlapsnaps its restart point to a boundary too.snapOverlapStartcan only move it earlier, and its window is capped at the configured overlap, so the effective overlap is between the configured value and twice it. Not documented at all before.Additions
content_chunker.max_chunks_per_document— a document that crosses the cap is markedskippedand receives no embeddings at all: it stays keyword-searchable but drops out of semantic search. Boundary-aware splitting also makes chunks shorter, so a document yields roughly 3% to 25% more chunks than a fixed-length split (measured: +2.7% on Japanese prose, +9.3% on English prose, +24.8% worst case) — the cap is easier to reach than it was. The row now says both.Re-chunking requires a recrawl — changing any of these settings only affects documents chunked afterwards; a document already stored as a chunk array keeps its boundaries until it is re-crawled.
Kept from #475
The guarantee that only the cut point moves, so concatenating a document's chunks still reproduces its content exactly, and the description of the independent grapheme-cluster overshoot that ignores
lookahead_percent.Scope
All seven languages:
en,ja,de,es,fr,ko,zh-cn.Verification
A full Sphinx build is not reproducible from this repository alone (
conf/conf.pyis templated by the builder), so the checks are structural:content_chunker.*list-table still has the same shape asmaster(23 rows / 69 cells) in each of the seven languages;.. note::blocks per file is unchanged frommaster(the two overlapping notes were merged, not stacked);docutilsparses all seven files with a diagnostic set identical tomaster(zero non-Sphinx diagnostics);