github-actions[bot] commented on code in PR #67005:
URL: https://github.com/apache/doris/pull/67005#discussion_r3859652154


##########
be/src/format_v2/table/lance_reader.h:
##########
@@ -34,6 +34,7 @@
 
 struct LanceBatch;
 struct LanceDataset;
+struct LanceScanStatistics;

Review Comment:
   [P1] Make this declaration match lance-c's public type
   
   The patched v0.1.7 header defines this as an anonymous typedef, `typedef 
struct { ... } LanceScanStatistics;`, rather than a tagged `struct 
LanceScanStatistics`. Both `lance_reader.cpp` and the changed test include this 
header before `<lance/lance.h>`, so this declaration introduces a different C++ 
type and the later typedef conflicts before either translation unit can 
compile. Please either tag the public C struct consistently or include the 
lance header here and remove this incompatible forward declaration.



##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -691,6 +758,10 @@ Status LanceTableReader::_open_scanner(const 
TFileRangeDesc& range) {
         return _lance_error("create Lance scanner");
     }
     std::unique_ptr<LanceScanner, LanceScannerDeleter> scanner_guard(scanner);
+    if (lance_scanner_set_statistics_callback(scanner, 
&LanceTableReader::_collect_scan_statistics,

Review Comment:
   [P2] Preserve statistics for successful early-stop scans
   
   This callback runs only when Lance observes full EOF; the bundled API 
explicitly does not invoke it on early scanner release. A successful Doris 
outer LIMIT can consume a non-final batch, call `stop_scanners()`, set 
`should_stop`, and close this scanner without another EOF-observing 
`lance_scanner_next()`. Because this callback is the only updater for all the 
new execution counters, that successful query reports zero (or only prior-split 
totals) despite having performed I/O. Please expose/flush a partial summary 
before close, with an incompleteness marker if needed, and cover a 
LIMIT/early-close path with value assertions.



##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -303,21 +304,56 @@ Status LanceTableReader::init(TableReadOptions&& options) 
{
 
     _ctz = _runtime_state->timezone_obj();
     const auto& lance_scan_params = _scan_params->lance_scan_params;
+    _dataset_open_time = ADD_TIMER(_scanner_profile, "LanceDatasetOpenTime");

Review Comment:
   [P2] Attach these metrics to the V2 profile hierarchy
   
   All of the new Lance timers/counters use the root-parent 
`ADD_TIMER`/`ADD_COUNTER` forms even though `TableReader::init()` has already 
created the required `FileScannerV2 -> TableReader -> FileReader -> IO` tree. 
As a result, dataset/scanner/decode work is displayed beside `FileScannerV2`, 
and `LanceExecutionIO*` is outside `IO`, so the profile cannot attribute the 
new detail to its owning layer. Please create a Lance child under 
`TableReader`, put the table/format metrics beneath it, place raw execution I/O 
under `IO` (or an IO child), and assert parent relationships rather than only 
flat counter presence.



##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -303,21 +304,56 @@ Status LanceTableReader::init(TableReadOptions&& options) 
{
 
     _ctz = _runtime_state->timezone_obj();
     const auto& lance_scan_params = _scan_params->lance_scan_params;
+    _dataset_open_time = ADD_TIMER(_scanner_profile, "LanceDatasetOpenTime");
+    _scanner_configure_time = ADD_TIMER(_scanner_profile, 
"LanceScannerConfigureTime");
+    _scanner_read_time = ADD_TIMER(_scanner_profile, "LanceScannerReadTime");
+    _arrow_to_doris_block_time = ADD_TIMER(_scanner_profile, 
"LanceArrowToDorisBlockTime");
+    _execution_iops = ADD_COUNTER(_scanner_profile, "LanceExecutionIOOps", 
TUnit::UNIT);
+    _execution_requests = ADD_COUNTER(_scanner_profile, 
"LanceExecutionIORequests", TUnit::UNIT);
+    _execution_bytes_read =
+            ADD_COUNTER(_scanner_profile, "LanceExecutionIOBytesRead", 
TUnit::BYTES);
+    _index_partition_cache_miss_loads =
+            ADD_COUNTER(_scanner_profile, "LanceIndexPartitionCacheMissLoads", 
TUnit::UNIT);
+    _index_comparisons = ADD_COUNTER(_scanner_profile, 
"LanceIndexComparisons", TUnit::UNIT);
+    // These scan counts are emitted by Lance's FilteredRead execution node. 
For vector searches
+    // with an explicit fragment set, they normally describe the fragments, 
ranges, and rows read
+    // while applying the row-id prefilter. They are scan input counts, not 
ANN result counts.
+    _lance_count_metrics = {
+            {"fragments_scanned",
+             ADD_COUNTER(_scanner_profile, "LanceFragmentsScanned", 
TUnit::UNIT)},
+            {"ranges_scanned",
+             ADD_COUNTER(_scanner_profile, "LanceRowOffsetRangesScanned", 
TUnit::UNIT)},
+            {"rows_scanned", ADD_COUNTER(_scanner_profile, "LanceRowsScanned", 
TUnit::UNIT)},
+            {"partitions_ranked",
+             ADD_COUNTER(_scanner_profile, "LanceIVFPartitionsRanked", 
TUnit::UNIT)},
+            {"partitions_searched",
+             ADD_COUNTER(_scanner_profile, "LanceIVFPartitionsSearched", 
TUnit::UNIT)},
+            {"deltas_searched",
+             ADD_COUNTER(_scanner_profile, "LanceVectorIndexSegmentsSearched", 
TUnit::UNIT)},
+    };
+    _lance_time_metrics = {
+            // This is wait time reported by the same Lance scan execution 
node described above,
+            // rather than Doris scanner scheduling wait time.
+            {"task_wait_time", ADD_TIMER(_scanner_profile, 
"LanceTaskWaitTime")},
+            {"find_partitions_elapsed",
+             ADD_TIMER(_scanner_profile, "LanceIVFPartitionRankingTime")},
+    };
     _vector_search = _scan_params->__isset.lance_scan_params &&
                      lance_scan_params.__isset.external_search_request;
     if (_vector_search) {
         RETURN_IF_ERROR(_validate_external_search_request());
         const auto& request = lance_scan_params.external_search_request;
         const auto& vector = request.search_query.vector_search;
-        const bool use_index = !request.__isset.vector_search_options ||
-                               
!request.vector_search_options.__isset.use_index ||
-                               request.vector_search_options.use_index;
-        _scanner_profile->add_info_string("LanceFragmentTopK", 
std::to_string(vector.top_k));
-        _scanner_profile->add_info_string("LanceFragmentOffset", 
std::to_string(vector.offset));
-        _scanner_profile->add_info_string("LanceVectorDimension",
-                                          
std::to_string(vector.query_vector.dimension));
-        _scanner_profile->add_info_string("LanceUseIndex", use_index ? "true" 
: "false");
-        _fragment_count = ADD_COUNTER(_scanner_profile, "LanceFragmentCount", 
TUnit::UNIT);
+        _scanner_profile->add_info_string("LanceTopK", 
std::to_string(vector.top_k));

Review Comment:
   [P2] Keep the fragment scope in these profile labels
   
   The production FE does not send the logical values here: 
`createFragmentSearchRequest()` rewrites `(top_k, offset)` to `(top_k + offset, 
0)` before serialization. Thus a logical `top_k=5, offset=1` is now profiled as 
`LanceTopK=6`, `LanceOffset=0`, and `LanceTopKPlusOffset=6`. The unit test 
constructs the BE request directly and misses this path. Please retain explicit 
fragment/candidate naming (as the removed `LanceFragmentTopK` did), or also 
propagate the original logical values under unambiguous names.



##########
thirdparty/vars.sh:
##########
@@ -552,10 +552,10 @@ PUGIXML_SOURCE=pugixml-1.15
 PUGIXML_MD5SUM="3b894c29455eb33a40b165c6e2de5895"
 
 # lance-c
-LANCE_C_DOWNLOAD="https://github.com/lance-format/lance-c/archive/refs/tags/v0.1.6.tar.gz";
-LANCE_C_NAME="lance-c-v0.1.6.tar.gz"
-LANCE_C_SOURCE="lance-c-0.1.6"
-LANCE_C_MD5SUM="1599faa2532d9ce963db1188f7435a56"
+LANCE_C_DOWNLOAD="https://github.com/lance-format/lance-c/archive/refs/tags/v0.1.7.tar.gz";

Review Comment:
   [P1] Regenerate the shipped Rust crate-license inventory
   
   This bump changes the locked normal/build dependency graph, but 
`dist/LICENSE-dist.txt` still identifies lance-c v0.1.2 and 
`dist/licenses/LICENSE-lance-c-rust-crates.txt` still says it was generated 
from v0.1.2 with the old Lance/DataFusion versions. The exact v0.1.7 graph adds 
shipped crates such as `goosefs-sdk`, `opendal-service-goosefs`, 
`opendal-service-tos`, `lance-arrow-scalar`, `lance-index-core`, 
`lance-select`, and `libsais-rs`, none of which appears in that notice. Please 
update the distribution manifest and regenerate the inventory from the exact 
patched v0.1.7 lockfile as part of this dependency update.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/lance/source/LanceScanNode.java:
##########
@@ -435,9 +435,6 @@ public String getNodeExplainString(String prefix, 
TExplainLevel detailLevel) {
         if (isExternalSearch()) {
             TVectorSearchParams vector = 
externalSearchRequest.getSearchQuery().getVectorSearch();
             result.append(prefix).append("externalSearchType=VECTOR\n");
-            
result.append(prefix).append("lanceVectorColumn=").append(vector.getColumn()).append("\n");

Review Comment:
   [P2] Retain the searched vector field in EXPLAIN
   
   After removing this line, neither the remaining scan-node output nor the new 
BE profile identifies which vector field is searched. That cannot always be 
inferred from the tuple because `vector_search` allows the searched field to be 
unprojected, so searches over different vector columns of the same table become 
diagnostically indistinguishable. Please keep a safe `lanceVectorColumn=<name>` 
field (while continuing to omit the raw query vector) and retain its regression 
assertion.



-- 
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]

Reply via email to