Token/ngram/text indexes take a column named `lower(s)` for the expression
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 22/100
Hướng nghiên cứu
Start with getKeyIndex and traverseTreeEquals in src/Storages/MergeTree/MergeTreeIndexBloomFilterText.cpp, then hasIndexForColumn and traverseFunctionNode in MergeTreeIndexConditionText.h and .cpp. Compare them with the structural check findIndexPosition and ExpressionMatcher in MergeTreeIndexBloomFilter.cpp, which #130814 added. Done means the reproducer's three tables return 1 for each query, and the cases are added to 05620_bloom_filter_index_map_keys_column_name.sql.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Describe what's wrong
- Queries on
mapKeys(m),lower(s)and similar expressions silently lose rows withtokenbf_v1,ngrambf_v1ortextindexes. - Trigger: a stored column literally named
mapKeys(m)orlower(s)carries one of these indexes. count()returns 0 instead of 1;use_skip_indexes = 0correctly returns 1.bloom_filterwas fixed by #130814 but these three index types still have the bug.
Root cause: MergeTreeConditionBloomFilterText::getKeyIndex and MergeTreeIndexConditionText::hasIndexForColumn resolve the index key by matching the result name only, so a stored column named like the expression's canonical name is mistaken for that expression. #130814 fixed only MergeTreeIndexConditionBloomFilter with a structural check and left these peers unchanged.
Analysis details (evidence, affected locations, impact)
Why we believe this is a bug: MergeTreeConditionBloomFilterText::traverseTreeEquals resolves the key with getKeyIndex(column_name), getKeyIndex("mapKeys(<m>)") and getKeyIndex("lower(<s>)") (MergeTreeIndexBloomFilterText.cpp:628-630, :652, :721); getKeyIndex (:325) is a plain search of the header names. MergeTreeIndexConditionText::traverseFunctionNode does the same via hasIndexForColumn = header.has(name) (MergeTreeIndexConditionText.h:292, .cpp:1306-1309). #130814 (where this was found; not confirmed as the cause)'s structural check (findIndexPosition -> ExpressionMatcher::isSame, findMapIndexPosition, MergeTreeIndexBloomFilter.cpp:455-510) exists only in the bloom_filter condition.
Affected locations:
src/Storages/MergeTree/MergeTreeIndexBloomFilterText.cpp:628— key,mapKeys(<col>),mapValues(<col>)resolved bygetKeyIndexname searchsrc/Storages/MergeTree/MergeTreeIndexBloomFilterText.cpp:652—arrayElement(m, k)takes any header column namedmapKeys(m)as the keys indexsrc/Storages/MergeTree/MergeTreeIndexBloomFilterText.cpp:721—hasTokenCaseInsensitivetakes any header column namedlower(<col>)src/Storages/MergeTree/MergeTreeIndexConditionText.h:292—hasIndexForColumnisheader.has(column_name)src/Storages/MergeTree/MergeTreeIndexConditionText.cpp:1307— text index key /mapKeys/mapValuesresolved by namesrc/Storages/MergeTree/MergeTreeIndexBloomFilter.cpp:459— the PR's fixed counterpart: name hit accepted only ifExpressionMatcher::isSame
Impact: Silent row loss for predicates on the expression whenever the table also stores a column with the expression's canonical name and indexes it with tokenbf_v1, ngrambf_v1 or text. For text, the direct-read rewrite (__text_index_il_hasToken_*) answers hasToken(lower(s), 'abc') from the stored column's index. The same schema is correct under bloom_filter since #130814, so the result now depends on the index type.
Does it reproduce on most recent release?
Confirmed on master (dc415c941c4f); not checked on a release.
How to reproduce
Needs a table with both a Map/String column and a separate column literally named mapKeys(m) or lower(s), indexed with tokenbf_v1, ngrambf_v1 or text.
Reproducer
-- Test: a tokenbf_v1, ngrambf_v1 or text index on a column literally named `mapKeys(m)` or `lower(s)` is not used for that expression.
DROP TABLE IF EXISTS t_tok;
DROP TABLE IF EXISTS t_ngram;
DROP TABLE IF EXISTS t_text;
CREATE TABLE t_tok
(
m Map(String, String),
s String,
`mapKeys(m)` String,
`lower(s)` String,
INDEX ik `mapKeys(m)` TYPE tokenbf_v1(256, 2, 0),
INDEX il `lower(s)` TYPE tokenbf_v1(256, 2, 0)
)
ENGINE = MergeTree ORDER BY tuple();
INSERT INTO t_tok VALUES (map('k', 'v'), 'ABC', 'x', 'x');
SELECT count() FROM t_tok WHERE m['k'] = 'v';
SELECT count() FROM t_tok WHERE lower(s) = 'abc';
SELECT count() FROM t_tok WHERE hasTokenCaseInsensitive(s, 'abc');
CREATE TABLE t_ngram
(
m Map(String, String),
s String,
`mapKeys(m)` String,
`lower(s)` String,
INDEX ik `mapKeys(m)` TYPE ngrambf_v1(1, 256, 2, 0),
INDEX il `lower(s)` TYPE ngrambf_v1(2, 256, 2, 0)
)
ENGINE = MergeTree ORDER BY tuple();
INSERT INTO t_ngram VALUES (map('k', 'v'), 'ABC', 'x', 'x');
SELECT count() FROM t_ngram WHERE m['k'] = 'v';
SELECT count() FROM t_ngram WHERE lower(s) LIKE '%ab%';
CREATE TABLE t_text
(
m Map(String, String),
s String,
`mapKeys(m)` Array(String),
`lower(s)` String,
INDEX ik `mapKeys(m)` TYPE text(tokenizer = 'array'),
INDEX il `lower(s)` TYPE text(tokenizer = 'splitByNonAlpha')
)
ENGINE = MergeTree ORDER BY tuple();
INSERT INTO t_text VALUES (map('k', 'v'), 'ABC', ['x'], 'x');
SELECT count() FROM t_text WHERE m['k'] = 'v';
SELECT count() FROM t_text WHERE has(mapKeys(m), 'k') SETTINGS optimize_functions_to_subcolumns = 0;
SELECT count() FROM t_text WHERE hasToken(lower(s), 'abc');
DROP TABLE t_tok;
DROP TABLE t_ngram;
DROP TABLE t_text;
Verified: this block reproduces on current master (dc415c941c4f) when pasted as is.
Expected behavior
Queries on m['k'], lower(s), hasToken, hasTokenCaseInsensitive and has(mapKeys(m), ...) should match rows regardless of whether a column happens to be named after the expression.
Expected output of the reproducer above:
1
1
1
1
1
1
1
1
Error message and/or stacktrace
The index wrongly binds to the stored column with the matching name and prunes the granule, returning 0 rows where 1 is expected.
Actual output of the reproducer above on master (dc415c941c4f):
0
0
0
0
0
0
0
0
Suggested fix
Port #130814 to the peers: pass index.expression->getActionsDAG().getOutputs() to MergeTreeConditionBloomFilterText and MergeTreeIndexConditionText, accept a name hit only when the index node is structurally the queried expression (reuse ExpressionMatcher, moved out of the anonymous namespace of MergeTreeIndexBloomFilter.cpp), and accept mapKeys(<m>)/mapValues(<m>)/lower(<s>) only when the index node is that function over the same input, like findMapIndexPosition. Trade-off: the shared matcher has to live in a header included by three index files. Add the cases to 05620_bloom_filter_index_map_keys_column_name.sql rather than a new file.
Additional context
Open risks:
KeyCondition-basedminmax, primary key andPARTITION BYshare the root cause; already listed in #123151 (groeneai comment), not re-tested here.setindex (MergeTreeIndexConditionSet) matching was not tested.
Found during automated review of PR #130814; the bug predates that PR (it reproduces on the master build just before it merged), so the introducing change is not identified yet. Severity P2 · Finding h_pr130814_001
- Ngôn ngữ chính
- C++
- Star
- 50.9k
- Fork
- 9.3k
- Merge trung bình
- 14 giờ 39 phút
- Pull request đã merge (30 ngày)
- 545
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của ClickHouse/ClickHouse
-
comp-cli
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
ClickHouse/ClickHouse#131191 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Unreadable /etc/ld.so.preload makes non-root ClickHouse refuse to startCó thể đã có người làm @lazerg đã nhận 2 ngày trước. Đang mởai_p2 comp-logging
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
ClickHouse/ClickHouse#130685 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
ai_p3 comp-foreign-db
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
ClickHouse/ClickHouse#130426 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
ai_p1 comp-aggregate-functions
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
ClickHouse/ClickHouse#130273 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Mutations on bucketed `Map` read all buckets in the per-part affected checkCó thể đã có người làm @Rushikesh1911 đã nhận 4 ngày trước. Đang mởai_p2 comp-mutations
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
ClickHouse/ClickHouse#130085 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của ClickHouse/ClickHouse
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
mw00/project-maya#983 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
StarRocks/starrocks#83246 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày