Skip to content

feat(indexing): parse Markdown front matter with SnakeYAML, split multi-record files, and accept documents array - #207

Open
adityamparikh wants to merge 3 commits into
apache:mainfrom
adityamparikh:feat/markdown-multi-record
Open

adityamparikh wants to merge 3 commits into
apache:mainfrom
adityamparikh:feat/markdown-multi-record

Conversation

@adityamparikh

@adityamparikh adityamparikh commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Three changes to Markdown indexing. Supersedes #203 and #206.

Front matter is parsed by a YAML parser. Front matter is YAML, but its values did not come from a YAML parser: the commonmark front-matter extension reads the block line by line, and MarkdownDocumentCreator added a hand-rolled splitter for flow sequences ([a, b]). A quoted title containing a comma or a colon, a quoted list element, or a nested mapping came out wrong or was lost. The block is now sliced out verbatim using commonmark's source spans and handed to SnakeYAML, which Spring Boot already ships. Implicit type resolution is switched off, so every scalar stays the text as written (2026-01-01 is not turned into a Date, 8.4 not into a Double); Solr's schema guessing types it. Sequences become multi-valued fields, nested mappings flatten with underscores (ratings_imdb), nulls are skipped. The flow-sequence splitter is deleted.

One file can hold many documents. create() always returned a single document, so a 61-show sample dataset would have needed 61 separate files. A file may now hold several records, each its own front matter block followed by its body, and the dataset ships as one shows-markdown.md.

Batching via documents array parameter. Incorporates #203 to align with index-json-documents (#202). index-markdown-documents accepts documents: List<String>, allowing clients to pass multiple documents in a single tool call rather than initiating dozens of separate tool-call round trips.

Why the split rule is narrow

Markdown has no record separator of its own, and --- already means two other things — a thematic break, and a setext heading underline. Naive concatenation fails twice over: commonmark only recognises front matter at position 0, so later blocks become body text, and a mid-file --- promotes the preceding paragraph into a heading.

Splitting therefore engages only when all of the following hold:

  • the file itself opens with a front matter block — ordinary prose containing a thematic break is never considered;
  • a boundary is a --- line preceded by a blank line and followed by a YAML key — a rule followed by prose is not a boundary;
  • that block is closed by a later --- — an unterminated block is not a boundary.

Anything that is not unambiguously several records still yields exactly one document. The residual ambiguity is documented on splitRecords: a document that both opens with front matter and uses a thematic break immediately followed by a key: value line will split when it should not.

What changed

  • MarkdownDocumentCreator: parser built with includeSourceSpans(BLOCKS); addFrontMatterFields loads the block with SnakeYAML's SafeConstructor and a resolver with no implicit tags. create() splits into records and maps each through the existing per-document logic, extracted as createOne(); adds splitRecords() / isRecordStart().
  • IndexingService: indexMarkdownDocuments signature accepts List<String> documents and indexes all documents in one call.
  • build.gradle.kts: -H:IncludeResources for shows-markdown.md on the nativeTest binary, which is the one that reads the fixture. It is deliberately not in nativeImageBuildArgs, which feeds the shipped binary and the published *-native-* images — those never load a test resource.
  • README.md & tests: updated tool description and tests for the array parameter.

Tests

New MarkdownDocumentCreatorTest covers the YAML cases (quoted scalars with delimiters, flow and block sequences, nested mappings, typed-looking scalars kept as text, invalid YAML) and the split cases; ShowsSampleDataTest parses shows-markdown.md and checks its 61 documents against shows.json field for field. IndexingServiceTest covers the List<String> documents array input and null handling. The regression guard on the split rule is that the eleven MarkdownIndexingTest cases asserting hasSize(1) pass unedited — if the rule were even slightly too eager, several would go red. ./gradlew spotlessApply build on Java 25 passes.

@adityamparikh
adityamparikh force-pushed the feat/markdown-multi-record branch 2 times, most recently from 3c4f880 to ea17141 Compare September 14, 2026 19:36
@adityamparikh adityamparikh changed the title feat(indexing): index one markdown file as many documents feat(indexing): parse Markdown front matter with SnakeYAML and split multi-record files Sep 14, 2026
@adityamparikh
adityamparikh force-pushed the feat/markdown-multi-record branch from ea17141 to ea392ec Compare September 16, 2026 16:36
@adityamparikh adityamparikh changed the title feat(indexing): parse Markdown front matter with SnakeYAML and split multi-record files feat(indexing): parse Markdown front matter with SnakeYAML, split multi-record files, and accept documents array Sep 16, 2026
adityamparikh and others added 3 commits September 24, 2026 10:41
The front matter is YAML, but its values came from the commonmark
extension's line-by-line reader plus a hand-rolled splitter for flow
sequences, so a quoted title containing a comma or a colon, a quoted list
element, or a nested mapping came out wrong. The block is now sliced out
verbatim via commonmark's source spans and handed to SnakeYAML, which is
already on the classpath through Spring Boot. Implicit type resolution is
switched off so every scalar stays the text as written, exactly as before;
Solr's schema guessing types it. The flow-sequence splitter is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CiUHyyXLTo9ATdgg8eRFZJ
Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Markdown had no way to carry a dataset: create() always returned a single
document, so a 61-show sample dataset would have needed 61 files. A file may
now hold several records, each its own YAML front matter block followed by
its body, and the dataset ships as one shows-markdown.md.

Markdown has no record separator of its own, and `---` already means two
other things -- a thematic break and a setext heading underline. Naive
concatenation fails twice over: commonmark only recognises front matter at
position 0, so later blocks become body text, and a mid-file `---` promotes
the preceding paragraph into a heading. Splitting is therefore narrow: the
file must itself open with front matter, a boundary is a `---` line preceded
by a blank line and followed by a YAML key, and that block must be closed by
a later `---`. Anything that is not unambiguously several records still
yields exactly one document, so the eleven MarkdownIndexingTest cases
asserting hasSize(1) pass unedited.

ShowsSampleDataTest checks the 61 documents parsed from that one file
against shows.json, field for field.

The -H:IncludeResources arg sits on the nativeTest binary, which is the one
that reads the fixture; nativeImageBuildArgs feeds the shipped binary and
the published images, which never load a test resource.

Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Co-authored-by: Junie <junie@jetbrains.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019qWfXJUJ7TU3HJgtNZZq2E
Accept documents as an array of Markdown strings (one per document)
instead of a single Markdown string, avoiding multiple tool-call round
trips from LLM clients and aligning with index-json-documents.

Each array element is parsed for YAML front matter metadata, title,
headings, and body content.

Signed-off-by: Aditya Parikh <aditya.m.parikh@gmail.com>
Co-authored-by: Junie <junie@jetbrains.com>
@adityamparikh
adityamparikh force-pushed the feat/markdown-multi-record branch from ea392ec to 2f81f66 Compare September 24, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant