From 7cd526d61f0a45fd1b070a93c20b38343d281174 Mon Sep 17 00:00:00 2001 From: Christian Sutter Date: Sun, 19 Nov 2023 18:29:56 +0000 Subject: [PATCH] Add simple ability to define best bets "Best bets" allow boosting a specific set of results as much as possible for a given query string. Unlike with the previous search product, it's not possible to guarantee that this result will always be on top of the results - but it will get us close. - Add `best_bets.yml` configuration file to define best bets - Add ability to `DiscoveryEngine::Search` service to boost when a query matches a best bet, with slightly descending boost to allow for the definition of several best bets --- .../discovery_engine/best_bets_boost.rb | 14 ++++++ app/services/discovery_engine/search.rb | 6 ++- config/application.rb | 3 ++ config/best_bets.yml | 13 ++++++ spec/services/discovery_engine/search_spec.rb | 44 +++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 app/services/discovery_engine/best_bets_boost.rb create mode 100644 config/best_bets.yml diff --git a/app/services/discovery_engine/best_bets_boost.rb b/app/services/discovery_engine/best_bets_boost.rb new file mode 100644 index 0000000..e18b541 --- /dev/null +++ b/app/services/discovery_engine/best_bets_boost.rb @@ -0,0 +1,14 @@ +module DiscoveryEngine + module BestBetsBoost + def best_bets_boost_specs(query_string) + best_bets_for_query = Array(Rails.configuration.best_bets[query_string]) + return unless best_bets_for_query.any? + + condition_links = best_bets_for_query.map { "\"#{_1}\"" }.join(",") + [{ + boost: 1, + condition: "link: ANY(#{condition_links})", + }] + end + end +end diff --git a/app/services/discovery_engine/search.rb b/app/services/discovery_engine/search.rb index d1f4f2b..10a9f04 100644 --- a/app/services/discovery_engine/search.rb +++ b/app/services/discovery_engine/search.rb @@ -3,6 +3,7 @@ class Search DEFAULT_COUNT = 10 DEFAULT_START = 0 + include BestBetsBoost include NewsRecencyBoost def initialize(client: ::Google::Cloud::DiscoveryEngine.search_service(version: :v1)) @@ -18,7 +19,7 @@ def call(query_string, start: nil, count: nil) serving_config:, page_size: count, offset: start, - boost_spec:, + boost_spec: boost_spec(query_string), ).response ResultSet.new( @@ -36,10 +37,11 @@ def serving_config Rails.configuration.discovery_engine_serving_config end - def boost_spec + def boost_spec(query_string) { condition_boost_specs: [ *news_recency_boost_specs, + *best_bets_boost_specs(query_string), ], } end diff --git a/config/application.rb b/config/application.rb index f003ae3..2a39d1b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -25,5 +25,8 @@ class Application < Rails::Application config.document_type_ignorelist_path_overrides = config_for( :document_type_ignorelist_path_overrides, ) + + # Query configuration + config.best_bets = config_for(:best_bets) end end diff --git a/config/best_bets.yml b/config/best_bets.yml new file mode 100644 index 0000000..6100f68 --- /dev/null +++ b/config/best_bets.yml @@ -0,0 +1,13 @@ +shared: + # TODO: Test data that we can delete once demo'ed + "i want to test best bets": + - /government/people/test-person + - /government/publications/test--150 + - /service-manual/technology/test-your-services-performance + +test: + "i want to test a single best bet": /here/you/go + "i want to test multiple best bets": + - /i-am-important + - /i-am-also-important + - /also-me diff --git a/spec/services/discovery_engine/search_spec.rb b/spec/services/discovery_engine/search_spec.rb index b8b4891..ff71577 100644 --- a/spec/services/discovery_engine/search_spec.rb +++ b/spec/services/discovery_engine/search_spec.rb @@ -74,6 +74,50 @@ expect(result_set.start).to eq(11) end end + + context "when searching for a query that has a single best bets defined" do + # see test section in YAML config + subject!(:result_set) { search.call("i want to test a single best bet") } + + let(:expected_boost_specs) do + super() + [{ + boost: 1, + condition: 'link: ANY("/here/you/go")', + }] + end + + it "calls the client with the expected parameters" do + expect(client).to have_received(:search).with( + serving_config: "serving-config-path", + query: "i want to test a single best bet", + offset: 0, + page_size: 10, + boost_spec: { condition_boost_specs: expected_boost_specs }, + ) + end + end + + context "when searching for a query that has multiple best bets defined" do + # see test section in YAML config + subject!(:result_set) { search.call("i want to test multiple best bets") } + + let(:expected_boost_specs) do + super() + [{ + boost: 1, + condition: 'link: ANY("/i-am-important","/i-am-also-important","/also-me")', + }] + end + + it "calls the client with the expected parameters" do + expect(client).to have_received(:search).with( + serving_config: "serving-config-path", + query: "i want to test multiple best bets", + offset: 0, + page_size: 10, + boost_spec: { condition_boost_specs: expected_boost_specs }, + ) + end + end end end end