Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
#
|
|
|
|
|
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
|
|
|
|
#
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
|
#
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
#
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
|
# limitations under the License.
|
|
|
|
|
#
|
|
|
|
|
|
2026-06-08 04:08:23 -07:00
|
|
|
"""Unit tests for aggregate_table_doc_metadata."""
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
2026-06-08 04:08:23 -07:00
|
|
|
from rag.utils.table_es_metadata import aggregate_table_doc_metadata, merge_table_parser_config_from_kb
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def es_engine(monkeypatch):
|
|
|
|
|
monkeypatch.setattr("rag.utils.table_es_metadata.settings.DOC_ENGINE_INFINITY", False)
|
|
|
|
|
monkeypatch.setattr("rag.utils.table_es_metadata.settings.DOC_ENGINE_OCEANBASE", False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def infinity_engine(monkeypatch):
|
|
|
|
|
monkeypatch.setattr("rag.utils.table_es_metadata.settings.DOC_ENGINE_INFINITY", True)
|
|
|
|
|
monkeypatch.setattr("rag.utils.table_es_metadata.settings.DOC_ENGINE_OCEANBASE", False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _table_task(**kb_extra):
|
|
|
|
|
return {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "manual",
|
|
|
|
|
"table_column_roles": {"country": "metadata", "category": "metadata"},
|
|
|
|
|
"table_column_names": ["country", "category"],
|
|
|
|
|
"field_map": {
|
|
|
|
|
"country_tks": "country",
|
|
|
|
|
"category_tks": "category",
|
|
|
|
|
},
|
|
|
|
|
**kb_extra,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestAggregateTableManualDocMetadata:
|
|
|
|
|
def test_aggregate_manual_mode_happy_path(self, es_engine):
|
|
|
|
|
task = _table_task()
|
|
|
|
|
chunks = [
|
|
|
|
|
{
|
|
|
|
|
"country_raw": "Brazil",
|
|
|
|
|
"category_raw": "Economy",
|
|
|
|
|
"country_tks": "x",
|
|
|
|
|
"category_tks": "y",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"country_raw": "Turkey",
|
|
|
|
|
"category_raw": "Disaster",
|
|
|
|
|
"country_tks": "x",
|
|
|
|
|
"category_tks": "y",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"country_raw": "Brazil",
|
|
|
|
|
"category_raw": "Economy",
|
|
|
|
|
"country_tks": "x",
|
|
|
|
|
"category_tks": "y",
|
|
|
|
|
},
|
|
|
|
|
]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out["country"] == ["Brazil", "Turkey"]
|
|
|
|
|
assert out["category"] == ["Economy", "Disaster"]
|
|
|
|
|
|
2026-06-08 04:08:23 -07:00
|
|
|
def test_aggregate_auto_mode_returns_data(self, es_engine):
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "auto",
|
2026-06-08 04:08:23 -07:00
|
|
|
"table_column_names": ["country"],
|
|
|
|
|
"field_map": {"country_tks": "country"},
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
},
|
|
|
|
|
}
|
2026-06-08 04:08:23 -07:00
|
|
|
chunks = [{"country_raw": "Brazil", "country_tks": "x"}]
|
|
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
|
|
|
|
assert out == {"country": ["Brazil"]}
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
|
fix(metadata): discover ES fields after sparse table chunks (#16949)
### What problem does this PR solve?
When a table dataset's `field_map` is missing or stale,
`aggregate_table_doc_metadata` falls back to probing chunk dictionaries
for each column's Elasticsearch field key. It currently performs that
probe only once, against the first dictionary chunk, and caches `(None,
"none")` if the field is absent there.
Sparse table rows commonly omit empty columns. If the first row has no
`notes` field but a later row contains `notes_raw`, the cached miss
causes every later row to be skipped and the document-level `notes`
metadata is silently lost. The result depends only on row order:
```python
chunks = [{}, {"notes_raw": "Handle with care"}]
aggregate_table_doc_metadata(chunks, task) # before: {}
aggregate_table_doc_metadata(list(reversed(chunks)), task)
# before: {"notes": ["Handle with care"]}
```
This was also identified in CodeRabbit's review of the merged
table-metadata implementation in #15780, but remained unfixed after that
PR merged:
https://github.com/infiniflow/ragflow/pull/15780#pullrequestreview-4448490676
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
### Fix
When the initial lookup found no key for a column, retry the existing
`_resolve_es_chunk_field_key` against the current chunk. Cache the first
successful resolution so subsequent rows retain the existing fast path.
Field-map-backed columns and columns found in the first chunk are
unchanged.
### Testing
- Added `test_aggregate_auto_mode_probes_later_sparse_chunks` with an
empty first row and a populated second row.
- Confirmed red→green: before the fix the assertion received `{}`; after
the fix it receives `{"notes": ["Handle with care"]}`.
- Full existing `test_table_metadata_aggregation.py`: **15 passed**.
- `ruff check` and `ruff format --check`: clean.
- `compileall` for both changed files: clean.
The local test environment did not contain the repository's full service
dependency set and had a corrupt pre-existing NLTK `wordnet.zip`. The
test module does not use those services or corpora, so the run stubbed
only `common.settings` engine flags, `json_repair`, and the global
conftest's NLTK resource lookup; the production module and aggregation
tests themselves ran unchanged.
### Duplicate-work check
Checked all currently open PRs (including changed file paths) and found
none touching `rag/utils/table_es_metadata.py` or its aggregation test.
The earlier #15780 review is historical context, not active competing
work.
### Disclosure
AI-assisted (Codex): the candidate came from an AI-assisted review
queue. I independently reproduced the order-dependent data loss against
the real module, checked the historical review and all open PR file
paths, and ran the regression plus full existing test file before
submitting.
Signed-off-by: chuenchen309 <48723787+chuenchen309@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 13:41:46 +08:00
|
|
|
def test_aggregate_auto_mode_probes_later_sparse_chunks(self, es_engine):
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "auto",
|
|
|
|
|
"table_column_names": ["notes"],
|
|
|
|
|
"table_column_roles": {"notes": "both"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
chunks = [{}, {"notes_raw": "Handle with care"}]
|
|
|
|
|
|
|
|
|
|
assert aggregate_table_doc_metadata(chunks, task) == {"notes": ["Handle with care"]}
|
|
|
|
|
|
2026-06-08 04:08:23 -07:00
|
|
|
def test_aggregate_auto_mode_all_columns_both(self, es_engine):
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
2026-06-08 04:08:23 -07:00
|
|
|
"table_column_mode": "auto",
|
|
|
|
|
"table_column_names": ["country", "category"],
|
|
|
|
|
"field_map": {"country_tks": "country", "category_tks": "category"},
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
},
|
|
|
|
|
}
|
2026-06-08 04:08:23 -07:00
|
|
|
chunks = [
|
|
|
|
|
{"country_raw": "Brazil", "country_tks": "x", "category_raw": "Economy", "category_tks": "y"},
|
|
|
|
|
{"country_raw": "Turkey", "country_tks": "x", "category_raw": "Disaster", "category_tks": "y"},
|
|
|
|
|
]
|
|
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
|
|
|
|
assert out["country"] == ["Brazil", "Turkey"]
|
|
|
|
|
assert out["category"] == ["Economy", "Disaster"]
|
|
|
|
|
|
|
|
|
|
def test_aggregate_no_mode_defaults_to_auto(self, es_engine):
|
|
|
|
|
"""When table_column_mode is missing, it defaults to 'auto'."""
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_names": ["country"],
|
|
|
|
|
"field_map": {"country_tks": "country"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
chunks = [{"country_raw": "Brazil", "country_tks": "x"}]
|
|
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
|
|
|
|
assert out == {"country": ["Brazil"]}
|
|
|
|
|
|
|
|
|
|
def test_aggregate_no_mode_no_columns_returns_empty(self, es_engine):
|
|
|
|
|
"""No mode and no column names/roles -> empty (nothing to aggregate)."""
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {},
|
|
|
|
|
}
|
|
|
|
|
assert aggregate_table_doc_metadata([{}], task) == {}
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
|
|
|
|
|
def test_aggregate_no_metadata_columns(self, es_engine):
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "manual",
|
|
|
|
|
"table_column_roles": {"country": "indexing"},
|
|
|
|
|
"table_column_names": ["country"],
|
|
|
|
|
},
|
|
|
|
|
}
|
2026-06-08 04:08:23 -07:00
|
|
|
assert aggregate_table_doc_metadata([{"country_tks": "x"}], task) == {}
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
|
|
|
|
|
def test_aggregate_prefers_raw_over_tks(self, es_engine):
|
|
|
|
|
task = _table_task()
|
|
|
|
|
task["kb_parser_config"]["table_column_roles"] = {"country": "metadata"}
|
|
|
|
|
task["kb_parser_config"]["table_column_names"] = ["country"]
|
|
|
|
|
chunks = [{"country_raw": "Brazil", "country_tks": ["brazil"]}]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out == {"country": ["Brazil"]}
|
|
|
|
|
|
|
|
|
|
def test_aggregate_tks_fallback(self, es_engine):
|
|
|
|
|
task = _table_task()
|
|
|
|
|
task["kb_parser_config"]["table_column_roles"] = {"country": "metadata"}
|
|
|
|
|
task["kb_parser_config"]["table_column_names"] = ["country"]
|
|
|
|
|
chunks = [{"country_tks": ["brazil"]}]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out == {"country": ["brazil"]}
|
|
|
|
|
|
|
|
|
|
def test_aggregate_partial_roles_defaults_to_both(self, es_engine):
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "manual",
|
|
|
|
|
"table_column_roles": {"country": "indexing"},
|
|
|
|
|
"table_column_names": ["country", "city"],
|
|
|
|
|
"field_map": {"city_tks": "city"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
chunks = [{"city_raw": "SP", "city_tks": "t", "country_tks": "x"}]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out == {"city": ["SP"]}
|
|
|
|
|
assert "country" not in out
|
|
|
|
|
|
|
|
|
|
def test_aggregate_empty_roles_all_columns_both(self, es_engine):
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "manual",
|
|
|
|
|
"table_column_roles": {},
|
|
|
|
|
"table_column_names": ["country", "city"],
|
|
|
|
|
"field_map": {"country_tks": "country", "city_tks": "city"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
chunks = [
|
|
|
|
|
{"country_raw": "BR", "city_raw": "SP", "country_tks": "x", "city_tks": "y"},
|
|
|
|
|
]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert "country" in out and "city" in out
|
|
|
|
|
|
|
|
|
|
def test_aggregate_deduplicates_values(self, es_engine):
|
|
|
|
|
task = _table_task()
|
|
|
|
|
task["kb_parser_config"]["table_column_roles"] = {"country": "metadata"}
|
|
|
|
|
task["kb_parser_config"]["table_column_names"] = ["country"]
|
|
|
|
|
chunks = [
|
|
|
|
|
{"country_raw": "US", "country_tks": "x"},
|
|
|
|
|
{"country_raw": "UK", "country_tks": "y"},
|
|
|
|
|
{"country_raw": "US", "country_tks": "x"},
|
|
|
|
|
]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out["country"] == ["US", "UK"]
|
|
|
|
|
|
|
|
|
|
def test_aggregate_kb_reload_field_map(self, es_engine, monkeypatch):
|
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
|
|
|
|
|
|
class MockKBS:
|
|
|
|
|
@staticmethod
|
|
|
|
|
def get_by_id(kid):
|
|
|
|
|
kb = MagicMock()
|
|
|
|
|
kb.parser_config = {"field_map": {"country_tks": "country"}}
|
|
|
|
|
return True, kb
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(
|
|
|
|
|
"rag.utils.table_es_metadata._knowledgebase_service_cls",
|
|
|
|
|
lambda: MockKBS,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "manual",
|
|
|
|
|
"table_column_roles": {"country": "metadata"},
|
|
|
|
|
"table_column_names": ["country"],
|
|
|
|
|
},
|
|
|
|
|
"kb_id": "kb-1",
|
|
|
|
|
}
|
|
|
|
|
chunks = [{"country_raw": "X", "country_tks": "t"}]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out == {"country": ["X"]}
|
|
|
|
|
|
|
|
|
|
def test_merge_infinity_chunk_data(self, infinity_engine):
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "table",
|
|
|
|
|
"parser_config": {},
|
|
|
|
|
"kb_parser_config": {
|
|
|
|
|
"table_column_mode": "manual",
|
|
|
|
|
"table_column_roles": {"country": "both"},
|
|
|
|
|
"table_column_names": ["country"],
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
chunks = [
|
|
|
|
|
{"chunk_data": {"country": "US"}},
|
|
|
|
|
{"chunk_data": {"country": "UK"}},
|
|
|
|
|
]
|
2026-06-08 04:08:23 -07:00
|
|
|
out = aggregate_table_doc_metadata(chunks, task)
|
Feature/table parser column roles (#13710)
### What problem does this PR solve?
The table file parser (CSV/Excel) currently treats all columns
identically — every column is both vectorized (embedded in chunk text)
and stored as filterable metadata. There's no way for users to control
which columns should be searchable by semantic meaning versus which
should only be filterable attributes.
For example, when ingesting a news articles CSV with columns like title,
content, country, category, source, etc., the embedding includes
metadata fields like country: Brazil and source: Reuters in the chunk
text, which dilutes the semantic quality of the embedding without adding
retrieval value.
The RDBMS connector (MySQL/PostgreSQL) already supports content_columns
/ metadata_columns, but this capability was missing for file-based table
ingestion.
This PR adds column-level control (vectorize / metadata / both) for the
table file parser, following RAGFlow's existing patterns.
Backward compatible: Datasets without table_column_roles or with
table_column_mode: auto behave exactly as before (all columns = both).
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
2026-05-11 07:06:04 +05:00
|
|
|
assert out == {"country": ["US", "UK"]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMergeTableParserConfigFromKbExtra:
|
|
|
|
|
"""Merge tests also covered in helpers file; keep one explicit case for aggregation module."""
|
|
|
|
|
|
|
|
|
|
def test_merge_preserves_parser_config_when_parser_not_table(self):
|
|
|
|
|
task = {
|
|
|
|
|
"parser_id": "naive",
|
|
|
|
|
"parser_config": {"a": 1},
|
|
|
|
|
"kb_parser_config": {"table_column_mode": "manual"},
|
|
|
|
|
}
|
|
|
|
|
assert merge_table_parser_config_from_kb(task) == {"a": 1}
|