Skip to content

Commit

Permalink
Merge pull request #803 from MITLibraries/gdt-163-access-type-filters
Browse files Browse the repository at this point in the history
Gdt 163 access type filters
  • Loading branch information
JPrevost committed Mar 4, 2024
2 parents e3e7743 + e8ae14b commit 0b13697
Show file tree
Hide file tree
Showing 34 changed files with 860 additions and 875 deletions.
4 changes: 4 additions & 0 deletions app/graphql/types/aggregations_type.rb
Expand Up @@ -5,6 +5,10 @@ class AggregationCountType < Types::BaseObject
end

class AggregationsType < Types::BaseObject
field :access_to_files, [Types::AggregationCountType],
null: true,
description: 'Total seach results by access type (which is a Right with description `Access to files`). ' \
'This is only applicable to geospatial records at this time.'
field :format, [Types::AggregationCountType], null: true, description: 'Total search results by format'
field :content_type, [Types::AggregationCountType], null: true, description: 'Total search results by content type'
field :contributors, [Types::AggregationCountType], null: true,
Expand Down
8 changes: 8 additions & 0 deletions app/graphql/types/query_type.rb
Expand Up @@ -61,6 +61,12 @@ def record_id(id:, index:)
argument :source, String, required: false, default_value: 'All', deprecation_reason: 'Use `sourceFilter`'

# applied filters
argument :access_to_files_filter, [String],
required: false, default_value: nil,
description: 'Filter results by access type. Use the `AccessToFiles` ' \
'aggregation for a list of possible values. Multiple ' \
'values are ORed.'

argument :content_type_filter, [String], required: false, default_value: nil,
description: 'Filter results by content type. Use the `contentType` ' \
'aggregation for a list of possible values. Multiple ' \
Expand Down Expand Up @@ -134,6 +140,7 @@ def construct_query(searchterm, citation, contributors, funding_information, geo
query[:locations] = locations
query[:subjects] = subjects
query[:title] = title
query[:access_to_files_filter] = filters[:access_to_files_filter]
query[:collection_filter] = filters[:collection_filter]
query[:content_format_filter] = filters[:format_filter]
query[:content_type_filter] = filters[:content_type_filter]
Expand All @@ -156,6 +163,7 @@ def source_deprecation_handler(query, new_source, old_source)

def collapse_buckets(es_aggs)
{
access_to_files: es_aggs['access_to_files']['only_file_access']['access_types']['buckets'],
contributors: es_aggs['contributors']['contributor_names']['buckets'],
source: es_aggs['source']['buckets'],
subjects: es_aggs['subjects']['subject_names']['buckets'],
Expand Down
3 changes: 3 additions & 0 deletions app/graphql/types/record_type.rb
Expand Up @@ -185,6 +185,9 @@ class RecordType < Types::BaseObject
'publication'
field :highlight, [Types::HighlightType], null: true, description: 'Search term matches in item metadata'
field :score, String, null: true, description: 'Search relevance'
field :provider, String,
null: true,
description: 'The host institution for a resource. Currently only used for geospatial records'

def in_bibliography
@object['related_items']&.map { |i| i['uri'] if i['relationship'] == 'IsCitedBy' }&.compact
Expand Down
27 changes: 27 additions & 0 deletions app/models/aggregations.rb
Expand Up @@ -4,6 +4,7 @@ class Aggregations
# https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
def self.all
{
access_to_files:,
contributors:,
content_type:,
content_format:,
Expand All @@ -15,6 +16,32 @@ def self.all
}
end

def self.access_to_files
{
nested: {
path: 'rights'
},
aggs: {
only_file_access: {
filter: {
terms: {
'rights.kind': [
'Access to files'
]
}
},
aggs: {
access_types: {
terms: {
field: 'rights.description.keyword'
}
}
}
}
}
}
end

def self.contributors
{
nested: {
Expand Down
28 changes: 28 additions & 0 deletions app/models/opensearch.rb
Expand Up @@ -218,6 +218,9 @@ def filters(params)
# source aggregation is "OR" and not "AND" so it does not use the filter_field_by_value method
f.push filter_sources(params[:source_filter]) if params[:source_filter]

# access to files aggregation is "OR" and not "AND" so it does not use the filter_field_by_value method
f.push filter_access_to_files(params[:access_to_files_filter]) if params[:access_to_files_filter]

if params[:subjects_filter].present?
params[:subjects_filter].each do |p|
f.push filter_field_by_value('subjects.value.keyword', p)
Expand All @@ -233,6 +236,31 @@ def filter_field_by_value(field, value)
}
end

# multiple access to files values are ORd
def filter_access_to_files(param)
{ nested: {
path: 'rights',
query: {
bool: {
should: access_to_files_array(param)
}
}
} }
end

def access_to_files_array(param)
rights = []
param.each do |right|
rights << {
term: {
'rights.description.keyword': right
}
}
end
rights
end

# multiple sources values are ORd
def filter_sources(param)
{
bool: {
Expand Down
12 changes: 6 additions & 6 deletions test/controllers/graphql_controller_test.rb
Expand Up @@ -104,7 +104,7 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
}' }
assert_equal(200, response.status)
json = JSON.parse(response.body)
assert_equal('32.201416', json['data']['search']['records'].first['score'])
assert_equal('32.326054', json['data']['search']['records'].first['score'])
end
end
end
Expand Down Expand Up @@ -166,7 +166,7 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
}' }
assert_equal(200, response.status)
json = JSON.parse(response.body)
assert(json['data']['search']['records'].first['contributors'].any? { |c| c.value? 'Kim, Moon S. (Moon Sung)' })
assert(json['data']['search']['records'].first['contributors'].any? { |c| c.value? 'Kim, Moon H. (Moon Ho)' })
end
end
end
Expand Down Expand Up @@ -482,7 +482,7 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
assert_equal('mit alma',
json['data']['search']['aggregations']['source']
.first['key'])
assert_equal(160_288,
assert_equal(208_361,
json['data']['search']['aggregations']['source']
.first['docCount'])
end
Expand All @@ -509,7 +509,7 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
assert_equal('mit alma',
json['data']['search']['aggregations']['source']
.first['key'])
assert_equal(1_399_825,
assert_equal(1_636_808,
json['data']['search']['aggregations']['source']
.first['docCount'])
end
Expand All @@ -536,7 +536,7 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
assert_equal('mit alma',
json['data']['search']['aggregations']['source']
.first['key'])
assert_equal(1_399_825,
assert_equal(1_636_808,
json['data']['search']['aggregations']['source']
.first['docCount'])
end
Expand Down Expand Up @@ -574,7 +574,7 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
}' }
assert_equal(200, response.status)
json = JSON.parse(response.body)
assert_equal(234, json['data']['search']['hits'])
assert_equal(225, json['data']['search']['hits'])
end
end
end
Expand Down
19 changes: 19 additions & 0 deletions test/models/opensearch_test.rb
Expand Up @@ -128,6 +128,25 @@ class OpensearchTest < ActiveSupport::TestCase
assert_equal(expected, Opensearch.new.filter_sources(sources))
end

test 'access_to_files_array creates correct query structure' do
rights = ['MIT authentication', 'Free/open to all']
expected = [{ term: { 'rights.description.keyword': 'MIT authentication' } },
{ term: { 'rights.description.keyword': 'Free/open to all' } }]

assert_equal(expected, Opensearch.new.access_to_files_array(rights))
end

test 'filter_access_to_files creates correct query structure' do
sources = ['MIT authentication', 'Free/open to all']
expected = { nested: { path: 'rights',
query: { bool: { should: [
{ term: { 'rights.description.keyword': 'MIT authentication' } },
{ term: { 'rights.description.keyword': 'Free/open to all' } }
] } } } }

assert_equal(expected, Opensearch.new.filter_access_to_files(sources))
end

test 'filter_field_by_value query structure' do
expected = {
term: { fakefield: 'i am a fake value' }
Expand Down
22 changes: 12 additions & 10 deletions test/vcr_cassettes/graphql_apply_multiple_content_types_filters.yml

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 12 additions & 10 deletions test/vcr_cassettes/graphql_filter_multiple_sources.yml

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions test/vcr_cassettes/graphql_filter_single_source.yml

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions test/vcr_cassettes/graphql_geobox.yml

Large diffs are not rendered by default.

0 comments on commit 0b13697

Please sign in to comment.