Commit ae792bea authored by tby's avatar tby Committed by Commit Bot

[Files Ranking] Add a new Dolphin model for zero-state ranking

This CL adds a new Dolphin model to the search result ranker for zero
state files ranking. Additionally, it:

1. Adds a new Finch flag to guard the construction of the model.
2. Adds/renames some getters/setters for consistent naming: the app
   model is an AppSearchResultRanker (Roselle) object, and the non-app
   model is a SearchResultRanker (Dolphin) object.

This CL also makes a small change to the SearchController's members:
the Mixer is moved above the SearchProviders. This is because, in
future CLs, a search provider will hold a pointer for a model owned
(indirectly) by the Mixer, and this ensures the model outlives the
provider.

Bug: 959679
Change-Id: Ib101463c61ed79657e380870eeb749e08188a131
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1604387Reviewed-by: default avatarJenny Zhang <jennyz@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarJia Meng <jiameng@chromium.org>
Commit-Queue: Tony Yeoman <tby@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659273}
parent c89bd444
...@@ -33,6 +33,8 @@ const base::Feature kEnableZeroStateAppsRanker{ ...@@ -33,6 +33,8 @@ const base::Feature kEnableZeroStateAppsRanker{
"EnableZeroStateAppsRanker", base::FEATURE_ENABLED_BY_DEFAULT}; "EnableZeroStateAppsRanker", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kEnableQueryBasedMixedTypesRanker{ const base::Feature kEnableQueryBasedMixedTypesRanker{
"EnableQueryBasedMixedTypesRanker", base::FEATURE_DISABLED_BY_DEFAULT}; "EnableQueryBasedMixedTypesRanker", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnableZeroStateMixedTypesRanker{
"EnableZeroStateMixedTypesRanker", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnableAppReinstallZeroState{ const base::Feature kEnableAppReinstallZeroState{
"EnableAppReinstallZeroState", base::FEATURE_DISABLED_BY_DEFAULT}; "EnableAppReinstallZeroState", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnableEmbeddedAssistantUI{ const base::Feature kEnableEmbeddedAssistantUI{
...@@ -90,6 +92,10 @@ bool IsQueryBasedMixedTypesEnabled() { ...@@ -90,6 +92,10 @@ bool IsQueryBasedMixedTypesEnabled() {
return base::FeatureList::IsEnabled(kEnableQueryBasedMixedTypesRanker); return base::FeatureList::IsEnabled(kEnableQueryBasedMixedTypesRanker);
} }
bool IsZeroStateMixedTypesRankerEnabled() {
return base::FeatureList::IsEnabled(kEnableZeroStateMixedTypesRanker);
}
bool IsAppReinstallZeroStateEnabled() { bool IsAppReinstallZeroStateEnabled() {
return base::FeatureList::IsEnabled(kEnableAppReinstallZeroState); return base::FeatureList::IsEnabled(kEnableAppReinstallZeroState);
} }
......
...@@ -53,6 +53,9 @@ ASH_PUBLIC_EXPORT extern const base::Feature kEnableZeroStateAppsRanker; ...@@ -53,6 +53,9 @@ ASH_PUBLIC_EXPORT extern const base::Feature kEnableZeroStateAppsRanker;
// Enable an model that ranks query based non-apps result. // Enable an model that ranks query based non-apps result.
ASH_PUBLIC_EXPORT extern const base::Feature kEnableQueryBasedMixedTypesRanker; ASH_PUBLIC_EXPORT extern const base::Feature kEnableQueryBasedMixedTypesRanker;
// Enable a model that ranks zero-state files and recent queries.
ASH_PUBLIC_EXPORT extern const base::Feature kEnableZeroStateMixedTypesRanker;
// Enables the feature to include a single reinstallation candidate in // Enables the feature to include a single reinstallation candidate in
// zero-state. // zero-state.
ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppReinstallZeroState; ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppReinstallZeroState;
...@@ -77,6 +80,7 @@ bool ASH_PUBLIC_EXPORT IsAdaptiveResultRankerEnabled(); ...@@ -77,6 +80,7 @@ bool ASH_PUBLIC_EXPORT IsAdaptiveResultRankerEnabled();
bool ASH_PUBLIC_EXPORT IsQueryBasedAppsRankerEnabled(); bool ASH_PUBLIC_EXPORT IsQueryBasedAppsRankerEnabled();
bool ASH_PUBLIC_EXPORT IsZeroStateAppsRankerEnabled(); bool ASH_PUBLIC_EXPORT IsZeroStateAppsRankerEnabled();
bool ASH_PUBLIC_EXPORT IsQueryBasedMixedTypesRankerEnabled(); bool ASH_PUBLIC_EXPORT IsQueryBasedMixedTypesRankerEnabled();
bool ASH_PUBLIC_EXPORT IsZeroStateMixedTypesRankerEnabled();
bool ASH_PUBLIC_EXPORT IsAppReinstallZeroStateEnabled(); bool ASH_PUBLIC_EXPORT IsAppReinstallZeroStateEnabled();
bool ASH_PUBLIC_EXPORT IsEmbeddedAssistantUIEnabled(); bool ASH_PUBLIC_EXPORT IsEmbeddedAssistantUIEnabled();
bool ASH_PUBLIC_EXPORT IsAppGridGhostEnabled(); bool ASH_PUBLIC_EXPORT IsAppGridGhostEnabled();
......
...@@ -156,19 +156,24 @@ void Mixer::RemoveDuplicates(SortedResults* results) { ...@@ -156,19 +156,24 @@ void Mixer::RemoveDuplicates(SortedResults* results) {
} }
void Mixer::FetchResults(const base::string16& query) { void Mixer::FetchResults(const base::string16& query) {
if (ranker_) if (non_app_ranker_)
ranker_->FetchRankings(query); non_app_ranker_->FetchRankings(query);
for (const auto& group : groups_) for (const auto& group : groups_)
group->FetchResults(ranker_.get()); group->FetchResults(non_app_ranker_.get());
} }
void Mixer::SetSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker) { void Mixer::SetNonAppSearchResultRanker(
ranker_ = std::move(ranker); std::unique_ptr<SearchResultRanker> ranker) {
non_app_ranker_ = std::move(ranker);
}
SearchResultRanker* Mixer::GetNonAppSearchResultRanker() {
return non_app_ranker_.get();
} }
void Mixer::Train(const std::string& id, RankingItemType type) { void Mixer::Train(const std::string& id, RankingItemType type) {
if (ranker_) if (non_app_ranker_)
ranker_->Train(id, type); non_app_ranker_->Train(id, type);
} }
} // namespace app_list } // namespace app_list
...@@ -50,9 +50,13 @@ class Mixer { ...@@ -50,9 +50,13 @@ class Mixer {
// Collects the results, sorts and publishes them. // Collects the results, sorts and publishes them.
void MixAndPublish(size_t num_max_results, const base::string16& query); void MixAndPublish(size_t num_max_results, const base::string16& query);
// Sets a SearchResultRanker to re-rank search results before they are // Sets a SearchResultRanker to re-rank non-app search results before they are
// published. // published.
void SetSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker); void SetNonAppSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker);
// Get a pointer to the SearchResultRanker owned by this object used for all
// non-app ranking.
SearchResultRanker* GetNonAppSearchResultRanker();
// Handle a training signal. // Handle a training signal.
void Train(const std::string& id, RankingItemType type); void Train(const std::string& id, RankingItemType type);
...@@ -88,7 +92,7 @@ class Mixer { ...@@ -88,7 +92,7 @@ class Mixer {
Groups groups_; Groups groups_;
// Adaptive models used for re-ranking search results. // Adaptive models used for re-ranking search results.
std::unique_ptr<SearchResultRanker> ranker_; std::unique_ptr<SearchResultRanker> non_app_ranker_;
DISALLOW_COPY_AND_ASSIGN(Mixer); DISALLOW_COPY_AND_ASSIGN(Mixer);
}; };
......
...@@ -51,10 +51,13 @@ SearchController::SearchController(AppListModelUpdater* model_updater, ...@@ -51,10 +51,13 @@ SearchController::SearchController(AppListModelUpdater* model_updater,
AppListControllerDelegate* list_controller, AppListControllerDelegate* list_controller,
Profile* profile) Profile* profile)
: mixer_(std::make_unique<Mixer>(model_updater)), : mixer_(std::make_unique<Mixer>(model_updater)),
ranker_(std::make_unique<AppSearchResultRanker>( app_ranker_(std::make_unique<AppSearchResultRanker>(
profile->GetPath(), profile->GetPath(),
chromeos::ProfileHelper::IsEphemeralUserProfile(profile))), chromeos::ProfileHelper::IsEphemeralUserProfile(profile))),
list_controller_(list_controller) {} list_controller_(list_controller) {
mixer_->SetNonAppSearchResultRanker(
std::make_unique<SearchResultRanker>(profile));
}
SearchController::~SearchController() {} SearchController::~SearchController() {}
...@@ -150,9 +153,12 @@ ChromeSearchResult* SearchController::GetResultByTitleForTest( ...@@ -150,9 +153,12 @@ ChromeSearchResult* SearchController::GetResultByTitleForTest(
return nullptr; return nullptr;
} }
void SearchController::SetSearchResultRanker( AppSearchResultRanker* SearchController::GetAppSearchResultRanker() {
std::unique_ptr<SearchResultRanker> ranker) { return app_ranker_.get();
mixer_->SetSearchResultRanker(std::move(ranker)); }
SearchResultRanker* SearchController::GetNonAppSearchResultRanker() {
return mixer_->GetNonAppSearchResultRanker();
} }
void SearchController::Train(const std::string& id, RankingItemType type) { void SearchController::Train(const std::string& id, RankingItemType type) {
...@@ -176,8 +182,4 @@ void SearchController::Train(const std::string& id, RankingItemType type) { ...@@ -176,8 +182,4 @@ void SearchController::Train(const std::string& id, RankingItemType type) {
mixer_->Train(id, type); mixer_->Train(id, type);
} }
AppSearchResultRanker* SearchController::GetSearchResultRanker() {
return ranker_.get();
}
} // namespace app_list } // namespace app_list
...@@ -54,16 +54,16 @@ class SearchController { ...@@ -54,16 +54,16 @@ class SearchController {
ChromeSearchResult* FindSearchResult(const std::string& result_id); ChromeSearchResult* FindSearchResult(const std::string& result_id);
ChromeSearchResult* GetResultByTitleForTest(const std::string& title); ChromeSearchResult* GetResultByTitleForTest(const std::string& title);
// Sets a SearchResultRanker to re-rank search results before they are
// published. The Mixer owned by the SearchController will take ownership of
// |ranker|.
void SetSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker);
// Sends training signal to each |providers_| // Sends training signal to each |providers_|
void Train(const std::string& id, RankingItemType type); void Train(const std::string& id, RankingItemType type);
// Get the app search result ranker owned by this object. // Gets the search result ranker owned by this object that is used for ranking
AppSearchResultRanker* GetSearchResultRanker(); // apps.
AppSearchResultRanker* GetAppSearchResultRanker();
// Gets the search result ranker owned by the Mixer that is used for all
// other ranking.
SearchResultRanker* GetNonAppSearchResultRanker();
private: private:
// Invoked when the search results are changed. // Invoked when the search results are changed.
...@@ -77,10 +77,10 @@ class SearchController { ...@@ -77,10 +77,10 @@ class SearchController {
// The query associated with the most recent search. // The query associated with the most recent search.
base::string16 last_query_; base::string16 last_query_;
std::unique_ptr<Mixer> mixer_;
using Providers = std::vector<std::unique_ptr<SearchProvider>>; using Providers = std::vector<std::unique_ptr<SearchProvider>>;
Providers providers_; Providers providers_;
std::unique_ptr<Mixer> mixer_; std::unique_ptr<AppSearchResultRanker> app_ranker_;
std::unique_ptr<AppSearchResultRanker> ranker_;
AppListControllerDelegate* list_controller_; AppListControllerDelegate* list_controller_;
DISALLOW_COPY_AND_ASSIGN(SearchController); DISALLOW_COPY_AND_ASSIGN(SearchController);
......
...@@ -75,7 +75,8 @@ std::unique_ptr<SearchController> CreateSearchController( ...@@ -75,7 +75,8 @@ std::unique_ptr<SearchController> CreateSearchController(
std::unique_ptr<SearchController> controller = std::unique_ptr<SearchController> controller =
std::make_unique<SearchController>(model_updater, list_controller, std::make_unique<SearchController>(model_updater, list_controller,
profile); profile);
AppSearchResultRanker* ranker = controller->GetSearchResultRanker();
AppSearchResultRanker* app_ranker = controller->GetAppSearchResultRanker();
// Add mixer groups. There are four main groups: answer card, apps // Add mixer groups. There are four main groups: answer card, apps
// and omnibox. Each group has a "soft" maximum number of results. However, if // and omnibox. Each group has a "soft" maximum number of results. However, if
...@@ -94,7 +95,7 @@ std::unique_ptr<SearchController> CreateSearchController( ...@@ -94,7 +95,7 @@ std::unique_ptr<SearchController> CreateSearchController(
controller->AddProvider(apps_group_id, std::make_unique<AppSearchProvider>( controller->AddProvider(apps_group_id, std::make_unique<AppSearchProvider>(
profile, list_controller, profile, list_controller,
base::DefaultClock::GetInstance(), base::DefaultClock::GetInstance(),
model_updater, ranker)); model_updater, app_ranker));
controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>( controller->AddProvider(omnibox_group_id, std::make_unique<OmniboxProvider>(
profile, list_controller)); profile, list_controller));
if (app_list_features::IsAnswerCardEnabled()) { if (app_list_features::IsAnswerCardEnabled()) {
...@@ -155,7 +156,7 @@ std::unique_ptr<SearchController> CreateSearchController( ...@@ -155,7 +156,7 @@ std::unique_ptr<SearchController> CreateSearchController(
controller->AddProvider( controller->AddProvider(
app_shortcut_group_id, app_shortcut_group_id,
std::make_unique<ArcAppShortcutsSearchProvider>( std::make_unique<ArcAppShortcutsSearchProvider>(
kMaxAppShortcutResults, profile, list_controller, ranker)); kMaxAppShortcutResults, profile, list_controller, app_ranker));
} }
// TODO(https://crbug.com/921429): Put feature switch in ash/public/app_list/ // TODO(https://crbug.com/921429): Put feature switch in ash/public/app_list/
...@@ -168,9 +169,6 @@ std::unique_ptr<SearchController> CreateSearchController( ...@@ -168,9 +169,6 @@ std::unique_ptr<SearchController> CreateSearchController(
std::make_unique<CrostiniRepositorySearchProvider>(profile)); std::make_unique<CrostiniRepositorySearchProvider>(profile));
} }
controller->SetSearchResultRanker(
std::make_unique<SearchResultRanker>(profile));
return controller; return controller;
} }
......
...@@ -49,7 +49,9 @@ Model ModelForType(RankingItemType type) { ...@@ -49,7 +49,9 @@ Model ModelForType(RankingItemType type) {
} // namespace } // namespace
SearchResultRanker::SearchResultRanker(Profile* profile) { SearchResultRanker::SearchResultRanker(Profile* profile)
: enable_zero_state_mixed_types_(
app_list_features::IsZeroStateMixedTypesRankerEnabled()) {
if (app_list_features::IsAdaptiveResultRankerEnabled()) { if (app_list_features::IsAdaptiveResultRankerEnabled()) {
RecurrenceRankerConfigProto config; RecurrenceRankerConfigProto config;
config.set_min_seconds_between_saves(240u); config.set_min_seconds_between_saves(240u);
...@@ -73,18 +75,40 @@ SearchResultRanker::SearchResultRanker(Profile* profile) { ...@@ -73,18 +75,40 @@ SearchResultRanker::SearchResultRanker(Profile* profile) {
} }
profile_ = profile; profile_ = profile;
if (auto* notifier = if (enable_zero_state_mixed_types_) {
file_manager::file_tasks::FileTasksNotifier::GetForProfile(profile_)) if (auto* notifier =
notifier->AddObserver(this); file_manager::file_tasks::FileTasksNotifier::GetForProfile(
/*file_tasks_observer_.Add( profile_)) {
file_manager::file_tasks::FileTasksNotifierFactory::GetInstance() notifier->AddObserver(this);
->GetForProfile(profile));*/ }
RecurrenceRankerConfigProto config;
config.set_min_seconds_between_saves(240u);
auto* predictor = config.mutable_zero_state_frecency_predictor();
predictor->set_target_limit(base::GetFieldTrialParamByFeatureAsInt(
app_list_features::kEnableZeroStateMixedTypesRanker, "target_limit",
200));
predictor->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble(
app_list_features::kEnableZeroStateMixedTypesRanker, "decay_coeff",
0.8f));
auto* fallback = config.mutable_fallback_predictor();
fallback->set_target_limit(200);
fallback->set_decay_coeff(0.8);
zero_state_mixed_types_ranker_ = std::make_unique<RecurrenceRanker>(
profile->GetPath().AppendASCII("zero_state_mixed_types_ranker.proto"),
config, chromeos::ProfileHelper::IsEphemeralUserProfile(profile));
}
} }
SearchResultRanker::~SearchResultRanker() { SearchResultRanker::~SearchResultRanker() {
if (auto* notifier = if (enable_zero_state_mixed_types_) {
file_manager::file_tasks::FileTasksNotifier::GetForProfile(profile_)) if (auto* notifier =
notifier->RemoveObserver(this); file_manager::file_tasks::FileTasksNotifier::GetForProfile(
profile_)) {
notifier->RemoveObserver(this);
}
}
} }
void SearchResultRanker::FetchRankings(const base::string16& query) { void SearchResultRanker::FetchRankings(const base::string16& query) {
...@@ -141,7 +165,15 @@ void SearchResultRanker::Train(const std::string& id, RankingItemType type) { ...@@ -141,7 +165,15 @@ void SearchResultRanker::Train(const std::string& id, RankingItemType type) {
void SearchResultRanker::OnFilesOpened( void SearchResultRanker::OnFilesOpened(
const std::vector<FileOpenEvent>& file_opens) { const std::vector<FileOpenEvent>& file_opens) {
// TODO(959679): route file open events to a model as training signals. if (enable_zero_state_mixed_types_) {
DCHECK(zero_state_mixed_types_ranker_);
for (const auto& file_open : file_opens)
zero_state_mixed_types_ranker_->Record(file_open.path.value());
}
}
RecurrenceRanker* SearchResultRanker::get_zero_state_mixed_types_ranker() {
return zero_state_mixed_types_ranker_.get();
} }
} // namespace app_list } // namespace app_list
...@@ -51,6 +51,8 @@ class SearchResultRanker : file_manager::file_tasks::FileTasksObserver { ...@@ -51,6 +51,8 @@ class SearchResultRanker : file_manager::file_tasks::FileTasksObserver {
// file_manager::file_tasks::FileTaskObserver: // file_manager::file_tasks::FileTaskObserver:
void OnFilesOpened(const std::vector<FileOpenEvent>& file_opens) override; void OnFilesOpened(const std::vector<FileOpenEvent>& file_opens) override;
RecurrenceRanker* get_zero_state_mixed_types_ranker();
private: private:
// Records the time of the last call to FetchRankings() and is used to // Records the time of the last call to FetchRankings() and is used to
// limit the number of queries to the models within a short timespan. // limit the number of queries to the models within a short timespan.
...@@ -68,13 +70,15 @@ class SearchResultRanker : file_manager::file_tasks::FileTasksObserver { ...@@ -68,13 +70,15 @@ class SearchResultRanker : file_manager::file_tasks::FileTasksObserver {
// affect apps. // affect apps.
std::unique_ptr<RecurrenceRanker> results_list_group_ranker_; std::unique_ptr<RecurrenceRanker> results_list_group_ranker_;
// Ranks files and previous queries for launcher zero-state.
std::unique_ptr<RecurrenceRanker> zero_state_mixed_types_ranker_;
// TODO(931149): Move the AppSearchResultRanker instance and associated logic // TODO(931149): Move the AppSearchResultRanker instance and associated logic
// to here. // to here.
Profile* profile_; Profile* profile_;
/*ScopedObserver<file_manager::file_tasks::FileTasksNotifier,
file_manager::file_tasks::FileTasksObserver> const bool enable_zero_state_mixed_types_;
file_tasks_observer_{this};*/
}; };
} // namespace app_list } // namespace app_list
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment