Skip to content

Commit

Permalink
Add graph_ldpath_mapper_service which uses ldpath to extract values i…
Browse files Browse the repository at this point in the history
…nstead of rdf query

Allows for a more complex query than simple `<s><p><o>`

NOTE: In this commit, the code still calls the original service that does predicate filtering using simple query.
  • Loading branch information
elrayle committed Apr 19, 2019
1 parent e45a072 commit ea65518
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 14 deletions.
49 changes: 49 additions & 0 deletions app/services/qa/linked_data/mapper/graph_ldpath_mapper_service.rb
@@ -0,0 +1,49 @@
# Provide service for mapping predicates to object values.
module Qa
module LinkedData
module Mapper
class GraphLdpathMapperService
class_attribute :ldpath_service
self.ldpath_service = Qa::LinkedData::LdpathService

# Extract values for ldpath specified in the ldpath_map from the graph and return as a value map for a single subject URI.
# @param graph [RDF::Graph] the graph from which to extract result values
# @param prefixes [Hash<Symbol><String>] URL map of prefixes to use with ldpaths
# @example prefixes
# {
# locid: 'http://id.loc.gov/vocabulary/identifiers/',
# skos: 'http://www.w3.org/2004/02/skos/core#',
# vivo: 'http://vivoweb.org/ontology/core#'
# }
# @param ldpath [Hash<Symbol><String||Symbol>] value either maps to a ldpath in the graph or is :subject_uri indicating to use the subject uri as the value
# @example ldpath map
# {
# uri: :subject_uri,
# id: 'locid:lccn :: xsd::string',
# label: 'skos:prefLabel :: xsd::string',
# altlabel: 'skos:altLabel :: xsd::string',
# sort: 'vivo:rank :: xsd::integer'
# }
# @param subject_uri [RDF::URI] the subject within the graph for which the values are being extracted
# @return [<Hash<Symbol><Array<Object>>] mapped result values with hash of map key = array of object values identified by the ldpath map.
# @example value map for a single result
# {:uri=>[#<RDF::URI:0x3fcff54a829c URI:http://id.loc.gov/authorities/names/n2010043281>],
# :id=>[#<RDF::Literal:0x3fcff4a367b4("n2010043281")>],
# :label=>[#<RDF::Literal:0x3fcff54a9a98("Valli, Sabrina"@en)>],
# :altlabel=>[],
# :sort=>[#<RDF::Literal:0x3fcff54b4c18("2")>]}
def self.map_values(graph:, ldpath_map:, subject_uri:, prefixes: {})
value_map = {}
ldpath_map.each do |key, ldpath|
next value_map[key] = [subject_uri] if ldpath == :subject_uri
ldpath_program = ldpath_service.ldpath_program(ldpath: ldpath, prefixes: prefixes)
values = ldpath_service.ldpath_evaluate(program: ldpath_program, graph: graph, subject_uri: subject_uri)
value_map[key] = values
end
value_map = yield value_map if block_given?
value_map
end
end
end
end
end
11 changes: 3 additions & 8 deletions app/services/qa/linked_data/mapper/graph_mapper_service.rb
Expand Up @@ -25,14 +25,9 @@ class GraphMapperService
# :label=>[#<RDF::Literal:0x3fcff54a9a98("Valli, Sabrina"@en)>],
# :altlabel=>[],
# :sort=>[#<RDF::Literal:0x3fcff54b4c18("2")>]}
def self.map_values(graph:, predicate_map:, subject_uri:)
value_map = {}
predicate_map.each do |key, predicate|
values = predicate == :subject_uri ? [subject_uri] : graph_service.object_values(graph: graph, subject: subject_uri, predicate: predicate)
value_map[key] = values
end
value_map = yield value_map if block_given?
value_map
def self.map_values(graph:, predicate_map:, subject_uri:, &block)
Qa.deprecation_warning(msg: "`Qa::LinkedData::Mapper::GraphMapperService` is deprecated; update to `GraphLdpathMapperService` (preferred) or `GraphPredicateMapperService`.")
Qa::LinkedData::Mapper::GraphPredicateMapperService.map_values(graph: graph, predicate_map: predicate_map, subject_uri: subject_uri, &block)
end
end
end
Expand Down
@@ -0,0 +1,40 @@
# Provide service for mapping predicates to object values.
module Qa
module LinkedData
module Mapper
class GraphPredicateMapperService
class_attribute :graph_service
self.graph_service = Qa::LinkedData::GraphService

# Extract predicates specified in the predicate_map from the graph and return as a value map for a single subject URI.
# @param graph [RDF::Graph] the graph from which to extract result values
# @param predicate_map [Hash<Symbol><String||Symbol>] value either maps to a predicate in the graph or is :subject_uri indicating to use the subject uri as the value
# @example predicate_map
# {
# uri: :subject_uri,
# id: [#<RDF::URI URI:http://id.loc.gov/vocabulary/identifiers/lccn>],
# label: [#<RDF::URI URI:http://www.w3.org/2004/02/skos/core#prefLabel>],
# altlabel: [#<RDF::URI URI:http://www.w3.org/2004/02/skos/core#altLabel>],
# sort: [#<RDF::URI URI:http://vivoweb.org/ontology/core#rank>]'
# }
# @param subject_uri [RDF::URI] the subject within the graph for which the values are being extracted
# @return [<Hash<Symbol><Array<Object>>] mapped result values with hash of map key = array of object values for predicates identified in predicate_map.
# @example value map for a single result
# {:uri=>[#<RDF::URI:0x3fcff54a829c URI:http://id.loc.gov/authorities/names/n2010043281>],
# :id=>[#<RDF::Literal:0x3fcff4a367b4("n2010043281")>],
# :label=>[#<RDF::Literal:0x3fcff54a9a98("Valli, Sabrina"@en)>],
# :altlabel=>[],
# :sort=>[#<RDF::Literal:0x3fcff54b4c18("2")>]}
def self.map_values(graph:, predicate_map:, subject_uri:)
value_map = {}
predicate_map.each do |key, predicate|
values = predicate == :subject_uri ? [subject_uri] : graph_service.object_values(graph: graph, subject: subject_uri, predicate: predicate)
value_map[key] = values
end
value_map = yield value_map if block_given?
value_map
end
end
end
end
end
Expand Up @@ -3,15 +3,32 @@ module Qa
module LinkedData
module Mapper
class SearchResultsMapperService
class_attribute :graph_mapper_service, :deep_sort_service, :context_mapper_service
self.graph_mapper_service = Qa::LinkedData::Mapper::GraphMapperService
class_attribute :graph_ldpath_mapper_service, :graph_predicate_mapper_service, :deep_sort_service, :context_mapper_service
self.graph_ldpath_mapper_service = Qa::LinkedData::Mapper::GraphLdpathMapperService
self.graph_predicate_mapper_service = Qa::LinkedData::Mapper::GraphMapperService
self.deep_sort_service = Qa::LinkedData::DeepSortService
self.context_mapper_service = Qa::LinkedData::Mapper::ContextMapperService

class << self
# Extract predicates specified in the predicate_map from the graph and return as an array of value maps for each search result subject URI.
# If a sort key is present, a subject will only be included in the results if it has a statement with the sort predicate.
# @param graph [RDF::Graph] the graph from which to extract result values
# @param prefixes [Hash<Symbol><String>] URL map of prefixes to use with ldpaths
# @example prefixes
# {
# locid: 'http://id.loc.gov/vocabulary/identifiers/',
# skos: 'http://www.w3.org/2004/02/skos/core#',
# vivo: 'http://vivoweb.org/ontology/core#'
# }
# @param ldpath [Hash<Symbol><String||Symbol>] value either maps to a ldpath in the graph or is :subject_uri indicating to use the subject uri as the value
# @example ldpath map
# {
# uri: :subject_uri,
# id: 'locid:lccn :: xsd::string',
# label: 'skos:prefLabel :: xsd::string',
# altlabel: 'skos:altLabel :: xsd::string',
# sort: 'vivo:rank :: xsd::integer'
# }
# @param predicate_map [Hash<Symbol><String||Symbol>] value either maps to a predicate in the graph or is :subject_uri indicating to use the subject uri as the value
# @example predicate map
# {
Expand All @@ -33,13 +50,15 @@ class << self
# :altlabel=>[],
# :sort=>[#<RDF::Literal:0x3fcff54b4c18("2")>]}
# ]
def map_values(graph:, predicate_map:, sort_key:, preferred_language: nil, context_map: nil)
def map_values(graph:, prefixes: {}, ldpath_map: nil, predicate_map: nil, sort_key:, preferred_language: nil, context_map: nil) # rubocop:disable Metrics/ParameterLists
search_matches = []
graph.subjects.each do |subject|
next if subject.anonymous? # skip blank nodes
values = graph_mapper_service.map_values(graph: graph, predicate_map: predicate_map, subject_uri: subject) do |value_map|
map_context(graph, sort_key, context_map, value_map, subject)
end
values = if ldpath_map.present?
map_values_with_ldpath_map(graph: graph, ldpath_map: ldpath_map, prefixes: prefixes, subject_uri: subject, sort_key: sort_key, context_map: context_map)
else
map_values_with_predicate_map(graph: graph, predicate_map: predicate_map, subject_uri: subject, sort_key: sort_key, context_map: context_map)
end
search_matches << values if result_subject? values, sort_key
end
search_matches = deep_sort_service.new(search_matches, sort_key, preferred_language).sort
Expand All @@ -63,6 +82,18 @@ def map_context(graph, sort_key, context_map, value_map, subject)
value_map[:context] = context
value_map
end

def map_values_with_ldpath_map(graph:, ldpath_map:, prefixes:, subject_uri:, sort_key:, context_map:) # rubocop:disable Metrics/ParameterLists
graph_ldpath_mapper_service.map_values(graph: graph, ldpath_map: ldpath_map, prefixes: prefixes, subject_uri: subject_uri) do |value_map|
map_context(graph, sort_key, context_map, value_map, subject_uri)
end
end

def map_values_with_predicate_map(graph:, predicate_map:, subject_uri:, sort_key:, context_map:)
graph_predicate_mapper_service.map_values(graph: graph, predicate_map: predicate_map, subject_uri: subject_uri) do |value_map|
map_context(graph, sort_key, context_map, value_map, subject_uri)
end
end
end
end
end
Expand Down
20 changes: 20 additions & 0 deletions lib/qa/authorities/linked_data/find_term.rb
Expand Up @@ -65,6 +65,26 @@ def parse_term_authority_response(id)
termhash
end

def ldpaths_for_term
{ required: required_term_ldpaths, optional: optional_term_ldpaths }
end

def required_term_ldpaths
label_ldpath = term_config.term_results_label_ldpath
raise Qa::InvalidConfiguration, "required label_ldpath is missing in configuration for LOD authority #{auth_name}" if label_ldpath.nil?
{ label: label_ldpath }
end

def optional_term_ldpaths
ldpaths = {}
ldpaths[:altlabel] = term_config.term_results_altlabel_ldpath unless term_config.term_results_altlabel_ldpath.nil?
ldpaths[:id] = term_config.term_results_id_ldpath unless term_config.term_results_id_ldpath.nil?
ldpaths[:narrower] = term_config.term_results_narrower_ldpath unless term_config.term_results_narrower_ldpath.nil?
ldpaths[:broader] = term_config.term_results_broader_ldpath unless term_config.term_results_broader_ldpath.nil?
ldpaths[:sameas] = term_config.term_results_sameas_ldpath unless term_config.term_results_sameas_ldpath.nil?
ldpaths
end

def preds_for_term
{ required: required_term_preds, optional: optional_term_preds }
end
Expand Down
21 changes: 21 additions & 0 deletions lib/qa/authorities/linked_data/search_query.rb
Expand Up @@ -51,6 +51,8 @@ def load_graph(url:)
def parse_search_authority_response
results = results_mapper_service.map_values(graph: @graph, predicate_map: preds_for_search, sort_key: :sort,
preferred_language: @language, context_map: context_map)
# results = results_mapper_service.map_values(graph: @graph, prefixes: search_config.prefixes, ldpath_map: ldpaths_for_search,
# sort_key: :sort, preferred_language: @language, context_map: context_map)
convert_results_to_json(results)
end

Expand All @@ -62,6 +64,25 @@ def context?
@context == true
end

def ldpaths_for_search
label_ldpath = search_config.results_label_ldpath
raise Qa::InvalidConfiguration, "required label_ldpath is missing in search configuration for LOD authority #{auth_name}" if label_ldpath.nil?
ldpaths = { label: label_ldpath }
ldpaths[:uri] = :subject_uri
ldpaths[:altlabel] = search_config.results_altlabel_ldpath unless search_config.results_altlabel_ldpath.nil?
ldpaths[:id] = id_ldpath.present? ? id_ldpath : :subject_uri
ldpaths[:sort] = sort_ldpath.present? ? sort_ldpath : ldpaths[:label]
ldpaths
end

def id_ldpath
@id_ldpath ||= search_config.results_id_ldpath
end

def sort_ldpath
@sort_ldpath ||= search_config.results_sort_ldpath
end

def preds_for_search
label_pred_uri = search_config.results_label_predicate
raise Qa::InvalidConfiguration, "required label_predicate is missing in search configuration for LOD authority #{auth_name}" if label_pred_uri.nil?
Expand Down

0 comments on commit ea65518

Please sign in to comment.