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


##########
be/src/storage/segment/segment_iterator.cpp:
##########
@@ -1786,11 +1786,17 @@ Status SegmentIterator::_init_index_iterators() {
     _index_query_context->io_ctx = &_opts.io_ctx;
     _index_query_context->stats = _opts.stats;
     _index_query_context->runtime_state = _opts.runtime_state;
+    if (auto it = _opts.delete_bitmap.find(segment_id()); it != 
_opts.delete_bitmap.end()) {
+        _index_query_context->delete_bitmap = it->second;
+    }
 
     if (_score_runtime) {
         _index_query_context->collection_statistics = 
_opts.collection_statistics;
         _index_query_context->collection_similarity = 
std::make_shared<CollectionSimilarity>();
-        _index_query_context->query_limit = _score_runtime->get_limit();
+        _index_query_context->query_limit =

Review Comment:
   [P1] Gate early TopK on the complete visible candidate domain
   
   Absence of a rowset delete predicate is not enough to make segment-local 
TopK safe. For example, with a higher-scoring `id=1` and lower-scoring `id=2`, 
`WHERE SEARCH('title:alpha') AND id=2 ORDER BY score() DESC LIMIT 1` lets 
`FunctionSearch` keep only id=1 from the full index, after which the existing 
id/key predicate intersects it away and id=2 cannot be recovered. UNIQUE-MOR 
has the same issue when an explicit `__DORIS_DELETE_SIGN__=1` row or version 
merge removes a high-scoring key above `SegmentIterator`; neither source 
appears in this predicate count or the MOW bitmap. Please enable early TopK 
only when no later filter/merge can reject a hit, or feed the complete 
admissible-row domain into the collector, and cover both triggers.



##########
be/src/storage/segment/segment_iterator.cpp:
##########
@@ -3806,7 +3812,8 @@ void 
SegmentIterator::_prepare_score_column_materialization() {
 
     IColumn::MutablePtr result_column;
     auto result_row_ids = std::make_unique<std::vector<uint64_t>>();
-    if (_score_runtime->get_limit() > 0 && _col_predicates.empty() &&
+    if (_opts.delete_condition_predicates->num_of_column_predicate() == 0 &&

Review Comment:
   [P1] Avoid materializing every score for a small TopK query
   
   Together with `query_limit = 0`, this branch makes any applicable delete 
predicate turn `ORDER BY score() ... LIMIT 1` into full-match collection: 
`collect_multi_segment_doc_set` inserts every score into `_bm25_scores`, then 
`get_bm25_scores` allocates row-id and score arrays for the entire bitmap 
before the delete predicate runs. A broad term on an old rowset with even one 
delete predicate can therefore consume O(matches) memory/CPU instead of bounded 
TopK resources. Please make the candidate collection 
visibility-aware/refillable while remaining bounded, or add a concrete resource 
guard with scale evidence that prevents this fallback from exhausting a query.



##########
be/test/storage/index/inverted/query_v2/multi_segment_collector_test.cpp:
##########
@@ -142,6 +143,41 @@ TEST_F(MultiSegmentCollectorTest, 
CollectDocSetWithMultiReader) {
     _CLDECDELETE(dir1);
 }
 
+TEST_F(MultiSegmentCollectorTest, CollectTopKExcludesDeletedDocs) {
+    auto* dir0 = FSDirectory::getDirectory((kTestDir + "/segment0").c_str());
+    auto* dir1 = FSDirectory::getDirectory((kTestDir + "/segment1").c_str());
+
+    ValueArray<lucene::index::IndexReader*> readers(2);
+    readers[0] = lucene::index::IndexReader::open(dir0, true);
+    readers[1] = lucene::index::IndexReader::open(dir1, true);
+    auto reader = make_shared_reader(_CLNEW 
lucene::index::MultiReader(&readers, true));
+
+    auto index_query_context = std::make_shared<IndexQueryContext>();
+    auto field = StringHelper::to_wstring("title");
+    TermQuery query(index_query_context, field, 
StringHelper::to_wstring("fleabag"));

Review Comment:
   [P2] Exercise the offset and actual block-WAND paths
   
   This case does not fail if `+ seg_base` is removed: bitmap `{0}` still 
deletes first-reader local doc 0, while the expected second-reader hit is local 
doc 1/global doc 3 and remains admitted. Also, `TermQuery::weight(false)` is 
held as `WeightPtr`; `TermWeight` has only a templated same-name overload, not 
a virtual `PruningCallback` override, so the `use_wand=true` leg takes 
`Weight`'s generic scorer loop just like `false`, and these two hits have equal 
frequency/length rather than a deleted high scorer plus a lower replacement. 
Please add a nonzero-base deletion that fails on local-id lookup, plus a 
genuinely scoring Boolean query whose `OccurBooleanWeight` enters block WAND 
with a deleted high scorer and a visible replacement.



##########
regression-test/suites/search/test_search_score_topn_delete_predicate.groovy:
##########
@@ -0,0 +1,111 @@
+// 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.
+
+suite("test_search_score_topn_delete_predicate", "p0") {
+    def insertRows = { tableName, rows ->
+        sql "INSERT INTO ${tableName} VALUES ${rows}"
+        sql "SYNC"
+    }
+
+    def assertScoreTopN = { tableName, predicate, expectedId ->
+        assertEquals(expectedId, sql("""

Review Comment:
   [P2] Use the regression golden-output mechanism
   
   These are deterministic query results, but the suite wraps them in raw 
`assertEquals(sql(...))` calls and adds no generated `.out`. The repository 
testing rules require `qt_`/`order_qt_` (or explicit `ORDER BY`) with 
runner-generated expected output rather than Groovy assertions for determined 
results. Please convert the cases to named query tests and commit the generated 
output so the full rows/types are reviewed by the normal regression harness.



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