Add a experimental flag to control the bugfix in cl/694010741

PiperOrigin-RevId: 730762929
This commit is contained in:
Toshiyuki Hanaoka
2025-02-25 08:24:06 +00:00
committed by Hiroyuki Komatsu
parent d939d1446b
commit 4af84e37ba
4 changed files with 79 additions and 59 deletions

View File

@ -543,7 +543,7 @@ message Capability {
[default = NO_TEXT_DELETION_CAPABILITY]; [default = NO_TEXT_DELETION_CAPABILITY];
} }
// Next ID: 105 // Next ID: 106
// Bundles together some Android experiment flags so that they can be easily // Bundles together some Android experiment flags so that they can be easily
// retrieved throughout the native code. These flags are generally specific to // retrieved throughout the native code. These flags are generally specific to
// the decoder, and are made available when the decoder is initialized. // the decoder, and are made available when the decoder is initialized.
@ -646,6 +646,9 @@ message DecoderExperimentParams {
// history rewriter wheh the target segment contains proper noun candidate. // history rewriter wheh the target segment contains proper noun candidate.
optional bool user_segment_history_rewriter_replace_proper_noun = 103 optional bool user_segment_history_rewriter_replace_proper_noun = 103
[default = false]; [default = false];
// Apply inner segment boundary information to the single segment candidate.
optional bool apply_single_inner_segment_boundary = 105 [default = true];
} }
// Clients' request to the server. // Clients' request to the server.

View File

@ -740,11 +740,21 @@ bool UserSegmentHistoryRewriter::IsAvailable(const ConversionRequest &request,
// Returns segments for learning. // Returns segments for learning.
// Inner segments boundary will be expanded. // Inner segments boundary will be expanded.
Segments UserSegmentHistoryRewriter::MakeLearningSegmentsFromInnerSegments( Segments UserSegmentHistoryRewriter::MakeLearningSegmentsFromInnerSegments(
const Segments &segments) { const ConversionRequest &request, const Segments &segments) {
auto inner_segments_info_available = [&request](const Segment::Candidate &c) {
if (request.request()
.decoder_experiment_params()
.apply_single_inner_segment_boundary()) {
return !c.inner_segment_boundary.empty();
} else {
return c.inner_segment_boundary.size() > 1;
}
};
Segments ret; Segments ret;
for (const Segment &segment : segments) { for (const Segment &segment : segments) {
const Segment::Candidate &candidate = segment.candidate(0); const Segment::Candidate &candidate = segment.candidate(0);
if (candidate.inner_segment_boundary.empty()) { if (!inner_segments_info_available(candidate)) {
// No inner segment info // No inner segment info
Segment *seg = ret.add_segment(); Segment *seg = ret.add_segment();
*seg = segment; *seg = segment;
@ -796,7 +806,7 @@ void UserSegmentHistoryRewriter::Finish(const ConversionRequest &request,
const Segments target_segments = const Segments target_segments =
UseInnerSegments(request) UseInnerSegments(request)
? MakeLearningSegmentsFromInnerSegments(*segments) ? MakeLearningSegmentsFromInnerSegments(request, *segments)
: *segments; : *segments;
std::vector<Segments::RevertEntry> revert_entries; std::vector<Segments::RevertEntry> revert_entries;
for (size_t i = target_segments.history_segments_size(); for (size_t i = target_segments.history_segments_size();

View File

@ -90,7 +90,7 @@ class UserSegmentHistoryRewriter : public RewriterInterface {
}; };
static Segments MakeLearningSegmentsFromInnerSegments( static Segments MakeLearningSegmentsFromInnerSegments(
const Segments &segments); const ConversionRequest &request, const Segments &segments);
// Returns id for RevertEntry // Returns id for RevertEntry
static uint16_t revert_id(); static uint16_t revert_id();

View File

@ -67,9 +67,9 @@ class UserSegmentHistoryRewriterTestPeer {
UserSegmentHistoryRewriterTestPeer() = delete; UserSegmentHistoryRewriterTestPeer() = delete;
static Segments MakeLearningSegmentsFromInnerSegments( static Segments MakeLearningSegmentsFromInnerSegments(
const Segments &segments) { const ConversionRequest &request, const Segments &segments) {
return UserSegmentHistoryRewriter::MakeLearningSegmentsFromInnerSegments( return UserSegmentHistoryRewriter::MakeLearningSegmentsFromInnerSegments(
segments); request, segments);
} }
}; };
@ -1755,9 +1755,11 @@ TEST_F(UserSegmentHistoryRewriterTest, SupportInnerSegmentsOnLearning) {
Segment::Candidate::RERANKED; Segment::Candidate::RERANKED;
segments.mutable_segment(0)->set_segment_type(Segment::FIXED_VALUE); segments.mutable_segment(0)->set_segment_type(Segment::FIXED_VALUE);
const ConversionRequest default_mobile_convreq = CreateConversionRequest();
{ {
const Segments learning_segments = UserSegmentHistoryRewriterTestPeer:: const Segments learning_segments = UserSegmentHistoryRewriterTestPeer::
MakeLearningSegmentsFromInnerSegments(segments); MakeLearningSegmentsFromInnerSegments(default_mobile_convreq,
segments);
EXPECT_EQ(learning_segments.segments_size(), 3); EXPECT_EQ(learning_segments.segments_size(), 3);
EXPECT_EQ(learning_segments.segment(0).key(), "わたしの"); EXPECT_EQ(learning_segments.segment(0).key(), "わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).key, "わたしの"); EXPECT_EQ(learning_segments.segment(0).candidate(0).key, "わたしの");
@ -1795,8 +1797,7 @@ TEST_F(UserSegmentHistoryRewriterTest, SupportInnerSegmentsOnLearning) {
Segment::FIXED_VALUE); Segment::FIXED_VALUE);
} }
const ConversionRequest convreq = CreateConversionRequest(); rewriter->Finish(default_mobile_convreq, &segments);
rewriter->Finish(convreq, &segments);
} }
{ {
@ -1823,9 +1824,11 @@ TEST_F(UserSegmentHistoryRewriterTest, SupportInnerSegmentsOnLearning) {
Segment::Candidate::RERANKED; Segment::Candidate::RERANKED;
segments.mutable_segment(0)->set_segment_type(Segment::FIXED_VALUE); segments.mutable_segment(0)->set_segment_type(Segment::FIXED_VALUE);
const ConversionRequest default_mobile_convreq = CreateConversionRequest();
{ {
const Segments learning_segments = UserSegmentHistoryRewriterTestPeer:: const Segments learning_segments = UserSegmentHistoryRewriterTestPeer::
MakeLearningSegmentsFromInnerSegments(segments); MakeLearningSegmentsFromInnerSegments(default_mobile_convreq,
segments);
EXPECT_EQ(learning_segments.segments_size(), 1); EXPECT_EQ(learning_segments.segments_size(), 1);
EXPECT_EQ(learning_segments.segment(0).key(), "わたしの"); EXPECT_EQ(learning_segments.segment(0).key(), "わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).key, "わたしの"); EXPECT_EQ(learning_segments.segment(0).candidate(0).key, "わたしの");
@ -1839,52 +1842,7 @@ TEST_F(UserSegmentHistoryRewriterTest, SupportInnerSegmentsOnLearning) {
Segment::FIXED_VALUE); Segment::FIXED_VALUE);
} }
const ConversionRequest convreq = CreateConversionRequest(); rewriter->Finish(default_mobile_convreq, &segments);
rewriter->Finish(convreq, &segments);
}
{
// Inner segment boundary with size 1 may have better information.
segments.Clear();
InitSegments(&segments, 1, 2);
constexpr absl::string_view kKey = "わたしの";
constexpr absl::string_view kValue = "私の";
segments.mutable_segment(0)->set_key(kKey);
Segment::Candidate *candidate =
segments.mutable_segment(0)->mutable_candidate(1);
candidate->value = kValue;
candidate->content_value = kValue;
candidate->key = kKey;
candidate->content_key = kKey;
// "わたしの, 私の", "わたし, 私"
candidate->PushBackInnerSegmentBoundary(12, 6, 9, 3);
candidate->lid = 10;
candidate->rid = 10;
segments.mutable_segment(0)->move_candidate(1, 0);
segments.mutable_segment(0)->mutable_candidate(0)->attributes |=
Segment::Candidate::RERANKED;
segments.mutable_segment(0)->set_segment_type(Segment::FIXED_VALUE);
{
const Segments learning_segments = UserSegmentHistoryRewriterTestPeer::
MakeLearningSegmentsFromInnerSegments(segments);
EXPECT_EQ(learning_segments.segments_size(), 1);
EXPECT_EQ(learning_segments.segment(0).key(), "わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).key, "わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).value, "私の");
EXPECT_EQ(learning_segments.segment(0).candidate(0).content_key,
"わたし");
EXPECT_EQ(learning_segments.segment(0).candidate(0).content_value, "");
EXPECT_EQ(learning_segments.segment(0).candidate(0).lid, 10);
EXPECT_EQ(learning_segments.segment(0).candidate(0).rid, 10);
EXPECT_EQ(learning_segments.segment(0).segment_type(),
Segment::FIXED_VALUE);
}
const ConversionRequest convreq = CreateConversionRequest();
rewriter->Finish(convreq, &segments);
} }
{ {
@ -1904,10 +1862,59 @@ TEST_F(UserSegmentHistoryRewriterTest, SupportInnerSegmentsOnLearning) {
candidate->content_key = "なかの"; candidate->content_key = "なかの";
candidate->content_key = "なかの"; candidate->content_key = "なかの";
const ConversionRequest convreq = CreateConversionRequest(); const ConversionRequest default_mobile_convreq = CreateConversionRequest();
EXPECT_TRUE(rewriter->Rewrite(convreq, &segments)); EXPECT_TRUE(rewriter->Rewrite(default_mobile_convreq, &segments));
EXPECT_EQ(segments.segment(0).candidate(0).value, "中野"); EXPECT_EQ(segments.segment(0).candidate(0).value, "中野");
} }
{
// Disable inner segment boundary for single segment
request_->mutable_decoder_experiment_params()
->set_apply_single_inner_segment_boundary(false);
// Inner segment boundary with size 1 may have better information.
segments.Clear();
InitSegments(&segments, 1, 2);
constexpr absl::string_view kKey = "わたしの";
constexpr absl::string_view kValue = "私の";
segments.mutable_segment(0)->set_key(kKey);
Segment::Candidate *candidate =
segments.mutable_segment(0)->mutable_candidate(1);
candidate->value = kValue;
candidate->content_value = kValue;
candidate->key = kKey;
candidate->content_key = kKey;
// "わたしの, 私の", "わたし, 私"
candidate->PushBackInnerSegmentBoundary(12, 6, 9, 3);
candidate->lid = 10;
candidate->rid = 10;
segments.mutable_segment(0)->move_candidate(1, 0);
segments.mutable_segment(0)->mutable_candidate(0)->attributes |=
Segment::Candidate::RERANKED;
segments.mutable_segment(0)->set_segment_type(Segment::FIXED_VALUE);
const ConversionRequest convreq = CreateConversionRequest();
{
const Segments learning_segments = UserSegmentHistoryRewriterTestPeer::
MakeLearningSegmentsFromInnerSegments(convreq, segments);
EXPECT_EQ(learning_segments.segments_size(), 1);
EXPECT_EQ(learning_segments.segment(0).key(), "わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).key, "わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).value, "私の");
EXPECT_EQ(learning_segments.segment(0).candidate(0).content_key,
"わたしの");
EXPECT_EQ(learning_segments.segment(0).candidate(0).content_value,
"私の");
EXPECT_EQ(learning_segments.segment(0).candidate(0).lid, 10);
EXPECT_EQ(learning_segments.segment(0).candidate(0).rid, 10);
EXPECT_EQ(learning_segments.segment(0).segment_type(),
Segment::FIXED_VALUE);
}
rewriter->Finish(convreq, &segments);
}
} }
TEST_F(UserSegmentHistoryRewriterTest, ReplaceableSingleKanji) { TEST_F(UserSegmentHistoryRewriterTest, ReplaceableSingleKanji) {