airborne12 opened a new pull request, #66047:
URL: https://github.com/apache/doris/pull/66047

   ### What problem does this PR solve?
   
   Issue Number: close #xxx
   
   Related PR: #xxx
   
   Problem Summary:
   
   BM25 `idf` and `avg_dl` are properties of the whole collection, but 
`OlapScanner` built them from
   `_tablet_reader_params.rs_splits` — the slice of the read source that *this* 
scanner was handed:
   
   ```cpp
   // be/src/exec/scan/olap_scanner.cpp (before)
   if (_tablet_reader_params.score_runtime) {
       _tablet_reader_params.collection_statistics = 
std::make_shared<CollectionStatistics>();
       RETURN_IF_ERROR(_tablet_reader_params.collection_statistics->collect(
               _state, _tablet_reader_params.rs_splits, ...));   // <-- only 
this scanner's rowsets
   }
   ```
   
   `ParallelScannerBuilder` divides a tablet's `entire_read_source.rs_splits` 
into several
   `partitial_read_source.rs_splits`, one per scanner. So as soon as parallel 
scan produced more than
   one scanner for a tablet, each scanner computed `idf` over a *different 
subset of rowsets*, and
   `score()` depended on how the tablet happened to be split — rows served by a 
scanner owning few
   rowsets scored differently from identical rows served by a scanner owning 
many.
   
   This affects any inverted index format that supports BM25 scoring.
   
   **Fix.** The read source is captured *before* it is sliced, and statistics 
are collected once per
   tablet over all of its rowsets. `CollectionStatisticsBuildState` performs 
the sharing: the first
   scanner to arrive builds while the others wait on a condition variable, then 
each receives its own
   clone. The collected counts live in an immutable block that clones share; 
only the lazily memoized
   `idf`/`avg_dl` maps are per-scanner, so the read path needs no locking. A 
failed or throwing build
   is recorded and handed to the waiters rather than retried once per scanner.
   
   The sharing is not incidental — without it this would be a straight 
regression, since every scanner
   would repeat the full-collection walk that previously covered only its own 
slice.
   
   ### Release note
   
   Fix `score()` returning different BM25 scores for the same row depending on 
how many scanners the
   tablet's read source was split into. Collection statistics are now computed 
over the entire
   collection and shared by all scanners of a tablet.
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [x] Regression test
   
         
`regression-test/suites/inverted_index_p0/test_bm25_score_parallel_scan.groovy` 
loads a V3
         inverted index table as several rowsets, then compares `ORDER BY 
score() LIMIT 20` with
         `enable_parallel_scan = false` against the same query forced onto many 
scanners
         (`parallel_scan_min_rows_per_scanner = 16`, 
`parallel_scan_max_scanners_count = 16`).
         The two result sets must be identical.
   
       - [ ] Unit Test
       - [ ] Manual test (add detailed scripts or steps below)
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason <!-- Add your reason?  -->
   
   - Behavior changed:
       - [ ] No.
       - [x] Yes.
   
         `score()` values change for queries that were previously served by 
more than one scanner per
         tablet. The new values are the correct collection-wide ones; the old 
values varied with the
         scanner split. Relative ranking within a single scanner was already 
consistent, so this mainly
         affects absolute scores and cross-scanner ordering.
   
   - Does this need documentation?
       - [x] No.
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label <!-- Add branch pick label that this PR should 
merge into -->
   


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