diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 573844c..3950b8d 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -54,6 +54,8 @@ def record_id(id:, index:) argument :title, String, required: false, default_value: nil, description: 'Search by title' argument :from, String, required: false, default_value: '0', description: 'Search result number to begin with (the first result is 0)' + argument :fulltext, Boolean, required: false, default_value: false, + description: 'Include fulltext field in search? Defaults to false.' argument :index, String, required: false, default_value: nil, description: 'It is not recommended to provide an index value unless we have provided ' \ 'you with one for your specific use case' @@ -99,11 +101,11 @@ def record_id(id:, index:) end def search(searchterm:, citation:, contributors:, funding_information:, geodistance:, geobox:, identifiers:, - locations:, subjects:, title:, index:, source:, from:, boolean_type:, **filters) + locations:, subjects:, title:, index:, source:, from:, boolean_type:, fulltext:, **filters) query = construct_query(searchterm, citation, contributors, funding_information, geodistance, geobox, identifiers, locations, subjects, title, source, boolean_type, filters) - results = Opensearch.new.search(from, query, Timdex::OSClient, highlight_requested?, index) + results = Opensearch.new.search(from, query, Timdex::OSClient, highlight_requested?, index, fulltext) response = {} response[:hits] = results['hits']['total']['value'] diff --git a/app/models/opensearch.rb b/app/models/opensearch.rb index 996def4..6aeb27f 100644 --- a/app/models/opensearch.rb +++ b/app/models/opensearch.rb @@ -4,14 +4,20 @@ class Opensearch SIZE = 20 MAX_PAGE = 200 - def search(from, params, client, highlight = false, index = nil) + def search(from, params, client, highlight = false, index = nil, fulltext = false) @params = params @highlight = highlight + @fulltext = fulltext?(fulltext) index = default_index unless index.present? client.search(index:, body: build_query(from)) end + # Only treat fulltext as true if it is boolean true or the string 'true' (case insensitive) + def fulltext?(fulltext_param) + fulltext_param == true || fulltext_param.to_s.downcase == 'true' + end + def default_index ENV.fetch('OPENSEARCH_INDEX', nil) end @@ -132,15 +138,23 @@ def minimum_should_match end end + # Fields to be searched in multi_match query. Adds 'fulltext' field if fulltext search is enabled. + def fields_to_search + fields = ['alternate_titles', 'call_numbers', 'citation', 'contents', 'contributors.value', 'dates.value', + 'edition', 'funding_information.*', 'identifiers.value', 'languages', 'locations.value', + 'notes.value', 'numbering', 'publication_information', 'subjects.value', 'summary', 'title'] + fields << 'fulltext' if @fulltext + + fields + end + def matches m = [] if @params[:q].present? m << { multi_match: { query: @params[:q].downcase, - fields: ['alternate_titles', 'call_numbers', 'citation', 'contents', 'contributors.value', 'dates.value', - 'edition', 'funding_information.*', 'identifiers.value', 'languages', 'locations.value', - 'notes.value', 'numbering', 'publication_information', 'subjects.value', 'summary', 'title'], + fields: fields_to_search, minimum_should_match: } } diff --git a/test/models/opensearch_test.rb b/test/models/opensearch_test.rb index f5173ef..7f4b89f 100644 --- a/test/models/opensearch_test.rb +++ b/test/models/opensearch_test.rb @@ -86,6 +86,21 @@ class OpensearchTest < ActiveSupport::TestCase end end + test 'fulltext is included when requested' do + os = Opensearch.new + os.instance_variable_set(:@params, { q: 'this' }) + os.instance_variable_set(:@fulltext, true) + + assert(os.matches.to_json.include?('"fields":["alternate_titles","call_numbers","citation","contents","contributors.value","dates.value","edition","funding_information.*","identifiers.value","languages","locations.value","notes.value","numbering","publication_information","subjects.value","summary","title","fulltext"]')) + end + + test 'fulltext is not included by default' do + os = Opensearch.new + os.instance_variable_set(:@params, { q: 'this' }) + + assert(os.matches.to_json.include?('"fields":["alternate_titles","call_numbers","citation","contents","contributors.value","dates.value","edition","funding_information.*","identifiers.value","languages","locations.value","notes.value","numbering","publication_information","subjects.value","summary","title"]')) + end + test 'searches a single field' do VCR.use_cassette('opensearch single field') do params = { title: 'spice it up' }