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


##########
be/src/storage/index/inverted/reader/collection_statistics.h:
##########
@@ -106,15 +107,27 @@ class CollectionStatistics {
                                              const std::wstring& term);
     MOCK_FUNCTION float get_or_calculate_avg_dl(const std::wstring& 
lucene_col_name);
 
+    // The terms the collected `prefix` expanded to in any segment of the 
tablet and that some
+    // returned row holds, in dictionary order; their idfs are in 
get_or_calculate_idf. None for a
+    // prefix that was not collected, as for a SEARCH predicate.
+    MOCK_FUNCTION std::vector<std::wstring> get_prefix_expansions(
+            const std::wstring& lucene_col_name, const std::wstring& prefix);
+
     // Replaces the collected counters with those of `other`. The derived 
idf/avgdl caches are
     // reset rather than copied, so the copy can be used by another thread 
without sharing them.
     void copy_collected_from(const CollectionStatistics& other);
 
 private:
+    // The terms each collected prefix expanded to, by field and prefix.
+    using PrefixExpansions =
+            std::unordered_map<std::wstring,
+                               std::unordered_map<std::wstring, 
std::set<std::wstring>>>;

Review Comment:
   [P2] Account for retained prefix-expansion memory
   
   These standard containers retain dictionary-sized term sets without charging 
the query MemTracker. For `inverted_index_max_expansions=0`, a broad two-token 
phrase prefix can retain the entire matching tablet vocabulary in 
`_prefix_expansions` and the expanded `_term_doc_freqs`; 
`copy_collected_from()` then deep-copies both into every scanner. Unlike the 
existing explicit accounting for SNII null-doc vectors, these allocations and 
copies have no reservation or consume/release accounting, and the production 
malloc hook forwards directly to jemalloc. A high-cardinality prefix therefore 
bypasses query/workload memory limits and can drive process memory pressure. 
Use tracked storage or complete explicit accounting, including term buffers and 
scanner copies.



##########
be/src/storage/index/inverted/reader/collection_statistics.cpp:
##########
@@ -117,6 +119,35 @@ void add_term_doc_frequency(
     (*logical_frequencies)[field][logical_term] += doc_frequency;
 }
 
+Status segment_scoring_terms(index_query::IndexSource& source, const 
CollectInfo& collect_info,
+                             std::unordered_map<std::wstring, 
std::set<std::wstring>>* expansions,
+                             std::vector<std::string>* terms) {
+    DORIS_CHECK(expansions != nullptr);
+    DORIS_CHECK(terms != nullptr);
+    *terms = collect_info.unique_terms;
+    std::unordered_set<std::string> listed(terms->begin(), terms->end());
+    for (const auto& scoring_prefix : collect_info.scoring_prefixes) {
+        index_query::TermPattern pattern;
+        
RETURN_IF_ERROR(index_query::TermPattern::create(index_query::TermPatternKind::kPrefix,
+                                                         
scoring_prefix.prefix, &pattern));
+        std::vector<std::string> expanded;
+        RETURN_IF_ERROR(source.expand_terms(
+                pattern,
+                
index_query::expansion_limit(index_query::TermPatternKind::kPrefix,
+                                             scoring_prefix.max_expansions),
+                &expanded));
+        auto& prefix_terms = 
(*expansions)[segment_v2::inverted_index::StringHelper::to_wstring(
+                scoring_prefix.prefix)];
+        for (auto& term : expanded) {
+            
prefix_terms.insert(segment_v2::inverted_index::StringHelper::to_wstring(term));
+            if (listed.insert(term).second) {
+                terms->push_back(std::move(term));

Review Comment:
   [P2] Count each tablet expansion in every collection segment
   
   Only locally expanded terms enter this segment's document-frequency loop, 
but `for_terms_and_prefix()` scores the union from all segments. With 
`inverted_index_max_expansions=1`, let segment A contain `apple rose`, and B 
contain `apple red` plus `apple rose`. A selects `rose`, B selects `red`; the 
tablet union contains both, yet `df(rose)` becomes 1 instead of 2. For N=3 its 
IDF is therefore 0.9808 instead of 0.4700, inflating every matching 
phrase-prefix score. Both CLucene and SNII use this helper. Collect the tablet 
expansion set first and count every selected term across every segment, or 
backfill missing segment contributions; preserve hidden-row subtraction. The 
single-segment regression does not cover this case.



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