Coverage Report

Created: 2026-10-09 18:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/index/inverted/token_stream.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <unicode/utext.h>
21
#include <unicode/utf8.h>
22
23
#include <algorithm>
24
#include <cstddef>
25
#include <memory>
26
#include <span>
27
#include <string_view>
28
#include <utility>
29
30
#include "CLucene.h"
31
#include "CLucene/analysis/AnalysisHeader.h"
32
#include "common/cast_set.h"
33
#include "storage/index/inverted/util/reader.h"
34
35
using namespace lucene::analysis;
36
37
namespace doris::segment_v2::inverted_index {
38
39
class DorisTokenizer;
40
using TokenizerPtr = std::shared_ptr<DorisTokenizer>;
41
42
using TokenStreamPtr = std::shared_ptr<TokenStream>;
43
44
// Reused analyzers keep ordinary scratch across values; one oversized value must not pin its
45
// capacity for the rest of the writer lifetime.
46
constexpr size_t ANALYZER_SCRATCH_HIGH_WATER_BYTES = 64 * 1024;
47
48
// Longest prefix of text that fits in max_bytes without splitting a rune, and its rune count.
49
197k
inline std::pair<size_t, size_t> utf8_prefix_at_most(std::string_view text, size_t max_bytes) {
50
197k
    const auto length = static_cast<int32_t>(text.size());
51
197k
    const auto limit = static_cast<int32_t>(std::min(text.size(), max_bytes));
52
197k
    int32_t offset = 0;
53
197k
    size_t rune_count = 0;
54
398k
    while (offset < length) {
55
200k
        int32_t next = offset;
56
200k
        U8_FWD_1(text, next, length);
57
200k
        if (next > limit) {
58
8
            break;
59
8
        }
60
200k
        offset = next;
61
200k
        ++rune_count;
62
200k
    }
63
197k
    return {static_cast<size_t>(offset), rune_count};
64
197k
}
65
66
template <typename Container>
67
62.9k
void release_oversized_scratch(Container& container) {
68
62.9k
    if (container.capacity() * sizeof(typename Container::value_type) >
69
62.9k
        ANALYZER_SCRATCH_HIGH_WATER_BYTES) {
70
44
        Container().swap(container);
71
44
    }
72
62.9k
}
_ZN5doris10segment_v214inverted_index25release_oversized_scratchISt6vectorIiSaIiEEEEvRT_
Line
Count
Source
67
52.9k
void release_oversized_scratch(Container& container) {
68
52.9k
    if (container.capacity() * sizeof(typename Container::value_type) >
69
52.9k
        ANALYZER_SCRATCH_HIGH_WATER_BYTES) {
70
32
        Container().swap(container);
71
32
    }
72
52.9k
}
_ZN5doris10segment_v214inverted_index25release_oversized_scratchINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRT_
Line
Count
Source
67
9.86k
void release_oversized_scratch(Container& container) {
68
9.86k
    if (container.capacity() * sizeof(typename Container::value_type) >
69
9.86k
        ANALYZER_SCRATCH_HIGH_WATER_BYTES) {
70
8
        Container().swap(container);
71
8
    }
72
9.86k
}
_ZN5doris10segment_v214inverted_index25release_oversized_scratchISt6vectorINS1_12PinyinFilter8RuneInfoESaIS5_EEEEvRT_
Line
Count
Source
67
68
void release_oversized_scratch(Container& container) {
68
68
    if (container.capacity() * sizeof(typename Container::value_type) >
69
68
        ANALYZER_SCRATCH_HIGH_WATER_BYTES) {
70
4
        Container().swap(container);
71
4
    }
72
68
}
73
74
/**
75
 * All custom tokenizers and token_filters must use the following functions 
76
 * to set token information. Using these unified set methods helps avoid 
77
 * unnecessary data copying.
78
 * 
79
 * Note: Must not mix with other set methods
80
 */
81
class DorisTokenStream {
82
public:
83
2.42k
    DorisTokenStream() = default;
84
2.42k
    virtual ~DorisTokenStream() = default;
85
86
300k
    void set(Token* t, const std::string_view& term, int32_t pos = 1) {
87
300k
        t->setTextNoCopy(term.data(), cast_set<int32_t>(term.size()));
88
300k
        t->setPositionIncrement(pos);
89
300k
    }
90
91
64.5k
    void set_text(Token* t, const std::string_view& term) {
92
64.5k
        t->setTextNoCopy(term.data(), cast_set<int32_t>(term.size()));
93
64.5k
    }
94
95
176k
    int32_t get_position_increment(Token* t) { return t->getPositionIncrement(); }
96
174k
    void set_position_increment(Token* t, int32_t pos) { t->setPositionIncrement(pos); }
97
98
    // Return each rune's original relative byte start followed by the token's final byte end.
99
0
    virtual std::span<const int32_t> get_source_byte_offsets() const { return {}; }
100
101
    // Return separate rune ends when removed delimiters leave gaps between adjacent runes.
102
0
    virtual std::span<const int32_t> get_source_byte_end_offsets() const { return {}; }
103
104
    // Return a conservative relative source span when exact rune boundaries are unavailable.
105
8.46k
    virtual bool get_conservative_source_byte_span(int32_t& start, int32_t& end) const {
106
8.46k
        return false;
107
8.46k
    }
108
109
    // Enable source-boundary tracking only for streams with a downstream consumer.
110
0
    virtual void set_source_byte_offsets_enabled(bool enabled) {}
111
};
112
113
class TokenStreamWrapper : public TokenStream {
114
public:
115
272
    explicit TokenStreamWrapper(std::shared_ptr<TokenStream> ts) : _impl(std::move(ts)) {}
116
272
    ~TokenStreamWrapper() override = default;
117
118
221k
    Token* next(Token* token) override { return _impl->next(token); }
119
146
    void close() override { _impl->close(); }
120
6
    void reset() override { _impl->reset(); }
121
122
private:
123
    std::shared_ptr<TokenStream> _impl;
124
};
125
126
class TokenStreamComponents {
127
public:
128
    TokenStreamComponents(TokenizerPtr tokenizer, TokenStreamPtr result)
129
608
            : _source(std::move(tokenizer)), _sink(std::move(result)) {}
130
131
    void set_reader(const ReaderPtr& reader);
132
    TokenStreamPtr get_token_stream();
133
    TokenizerPtr get_source();
134
135
private:
136
    TokenizerPtr _source;
137
    TokenStreamPtr _sink;
138
};
139
using TokenStreamComponentsPtr = std::shared_ptr<TokenStreamComponents>;
140
141
}; // namespace doris::segment_v2::inverted_index