github-actions[bot] commented on code in PR #67650:
URL: https://github.com/apache/doris/pull/67650#discussion_r3985684766
##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -126,6 +128,12 @@ Status LanceTableReader::init(TableReadOptions&& options) {
TUnit::UNIT,
LANCE_READER_PROFILE, 1);
_execution_bytes_read = ADD_CHILD_COUNTER_WITH_LEVEL(
_scanner_profile, "LanceExecutionIOBytesRead", TUnit::BYTES,
LANCE_READER_PROFILE, 1);
+ _data_cache_bytes_read_from_cache =
+ ADD_CHILD_COUNTER_WITH_LEVEL(_scanner_profile,
"LanceDataCacheBytesReadFromCache",
+ TUnit::BYTES, LANCE_READER_PROFILE,
1);
+ _data_cache_bytes_read_from_remote =
+ ADD_CHILD_COUNTER_WITH_LEVEL(_scanner_profile,
"LanceDataCacheBytesReadFromRemote",
Review Comment:
[P2] Do not expose this logical miss counter as remote I/O bytes. The C ABI
says `bytes_read_from_remote` counts requested bytes returned after a miss and
excludes block-aligned amplification; `cached_ranges()` can fetch a full 1 MiB
block for a tiny range while incrementing only the tiny range. The same field
is also incremented for local origins. This profile value therefore understates
physical reads and misattributes local I/O as remote. Please name it as logical
origin/miss bytes, and separately publish actual aligned origin bytes/requests
with the real source attribution.
##########
fe/fe-core/src/main/java/org/apache/doris/datasource/lance/source/LanceScalarIndexPlanner.java:
##########
@@ -0,0 +1,139 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+package org.apache.doris.datasource.lance.source;
+
+import org.apache.doris.analysis.CompoundPredicate;
+import org.apache.doris.analysis.Expr;
+import org.apache.doris.analysis.SlotRef;
+import org.apache.doris.datasource.lance.LanceFragmentInfo;
+import org.apache.doris.datasource.lance.LanceIndexSegmentInfo;
+import org.apache.doris.datasource.lance.LanceTableMetadata;
+
+import org.lance.index.IndexType;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+/** Assigns one BTree/Bitmap/LabelList segment and a disjoint fragment domain
to each ordinary scan task. */
+final class LanceScalarIndexPlanner {
+ static final class Plan {
+ final String indexName;
+ final IndexSegmentSplitPlan splits;
+ private final long coveredRows;
+
+ Plan(String indexName, IndexSegmentSplitPlan splits, long coveredRows)
{
+ this.indexName = indexName;
+ this.splits = splits;
+ this.coveredRows = coveredRows;
+ }
+ }
+
+ static Plan plan(LanceTableMetadata metadata, List<Expr> pushedConjuncts,
+ Map<Long, LanceFragmentInfo> visibleFragments) {
+ if (metadata.getVersion() <= 0) {
+ return null;
+ }
+ Set<Integer> filterFields = collectFilterFields(metadata,
pushedConjuncts);
+ if (filterFields.isEmpty()) {
+ return null;
+ }
+ // Group all segments of each logical index before checking coverage.
Name order
+ // provides a stable winner when multiple indices cover the same
number of rows.
+ Map<String, List<LanceIndexSegmentInfo>> indices =
metadata.getIndexSegments().stream()
+
.collect(Collectors.groupingBy(LanceIndexSegmentInfo::getIndexName,
+ TreeMap::new, Collectors.toList()));
+ Plan selected = null;
+ for (List<LanceIndexSegmentInfo> segments : indices.values()) {
+ // PR #79 supports one top-level key in BTree/Bitmap/LabelList
indices. Lance
+ // performs the final typed driver selection and falls back within
the same domain.
+ LanceIndexSegmentInfo index = segments.get(0);
+ if ((index.getIndexType() != IndexType.BTREE &&
index.getIndexType() != IndexType.BITMAP
+ && index.getIndexType() != IndexType.LABEL_LIST)
+ || index.getFieldIds().size() != 1 ||
!filterFields.contains(index.getFieldIds().get(0))) {
Review Comment:
[P1] Only create a segment split when the pushed filter can actually drive
this index. This check accepts any pushed expression that mentions the field,
but Doris pushes predicates such as `!=`, `NOT IN`, and `IS NOT NULL` that
Lance v11 represents as `Not(Query)`; PR #79's `driver()` only descends
`Query`/`And`. It then reports `no_driver` after disabling ordinary scalar
indexes and full-scans the segment's entire fragment domain. With the common
single segment covering many fragments, this turns the previous
fragment-parallel scan into one unsplittable full scan on one BE. Please align
FE eligibility with the typed Lance planner, or retain fragment/global-index
planning whenever a driver is not guaranteed.
##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -1101,12 +1173,43 @@ void LanceTableReader::_close_dataset() {
_fts_query_context = nullptr;
}
if (_dataset != nullptr) {
+ _collect_data_cache_statistics();
Review Comment:
[P2] Refresh these counters at scan batch boundaries. This is the only call
to `_collect_data_cache_statistics()`, and `_close_dataset()` normally runs
only when the reader closes (the same dataset can also span several splits).
Every successful batch, intermediate split, cancellation, and
scanner/conversion error therefore leaves the new cache counters at zero until
the query is already tearing down, contrary to the scanner-v2 requirement that
child statistics be visible for in-progress scans. Please sample the cumulative
dataset snapshot on each `get_block()` exit, including EOF/error paths, while
retaining the close-time refresh.
--
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]