diff --git a/.codeclimate.yml b/.codeclimate.yml index 97cfe73..af1f8ad 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,4 +1,5 @@ plugins: rubocop: enabled: true - channel: rubocop-1-23-0 + channel: rubocop-1-56-3 + diff --git a/.rubocop.yml b/.rubocop.yml index 0c7fa89..02229bd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.1 NewCops: enable Exclude: - "db/**/*" diff --git a/app/models/opensearch.rb b/app/models/opensearch.rb index ca70c69..e533f79 100644 --- a/app/models/opensearch.rb +++ b/app/models/opensearch.rb @@ -6,7 +6,7 @@ def search(from, params, client, highlight = false, index = nil) @params = params @highlight = highlight index = default_index unless index.present? - client.search(index: index, + client.search(index:, body: build_query(from)) end @@ -17,10 +17,10 @@ def default_index # Construct the json query to send to elasticsearch def build_query(from) query_hash = { - from: from, + from:, size: SIZE, - query: query, - aggregations: aggregations + query:, + aggregations: } query_hash[:highlight] = highlight if @highlight @@ -109,9 +109,30 @@ def matches match_single_field_nested(:identifiers, m) match_single_field_nested(:locations, m) match_single_field_nested(:subjects, m) + + match_geodistance(m) if @params[:geodistance].present? m end + def match_geodistance(match_array) + match_array << { + bool: { + must: { + match_all: {} + }, + filter: { + geo_distance: { + distance: @params[:geodistance][:distance], + 'locations.geoshape': { + lat: @params[:geodistance][:latitude], + lon: @params[:geodistance][:longitude] + } + } + } + } + } + end + # https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html def filters(params) f = [] @@ -177,7 +198,7 @@ def source_array(param) param.each do |source| sources << { term: { - source: source + source: } } end diff --git a/test/models/opensearch_test.rb b/test/models/opensearch_test.rb index 9937c97..39d1870 100644 --- a/test/models/opensearch_test.rb +++ b/test/models/opensearch_test.rb @@ -4,43 +4,50 @@ class OpensearchTest < ActiveSupport::TestCase test 'matches citation' do os = Opensearch.new os.instance_variable_set(:@params, { citation: 'foo' }) - assert os.matches.select { |m| m[:citation] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"citation":"foo"}}')) end test 'matches title' do os = Opensearch.new os.instance_variable_set(:@params, { title: 'foo' }) - assert os.matches.select { |m| m[:title] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"title":"foo"}}')) end test 'matches contributors' do os = Opensearch.new os.instance_variable_set(:@params, { contributors: 'foo' }) - assert os.matches.select { |m| m['contributors.value'] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"contributors.value":"foo"}}')) end test 'matches funding_information' do os = Opensearch.new os.instance_variable_set(:@params, { funding_information: 'foo' }) - assert os.matches.select { |m| m['funding_information.funder_name'] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"funding_information.funder_name":"foo"}}')) end test 'matches identifiers' do os = Opensearch.new os.instance_variable_set(:@params, { identifiers: 'foo' }) - assert os.matches.select { |m| m['identifiers.value'] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"identifiers.value":"foo"}}')) end test 'matches locations' do os = Opensearch.new os.instance_variable_set(:@params, { locations: 'foo' }) - assert os.matches.select { |m| m['locations.value'] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"locations.value":"foo"}}')) end test 'matches subjects' do os = Opensearch.new os.instance_variable_set(:@params, { subjects: 'foo' }) - assert os.matches.select { |m| m['subjects.value'] == 'foo' } + + assert(os.matches.to_json.include?('{"match":{"subjects.value":"foo"}}')) end test 'matches everything' do @@ -48,15 +55,15 @@ class OpensearchTest < ActiveSupport::TestCase os.instance_variable_set(:@params, { q: 'this', citation: 'here', title: 'is', contributors: 'a', funding_information: 'real', identifiers: 'search', locations: 'rest', subjects: 'assured,' }) - matches = os.matches - assert matches.select { |m| m[:q] == 'this' } - assert matches.select { |m| m[:citation] == 'here' } - assert matches.select { |m| m[:title] == 'is' } - assert matches.select { |m| m['contributors.value'] == 'a' } - assert matches.select { |m| m['funding_information.funder_name'] == 'real' } - assert matches.select { |m| m['identifiers.value'] == 'search' } - assert matches.select { |m| m['locations.value'] == 'rest' } - assert matches.select { |m| m['subjects.value'] == 'assured' } + + assert(os.matches.to_json.include?('{"multi_match":{"query":"this","fields":')) + assert(os.matches.to_json.include?('{"match":{"citation":"here"}}')) + assert(os.matches.to_json.include?('{"match":{"title":"is"}}')) + assert(os.matches.to_json.include?('{"match":{"contributors.value":"a"}}')) + assert(os.matches.to_json.include?('{"match":{"funding_information.funder_name":"real"}}')) + assert(os.matches.to_json.include?('{"match":{"identifiers.value":"search"}}')) + assert(os.matches.to_json.include?('{"match":{"locations.value":"rest"}}')) + assert(os.matches.to_json.include?('{"match":{"subjects.value":"assured,"}}')) end test 'can override index' do @@ -266,4 +273,27 @@ class OpensearchTest < ActiveSupport::TestCase refute(os.build_query(0).include?('highlight')) end + + test 'can search by geopoint' do + os = Opensearch.new + os.instance_variable_set(:@params, + { geodistance: { latitude: '42.361145', longitude: '-71.057083', distance: '50mi' } }) + + assert( + os.query.to_json.include?('{"distance":"50mi","locations.geoshape":{"lat":"42.361145","lon":"-71.057083"}}') + ) + end + + test 'can search for combination of geopoint and keyword' do + os = Opensearch.new + os.instance_variable_set(:@params, + { geodistance: { latitude: '42.361145', longitude: '-71.057083', distance: '50mi' }, + q: 'rail stations' }) + + assert(os.matches.to_json.include?('{"multi_match":{"query":"rail stations","fields":')) + + assert( + os.query.to_json.include?('{"distance":"50mi","locations.geoshape":{"lat":"42.361145","lon":"-71.057083"}}') + ) + end end