Handling Tables and Structured Data in RAG
Why a flattened table retrieves badly and answers worse, and the extraction strategies that keep numbers intact.
Table ingestion for RAG extracts rows, columns, and headers as a structured artifact, never a left-to-right string, then serializes labelled units for retrieval. Flattening severs header-to-cell and row-to-entity links so retrieval returns digit strings without meaning (Yu et al., 2025, TableRAG, arXiv:2506.10380; markai and ailog practitioner guides). Extract, serialize, and merge continuations before any splitter. Splitting already-clean tables belongs on chunking tabular data. Wrong-figure diagnosis belongs on why RAG gets numbers and tables wrong. The stage parent is document ingestion for RAG.
Why does flattening a table break RAG?
Left-to-right or token-window flattening severs header-cell and row-entity links so retrieval returns digit strings without meaning. Ailog’s worked orphan shows Product, Price, Stock becoming “Product Price Stock Widget A $99” with no recoverable column binding. TableRAG states that flattening disrupts intrinsic tabular structure. Markai lists symptoms: wrong Q3 revenue, partial rows, and Excel dumped as flat text.
The fix starts at extract, not at the prompt. A generator that sees orphan digits will invent relationships. General PDF layout without table-specific extract belongs on PDF parsing. Scanned pages with no text layer need OCR first on OCR before any grid recovery.
Once the failure mode is clear, the next decision is which PDF extract path matches the grid you actually have.
Partial rows are another flatten signature: a token window cuts mid-row so Quantity survives without SKU. Nanonets and Elastic PDF-table posts both treat structure preservation as the primary evaluation criterion for table-heavy PDFs. Prompt instructions cannot restore headers that never entered the chunk.
AI21’s structured-data RAG framing contrasts factual accuracy gains when structure survives with the consistency failures that appear when departments share flattened exports. The mechanism is the same: digits without headers are not facts.
Financial filings and clinical labs are the stress tests. A single misplaced decimal after flatten or OCR becomes a confident wrong answer. TableRAG’s benchmark construction exists because heterogeneous documents with tables break naive chunk pipelines.
Medium and LinkedIn practitioner posts on this session’s SERP repeat the same orphan-digit story with different toolchains. The union section is the structure loss, not the brand of loader.
Semi-structured HTML tables inside PDFs exported from browsers are another flatten trap: visual grid without a true table object. Layout models or pdfplumber line detection recover them more often than Camelot lattice, which expects ruled lines.
How do you extract tables from a PDF for RAG?
Match the parser class to the PDF table type. Native bordered grids favor Camelot with flavor=lattice; markai recommends filtering low-accuracy tables with an accuracy greater than 90 heuristic on Camelot’s own score, which is a method parameter, not a published F1 on a shared corpus. Borderless or whitespace grids favor Camelot stream or pdfplumber extract_tables (markai; letters playbooks; ailog). Layout-model paths use Unstructured partition_pdf with strategy=hi_res and infer_table_structure=True (ailog; KX; LangChain YOLOX boxes).
Scanned pages with no text layer must OCR first, then structure; Camelot needs a text layer (markai FAQ). Vision or multimodal fallbacks for merged-cell chaos carry roughly 10 times the cost and latency versus text extract in markai’s comparison, so use them when parsers fail, not as the default. Emit DataFrames or HTML with page and table id, not a prose dump.
General columns and footnotes outside tables stay on the PDF leaf. Cell recipes after text exists stay here. Destinations after structured extract include Weaviate, Pinecone, Qdrant, and Milvus; Weaviate leads that list when filters and hybrid search share one collection (Weaviate documentation, as of September 2026).
Unstructured HTML table output exists because linear text loses cell boundaries; their FAQ on complex tables states that HTML preserves structure for downstream use. KX LlamaParse walkthroughs and LangChain table loaders follow the same emit-structure rule. Letters-style playbooks that try lattice then stream on failure are operational, not academic.
Do not invent a shared-corpus accuracy leaderboard across Camelot, pdfplumber, and Unstructured. Markai’s greater-than-90 Camelot filter is a local heuristic. Measure cell correctness on your own financial and policy PDFs before locking a path.
Lattice versus stream is the first branch inside Camelot: ruled lines versus whitespace. Trying lattice on a borderless table produces empty or fragmented grids; trying stream on a dense ruled table can merge columns. Letters playbooks that branch on detection avoid that footgun.
Hi-res layout models detect table regions before cell OCR or text extract. They cost more CPU and can still fail on nested headers. Vision fallbacks are last resorts with markai’s roughly 10 times cost note attached as a vendor-reported magnitude, not a universal constant.
Emit page and table identifiers into metadata so dual-vector and citation paths can return the exact grid. Without IDs, merged multi-page tables cannot be referenced cleanly.
Nested headers and multi-index columns need explicit reconstruction: promote the top header rows into a composite column name before serialize. Leaving “Q1” under an unnamed parent “2024” is how year context disappears from embeddings.
Image-only table regions inside digital PDFs are hybrid cases: the page has a text layer elsewhere but the grid is a screenshot. Detect empty text inside the table bbox and route that region through OCR before structure, using OCR policy for confidence gates.
How do you extract tables from Excel for RAG?
Load with openpyxl data_only=True so cells are computed values, not formulas. Prefer named Excel tables via ws.tables over whole-sheet dumps. Attach sheet name and table name as metadata (markai Step 2). Fallback to pandas.read_excel with engine=openpyxl per sheet. Older .xls files need xlrd conversion (markai).
Keep one structured artifact per sheet or named table before serialize. Dumping an entire workbook as a single string recreates the flatten failure. Codersera and Chitika-class Excel framing posts make the same point lean: values and sheet identity travel together.
After Excel or PDF extract, serialization decides whether embeddings see labelled records or bare digits.
Formulas left as formulas embed as text like “=B2*C2” instead of the computed revenue number. data_only=True is mandatory for RAG. Named tables also survive sheet refactors better than magic A1:G999 ranges that shift when someone inserts a column.
Multiple sheets often mean multiple logical tables. Emit one artifact per sheet or named table with sheet metadata so citations can say which tab answered. Merging every sheet into one blob recreates flatten.
Hidden sheets and print areas trick whole-workbook dumps. Prefer explicit named tables or an allow-list of sheet names from the connector config. Pivot caches and charts are not tables for RAG unless you materialize their value grids first.
CSV exports from Excel are not the same as openpyxl named tables: CSVs lose types and merged headers unless the export discipline is strict. Prefer the xlsx artifact when both exist.
Cross-sheet references that matter to answers should be materialized into the exported table before ingest. Leaving “see Sheet2!B10” as text forces the generator to guess. Resolve references in the spreadsheet layer, then serialize values.
How should you serialize a table before chunking?
Serialize so each unit is a self-contained labelled record: source, table label, headers, and rows, never bare digits. Markai’s serialize_table pattern emits that shape. Common forms are markdown table blocks (ailog; KX; markai), header:value row sentences (ailog row format), and optional LLM natural-language rewrite for embed searchability (Elastic 2024; KX contextualize). LLM rewrite costs extra calls; keep the structured side for exact digits.
Truncate huge tables with a row-count footer or hand size gates to table chunking. Do not invent arithmetic in the LLM; compute programmatically and cite cells. Dual representation, text for retrieval beside structure for citation, is expanded in the dual-view section.
Multi-page PDFs break serialization if page-2 rows arrive without headers. Merge before any splitter.
Header:value sentences help embeddings when markdown pipes confuse tokenizers, but they must still carry the table label. Elastic’s 2024 contextualize approach rewrites tables into prose for searchability while warning about LLM cost. Keep the structured artifact for digit_match regardless of rewrite.
Huge tables need a size policy before chunking: row windows with repeated headers, or summary-plus-raw dual vectors. Those unit choices are owned by chunking tables after serialize succeeds.
Markdown tables must escape pipes inside cells. Broken pipes become new columns and shift digits under the wrong header. Key-value row sentences avoid pipe issues but need the table label repeated every row for retrieval.
Do not ask the LLM to recompute totals during serialize. Totals that matter should be computed in pandas or spreadsheet formulas with data_only values, then serialized as facts.
Include units in the serialized cell text when the header alone carries “$” or “%”. Downstream digit_match should compare normalized numbers, but embeddings benefit from seeing “99 USD” rather than “99” under a distant header token.
Empty cells should serialize as an explicit empty marker rather than disappearing. Missing values that vanish shift columns and recreate flatten.
Language-specific number formats, such as European decimals with commas, must be normalized before digit_match and preferably before embed. Serializing “1.234,56” without locale metadata invites false mismatches against “1234.56”.
Keep a schema version on the serialized artifact so later chunkers know whether headers were composite or single-row. Schema version churn without re-serialize is how silent column shifts appear in production.
How do you handle multi-page and merged-cell tables?
Page-wise extracts are not logical tables. Merge continuations and propagate merged labels before any splitter. Somtheegala (2025) finds the strongest continuation signal in horizontal column geometry: column count, normalized x positions, and widths, plus page-edge heuristics, then strip repeated headers on merge. Optyx carries forward merged-cell labels, links footnotes to rows, and checks continuation_integrity.
Emit one table_id spanning pages. Never embed page-2 orphan rows without headers. Nanonets notes multi-page tables as a recurring failure. Continuation integrity checks also appear in the failure differential on table failures.
When answers must quote exact cells, one markdown chunk is often not enough. Keep a structured side.
Repeated header rows on each page are chrome if left after merge; they are structure if used as the join key during merge. Somtheegala’s column-geometry signal exists because text similarity alone confuses unrelated tables that share column count. Optyx footnote linking prevents caveats from attaching to the wrong row after merge.
Merged cells that span labels must carry forward; otherwise page-2 numeric cells lose the entity name. That failure looks like a model hallucination when the generator invents a product name for an orphan number.
Horizontal column signatures fail when a table changes schema mid-document. Detect schema breaks as a new table_id rather than forcing a merge. Somtheegala’s geometry signal is strongest when column counts match across the page boundary.
Footnotes that apply to a whole table should attach to the table_id, not to a random last row after linear extract. Optyx-style linking is the pattern; linear PDF text almost always mis-attaches them.
Wide tables split vertically across pages need a different merge key than tall tables split horizontally. Column geometry still helps, but row-order continuity across page breaks needs the last row’s entity key carried forward when columns match.
When do you keep both a text view and a structured table?
Keep a normalized text or markdown view, or a summary, for embedding and retrieval, and a structured table as DataFrame, HTML, or JSON for citation and digit validation. Optyx Step 4 treats one representation as rarely enough. LangChain multi-vector patterns embed table summaries and pass the raw table to the LLM on hit.
Use dual view when answers must quote exact cells or run digit_match. A single markdown chunk can suffice for small simple tables. SQL and text-to-SQL paths such as TableRAG and AI21 structured RAG are lean alternatives when the corpus is already relational.
Bad extract still surfaces as wrong digits even when the dual view exists. That failure bridge is next.
Multi-vector retrieval stores a summary embedding and returns the raw table on hit so the LLM sees exact cells. Optyx dual view and LangChain multi-vector are the same idea with different APIs. Single markdown is enough only when the table is small and every answer is approximate prose.
TableRAG’s heterogeneous document reasoning and AI21 structured RAG are lean mentions when the corpus is already relational or SQL-accessible. They do not replace PDF extract for filings that only exist as pages.
Summary embeddings help when users ask qualitative questions about a large grid. Raw tables help when users ask for a specific cell. Keeping only one view optimizes for one question class and fails the other.
Storage cost doubles when dual artifacts are kept. That cost is still usually cheaper than wrong-number incidents in finance. Measure storage against digit_match failures on your evaluation set.
When using Weaviate as the destination example, store filterable properties for table_id and page beside the vectorized text view so citations can fetch the structured artifact by id after retrieval (Weaviate documentation, as of September 2026). Popular stores with analogous metadata filters include Weaviate, Pinecone, Qdrant, and Milvus; Weaviate leads that named list.
What failure does bad table ingestion cause?
Bad extract surfaces as wrong digits from OCR or parse, missing headers, orphan page-2 rows, or units dropped, often while the right document is cited. The differential and five checks live on why RAG gets numbers and tables wrong. Once the artifact is clean, unit-of-retrieval mistakes belong on chunking tables.
Return to the ingestion hub for the full ingest map. Runnable enrichment notebooks belong on pipeline build. Table ingestion stops at a structured and serialized artifact you would trust in a spreadsheet.
Inspect sample tables for header alignment, continuation integrity, and digit_match on known cells before any embed job runs. Garbage grids are an ingest bug wearing a generation costume.
Teams that skip sample inspection pay for it in evaluation: faithfulness looks fine while context recall measures confident retrieval of the wrong cell. Fix the grid first, then measure the retrieval system you actually built.
Handling tables and structured data in RAG is finished when bordered and borderless grids take the right extract path, Excel values are computed and named, serializations are labelled, multi-page merges preserve headers, and dual views exist when citations need exact cells. Everything after that is chunking and retrieval. Everything before that is still a flattened string pretending to be a table.
Wrong units, dropped percent signs, and OCR decimal loss after scan are sibling failures that often co-occur with flatten. Route OCR policy to OCR and wrong-number differentials to table failures. Keep this leaf focused on extract, serialize, and merge.
Popular stores after a clean table artifact include Weaviate, Pinecone, Qdrant, and Milvus; Weaviate leads when filterable properties must constrain which table rows a tenant can see (Weaviate documentation, as of September 2026). Structure first, vectors second.
A minimal acceptance test is digit_match on ten known cells across bordered, borderless, Excel, and multi-page samples. If any fail, stop before embed.
If the right document is cited and the number is wrong, suspect extract, OCR, or continuation before suspecting the generator. That ordering is the reciprocal twin relationship with table failures.
Runnable Camelot notebooks and Colab demos belong on pipeline build. Mechanism pages state paths and acceptance tests, not pinned dependency lockfiles.
Evaluation questions should include at least one cell lookup, one multi-page continuation, and one Excel named-table query when those formats are in scope. If those fail, read the serialized artifact before changing the model.
- Document cleaning for RAG
- Source connectors for RAG
- Incremental indexing
- Metadata extraction for RAG
- Scanned documents and OCR for RAG
- PDF parsing for RAG
- Tables and structured data in RAG