eldenmoon commented on PR #69761:
URL: https://github.com/apache/doris/pull/69761#issuecomment-6598520201
## Review of `c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455`
**Recommendation: request changes.** Two merge-blocking issues remain: one
newly identified BUILD INDEX integration defect, and one native-compaction
consistency limitation already acknowledged in the PR description. The latter
is explicitly identified as known, not presented as a new discovery.
This is a static review of the pinned head against merge base
`339e087b11f760e9e45ce33d94862b4b63f1d9ee`. All 60 changed files were covered,
followed by an independent counterargument pass on both findings. **The
reproduction sequences and results below are source-derived; I did not execute
SQL, builds, tests or benchmarks.**
### F-01 — Blocker: BUILD of an ordinary string index can terminate the BE
when values and numeric indexes share an SNII container
A supported ordinary-index operation can force the generic SNII
`IndexBuilder` to rebuild an existing VARIANT values index, although that
builder cannot handle VARIANT.
**Concrete trigger:** local/shared-nothing mode with the default
`enable_light_index_change=true`. Create the values and numeric indexes, write
an old rowset, and only then add the string index:
```sql
SET default_variant_enable_nested_group=false;
CREATE TABLE vvi_build (
id INT, v VARIANT, s STRING, n INT,
INDEX values_idx(v) USING INVERTED
PROPERTIES("variant_index_scope"="values", "parser"="english"),
INDEX n_idx(n) USING INVERTED
) DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1
PROPERTIES(
"replication_num"="1",
"inverted_index_storage_format"="SNII",
"disable_auto_compaction"="true"
);
INSERT INTO vvi_build VALUES
(1, parse_to_variant('{"x":"hello"}'), 'text', 1);
ALTER TABLE vvi_build ADD INDEX s_idx(s) USING INVERTED
PROPERTIES("parser"="english");
-- Wait for the light ADD metadata job to complete.
BUILD INDEX s_idx ON vvi_build;
```
The ordering is essential: the historical rowset must lack `s_idx`,
otherwise BUILD can skip it as already indexed. No ADD/BUILD of the values
index itself is requested, so the existing FE restriction does not prevent this
sequence.
The reachable failure chain is:
1. The numeric SNII writer persists a BKD blob in the source container.
2. `plan_snii_index_rewrite` cannot inherit unchanged logical indexes from a
container containing a blob. It schedules **all resident logical indexes** for
rebuild, including `values_idx`, not just the requested `s_idx`.
3. `_build_snii_indexes_for_segment` checks generic support for VARIANT with
`DORIS_CHECK` **before** its local `try`.
4. Generic index writing rejects VARIANT. Debug builds log FATAL; in release
the fatal exception escapes the actual BUILD callback/thread-pool/pthread-entry
chain, which has no enclosing catch-and-convert boundary. The consequence can
therefore be BE process termination, not merely a failed index job.
Primary evidence:
- [Historical rowset
selection](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/tablet/tablet.cpp#L1376-L1404)
and [FE BUILD restriction on the requested
column](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java#L2595-L2606).
- [BKD blob
registration](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/index/inverted/snii/snii_bkd_index_writer.cpp#L242-L244)
and [container-wide rewrite
planning](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/task/index_builder.cpp#L78-L140).
- [VARIANT support check before the local
try](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/task/index_builder.cpp#L929-L944)
and [generic unsupported-type
check](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/index/index_writer.cpp#L34-L35).
- [Actual BUILD
callback](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/agent/task_worker_pool.cpp#L824-L835)
and [pthread
entry](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/util/thread.cpp#L430-L463).
**Suggested fix:** make the container rebuild plan account for every
resident logical index. Either rebuild a values index through its specialized
writer using a complete root assembled from stored values, or provide a
blob-capable container rewrite that safely preserves that unchanged values
index. Add an exception-to-Status boundary as well; catching the exception
alone still leaves a supported BUILD operation unable to complete.
**Required regression:** values + numeric/BKD indexes, historical insert,
ADD/BUILD ordinary STRING index, then verify both the new STRING postings and
the existing values postings. This is a newly exposed integration defect on
values-enabled tables; it is not a claim that existing ordinary tables without
values indexes regress.
### F-02 — Major, known PR-declared limitation: native compaction can make
indexed and index-disabled MATCH return different row sets
The PR already acknowledges boolean/numeric token drift. I still consider it
merge-blocking because the values index is consumed as an **exact predicate
result**, while its postings can cease to describe the final stored value.
A concrete case uses ORDINARY storage, a materialized dynamic path `n`, and
two separately written rowsets:
```text
id=1: {"n":true}
id=2: {"n":1}
```
The source physical types are BOOLEAN and BIGINT. With native inverted-index
compaction and vertical VARIANT subcolumn expansion, data compaction selects
BIGINT and casts `true` to numeric `1`. Native values-index merging only remaps
source postings, so id 1 retains token `true` and does not gain token `1`.
**Source-derived results after that compaction:**
| Predicate | Index enabled | Index disabled |
|---|---|---|
| `WHERE v MATCH_ANY 'true'` | id 1 | no rows |
| `WHERE v MATCH_ANY '1'` | id 2 | id 1 and id 2 |
These are respectively a false positive and a false negative relative to the
final reconstructed values.
For a regression, explicitly set ORDINARY mode, disable NestedGroup, use
`default_variant_max_subcolumns_count=100` so the sole `n` path materializes,
disable automatic compaction until both rowsets exist, and disable
query/condition/index caches. Run a real full compaction with:
```text
enable_vertical_compaction=true
enable_ordered_data_compaction=false
inverted_index_compaction_enable=true
enable_vertical_compact_variant_subcolumns=true
```
The existing regression suite provides [the full-compaction
helper](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/regression-test/suites/variant_p0/v2/with_index/test_variant_values_index_compaction.groovy#L100).
Both source logical indexes must be healthy and must not have
`skip_index_compaction` set. Compare identical WHERE queries with:
```sql
SET enable_match_without_inverted_index=true;
SET enable_inverted_index_query=true;
SELECT id FROM vvi_bool_native WHERE v MATCH_ANY 'true' ORDER BY id;
SELECT id FROM vvi_bool_native WHERE v MATCH_ANY '1' ORDER BY id;
SET enable_inverted_index_query=false;
SELECT id FROM vvi_bool_native WHERE v MATCH_ANY 'true' ORDER BY id;
SELECT id FROM vvi_bool_native WHERE v MATCH_ANY '1' ORDER BY id;
```
A plain MATCH projection is **not** a reliable scalar oracle: it can itself
use an index-backed scan virtual column. Explicitly disable index execution for
any projection used as a scalar control.
The mechanism is established by:
- [Values-root native
admission](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/compaction/compaction.cpp#L1679-L1683)
and [the planner selecting rebuild only when the pair is absent from the
native
set](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/exec/common/variant_util.cpp#L1175-L1183).
- [Physical leaf conversion to the output
type](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/segment/segment_iterator.cpp#L3105-L3112)
and [native indexes being excluded from fresh
writing](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/segment/vertical_segment_writer.cpp#L200-L208).
- [Exact MATCH bitmap
consumption](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/segment/segment_iterator.cpp#L1539-L1545)
and [filter
removal](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/storage/segment/segment_iterator.cpp#L1643-L1647).
There is no scalar residual to correct stale positives; a positive-only
recheck could not recover rows already removed by false-negative postings
anyway.
**Suggested fix:** require a per-root guarantee that source-to-output
conversion and visibility changes preserve canonical leaf text before retaining
native merge. Otherwise use the existing whole-root rebuild path. A
conservative temporary fallback is to exclude values roots from native merging,
with the performance tradeoff made explicit. A finer veto can retain native
merging for proven-safe roots. The corrected native set must consistently drive
schema expansion, writer exclusion and posting merge; marking a root for
rebuild while leaving its pair native would still suppress the necessary writer.
This does **not** establish newly lost committed raw values: underlying
VARIANT type promotion is pre-existing. The defect is silent
query-plan-dependent filtering against the final values. The separately
documented empty-array/sparse visibility limitation also needs to be covered by
the eventual semantic-stability guarantee; it is not being presented as another
new finding here.
**Coverage gap:** [the mixed native/rebuild BE
test](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/test/storage/variant/index_storage_variant_compaction_read_test.cpp#L342-L383)
explicitly forces its bool/int root to rebuild. [The SQL compaction
suite](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/regression-test/suites/variant_p0/v2/with_index/test_variant_values_index_compaction.groovy#L49-L52)
explicitly avoids bool/numeric mixing. Neither tests this native case. Add the
two-rowset input without a skip flag and assert index-enabled/index-disabled
parity for both tokens before and after compaction.
### Additional performance, maintainability and compatibility notes
- The shared final-value assembler and leaf visitor are useful boundaries to
retain. The earlier repeated-compaction-planning concern is resolved:
eligibility is computed once after filtering and before expansion.
- The [new scalar MATCH
path](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/exprs/function/match.cpp#L127-L143)
collects and sorts all row tokens, approximately `O(T log T + Q log T)` work
with `O(T)` token storage. Consider reusing [query-term membership and
early-exit
behavior](https://github.com/apache/doris/blob/c7fec9b1ff79cd0fbc4296189f0ccedd9ee98455/be/src/exprs/function/match.cpp#L672-L765)
from existing MATCH implementations. This is an optimization opportunity, not
a measured slowdown claim.
- The 4096-row writer batch bounds rows rather than bytes. Add
feature-specific measurements for wide documents/high token counts, peak
memory, ingest, scalar MATCH and native-versus-rebuild compaction cost.
- Current-version legacy root/path behavior and the historical CAST/alias
issue were rechecked; no additional defect was confirmed there. Reusing the
existing property map and wire fields does not establish mixed-version or
downgrade safety. Enable the feature after the relevant FE/BE nodes are
upgraded unless explicit mixed-version support is established.
- Existing tests inspect real data, schema, postings and MoW deletion
behavior. The two decisive missing integration gates are F-01's historical
BUILD with a resident blob and F-02's native type-promotion parity case.
Please address F-01/F-02 and add their targeted regressions before merging.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]