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


##########
fe/fe-core/src/main/java/org/apache/doris/tablefunction/LanceExternalSearchTableValuedFunction.java:
##########
@@ -196,6 +197,10 @@ protected static PreparedSearch prepareSearch(CommonSearch 
common, int fieldId,
                     .setFormat(TSearchFilterFormat.SQL)
                     
.setPayload(validateAndEncodeSqlFilter(common.params.get(FILTER))));
         }
+        // Keep the search-filter timing common to vector and full-text TVFs. 
Omission defaults
+        // to postfilter for both kinds of search.

Review Comment:
   [P1] Preserve filter semantics during BE rolling upgrades. A new FE sends 
`prefilter=false` for an omitted property, which an old BE ignores and still 
prefilters; conversely, an old FE sends no field, which this new BE treats as 
postfilter. With `top_k=3` and `filter=category = 'odd'`, one BE returns only 
row 2 while the other returns rows 2, 4, and 6, so the same query changes with 
split placement. Version or capability gate this semantic change on both sides, 
or retain the old default until all eligible BEs understand it.



##########
be/test/format_v2/table/lance_reader_test.cpp:
##########
@@ -923,15 +923,15 @@ TEST(LanceTableReaderVectorSearchTest, 
MultiVectorScoresFiltersOffsetsAndIndexed
                     }
                     // Read metrics after close: lance-c publishes its final 
execution summary
                     // when the stream is released, including for an early 
top-k stop.
-                    for (const char* name : {"LancePrefilterLoads", 
"LancePrefilterInputRows",
-                                             "LancePrefilterInputBatches", 
"LancePrefilterRowIds",
-                                             "LancePrefilterLoadTime", 
"LancePrefilterInputTime",
-                                             "LancePrefilterBuildTime"}) {
+                    for (const char* name : {"RowIdPrefilterLoads", 
"RowIdPrefilterInputRows",
+                                             "RowIdPrefilterInputBatches", 
"RowIdPrefilterIds",
+                                             "RowIdPrefilterLoadTime", 
"RowIdPrefilterInputTime",

Review Comment:
   [P2] Set `prefilter=true` in the BE cases that still assert prefilter 
behavior. This filtered test only sets `search_filter`, so the new BE passes 
false to Lance, while the changed assertions require every row-ID prefilter 
counter to be positive. The filtered TopK expectations in this file also assume 
prefilter-before-ranking and will fail. Set the flag explicitly in those 
existing cases and cover the new false/default path separately.



##########
thirdparty/patches/lance-c-foyer.patch:
##########
@@ -1003,32 +7293,20 @@ index 
0000000000000000000000000000000000000000..cfc47f1528d11b6be068c09dd4703ff4
 +                    },
 +                )
 +                .await?;
-+            // HTTP responses carry transport extensions even for immutable 
files.
-+            // Cache metadata independently; request-specific extensions are 
never replayed.
++            // Cache only immutable metadata and attributes, never 
request-specific state.
 +            self.reader.cache.metadata.insert(
-+                metadata_key.clone(),
++                metadata_key,
 +                (result.meta.clone(), result.attributes.clone()),
 +            );
-+            (result.meta, result.attributes, result.extensions)
++            (result.meta, result.attributes)
 +        };
 +        let object_size = metadata.size;
-+        let size_bytes = object_size.to_le_bytes();
-+        // WriteOnInsertion enqueues disk I/O even for an identical value. 
Look in
-+        // both tiers so warm reads, including recovered entries, remain 
read-only.

Review Comment:
   [P2] Skip the size-key insert on warm reads. This `cached_get` path is 
reached by ordinary Lance range reads, and `WriteOnInsertion` enqueues a disk 
write for the same 8-byte size record on every call, even when metadata and 
data blocks are cached. The previous patch checked the memory and disk tiers 
before inserting and had a zero-write warm-read test; retain that guard and 
test to avoid persistent write amplification.



##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -1180,7 +1066,8 @@ void LanceTableReader::_collect_scan_statistics(void* 
callback_ctx, const void*
     update_counter(reader->_execution_iops, statistics->iops, "iops");
     update_counter(reader->_execution_requests, statistics->requests, 
"requests");
     update_counter(reader->_execution_bytes_read, statistics->bytes_read, 
"bytes_read");
-    update_counter(reader->_index_partition_cache_miss_loads, 
statistics->index_partitions_loaded,
+    update_counter(reader->_index_object_loads, statistics->indices_loaded, 
"indices_loaded");
+    update_counter(reader->_index_components_loaded, 
statistics->index_partitions_loaded,
                    "index_partitions_loaded");
     update_counter(reader->_index_comparisons, statistics->index_comparisons, 
"index_comparisons");
 

Review Comment:
   [P2] Keep the counter tree stable across Lance scanner tasks. These groups 
are now created only for metrics reported by each task, but FE 
`RuntimeProfile.mergeCounters` traverses only the first task's child-counter 
map. A vector query with an uncovered flat split and an indexed split can 
therefore lose all `LanceVectorIndex` metrics in its aggregate Profile when the 
flat task is first. Pre-register the hierarchy for every scanner or merge the 
union of counter names, and cover the mixed-split aggregate.



##########
be/src/format_v2/table/lance_reader.cpp:
##########
@@ -1197,38 +1084,20 @@ void LanceTableReader::_collect_scan_statistics(void* 
callback_ctx, const void*
             continue;
         }
         const std::string_view name(metric.name == nullptr ? "" : metric.name, 
metric.name_len);
-        RuntimeProfile::Counter* counter = nullptr;
-        switch (metric.kind) {
-        case LANCE_SCAN_METRIC_COUNT: {
-            const auto found = reader->_lance_count_metrics.find(name);
-            if (found != reader->_lance_count_metrics.end()) {
-                counter = found->second;
+        for (const auto& definition : LANCE_SCAN_METRICS) {
+            if (definition.native_name != name) {
+                continue;
             }
-            break;
-        }
-        case LANCE_SCAN_METRIC_TIME_NANOSECONDS: {
-            const auto found = reader->_lance_time_metrics.find(name);
-            if (found != reader->_lance_time_metrics.end()) {
-                counter = found->second;
-            } else if (name == "search_time") {
-                // Scalar-index metrics exist only when Lance includes the 
corresponding
-                // execution node in this scan plan.
-                counter = ADD_CHILD_TIMER_WITH_LEVEL(reader->_scanner_profile,

Review Comment:
   [P2] Keep metric allocation out of the Lance statistics callback. 
`add_lance_counter` now allocates counters and map entries for every first-seen 
metric at EOF; an allocation failure can throw through 
`LanceScanStatisticsCallback`, whose ABI requires callbacks to return normally, 
potentially aborting the BE. Pre-register these metrics before handing the 
callback to Lance, or catch allocation failures inside the callback and skip 
best-effort profiling.



##########
thirdparty/patches/lance-c-foyer.patch:
##########
@@ -547,32 +6861,9 @@ index 
0000000000000000000000000000000000000000..cfc47f1528d11b6be068c09dd4703ff4
 +use crate::runtime::block_on;
 +use crate::session::{LanceSession, session_new_with_data_cache_factory};
 +
-+const CACHE_KEY_VERSION: &str = "lance-data-v2";
++const CACHE_KEY_VERSION: &str = "lance-data-v1";
 +const FOYER_PAGE_SIZE: usize = 4096;
 +
-+struct OriginNamespace {
-+    origin: Weak<dyn ObjectStore>,
-+    namespace: uuid::Uuid,
-+}
-+
-+static ORIGIN_NAMESPACES: LazyLock<Mutex<HashMap<usize, OriginNamespace>>> =
-+    LazyLock::new(|| Mutex::new(HashMap::new()));
-+
-+fn origin_namespace(origin: &Arc<dyn ObjectStore>) -> uuid::Uuid {
-+    // store_prefix omits endpoint/credentials, and this interface exposes no 
stable
-+    // backend identity. Only the same live origin may reuse metadata or data.
-+    // Persist a random namespace, never an address that another process can 
reuse.
-+    let mut namespaces = ORIGIN_NAMESPACES.lock().unwrap();
-+    namespaces.retain(|_, entry| entry.origin.strong_count() != 0);
-+    namespaces
-+        .entry(Arc::as_ptr(origin) as *const () as usize)
-+        .or_insert_with(|| OriginNamespace {
-+            origin: Arc::downgrade(origin),
-+            namespace: uuid::Uuid::new_v4(),
-+        })
-+        .namespace
-+}
-+
 +/// Configuration for the optional Foyer data-file cache.
 +#[repr(C)]

Review Comment:
   [P1] Include the actual storage origin in Foyer cache keys. This now retains 
only Lance's `store_prefix`, which is `s3$bucket` for S3 and omits 
`aws_endpoint`, while Doris passes per-catalog endpoints into a BE-wide 
default-enabled session. Two catalogs with the same bucket and object path on 
different endpoints can read the first endpoint's cached data (or a recovered 
disk block) instead of their own, even when the second origin would deny the 
read. Key both metadata and blocks by a stable endpoint/authorization identity, 
or isolate origins, and restore the distinct-endpoint tests.



##########
docs/lance-prefilter-profile.md:
##########
@@ -32,17 +32,17 @@ vectors use a different loader and are not included in 
these counters.
 
 | Counter | Meaning |
 | --- | --- |
-| `LancePrefilterLoads` | Number of row-ID prefilter loader executions 
started. |
-| `LancePrefilterInputBatches` | Successfully consumed input batches. |
-| `LancePrefilterInputRows` | Non-null input row IDs, including duplicates. |
-| `LancePrefilterRowIds` | Sum of distinct row IDs in successfully completed 
allow sets. |
-| `LancePrefilterLoadTime` | Total loader wall time, including input polling 
and set construction. |
-| `LancePrefilterInputTime` | Wall time polling input batches, including 
upstream execution, I/O, decoding and scheduling. |
-| `LancePrefilterBuildTime` | Wall time inserting row IDs into the allow set, 
measured once per batch. |
+| `RowIdPrefilterLoads` | Number of row-ID prefilter loader executions 
started. |

Review Comment:
   [P3] Update the prefilter guide for the new default. The paragraph above 
this renamed counter table still says an actual filter uses the row-ID 
prefilter path, but a `vector_search` with `filter` and no `prefilter` now 
postfilters and can have no row-ID prefilter counters. Qualify that statement 
with `prefilter=true` and describe the false/default case so profiles are 
interpreted correctly.



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