Graph Oriented Objects for Ruby (Goo)
Goo is a Ruby library that provides ORM-alike capabilities to interact with RDF/SPARQL backends. Goo provides a DSL for defining schemas for objects and controls how they get validated, serialized, saved, and retrieved from the triplestore. Using RDF and SPARQL for large-scale applications creates challenges in terms of scalability and technology adoption. We designed Goo with two main objectives:
Goo abstracts SPARQL so developers do not need to be SPARQL experts to handle large RDF graphs efficiently.
Goo is designed to serve BioPortal growing REST traffic. BioPortal's REST API provides access to hundreds of millions of Biomedical artifacts. Scalability and efficiency is at the core of Goo's design.
Source code see: https://github.com/ncbo/goo
How to use
Github documentation see: http://ncbo.github.io/goo/
Examples
Example: getting a user and editing it
Using bin/ncbo_cron --console
user = LinkedData::Models::User.find("admin").first
user.bring_remaining
user.password=("my_password")
user.valid?
user.saveExample: get all mappings
LinkedData::Models::Mappings.all.include(:id, :source, :classes)
#Get all mappings with all attributes
LinkedData::Models::RestBackupMapping.all
.include(LinkedData::Models::RestBackupMapping.attributes(:all)).each do |m|
puts m.id.to_s
end
#Get and delete all mappings
LinkedData::Models::RestBackupMapping.all.each do |m|
puts m.id.to_s
mapping_id = RDF::URI.new(m.id.to_s)
puts LinkedData::Mappings.delete_rest_mapping(mapping_id)
endExample: get a slice and edit it
# Retrieve an ontology
ont = LinkedData::Models::Ontology.find("STY").first
sub =
ont = LinkedData::Models::Ontology.find("STY").include(LinkedData::Models::Ontology.attributes(:all)).first
# Retrieve all submissions of ont
sub = LinkedData::Models::OntologySubmission.where(ontology: ont).include(:submissionId).include(:submissionStatus).all
# Retrieve a submission of ont1 including all its attributes
sub = LinkedData::Models::OntologySubmission.where(ontology: ont).include(LinkedData::Models::OntologySubmission.attributes(:all)).first
# Retrive latest submission and bring all properties
sub = ont.latest_submission
sub.bring_remaining
sub.ontology.bring_remaining
# Retrieve a slice
slice = LinkedData::Models::Slice.find("umls").include(:acronym, :name, :ontologies).first
# To include all attributes:
slice = LinkedData::Models::Slice.find("umls")
.include(LinkedData::Models::Slice.attributes(:all))
.first
# Change the name
slice.name = "test"
# Change the ontologies of this slice
slice.ontologies = [ont]
# Save the changes
if slice.valid?
slice.save
end
# Display errors
slice.errorsHow it works
Model set up
Model settings
TODO see https://github.com/ncbo/goo/blob/master/lib/goo/base/resource.rb
Model attributes
# Get all attributes of a model
LinkedData::Models::OntologySubmission.attributes(:all)
# Get the settings of an attribute
LinkedData::Models::OntologySubmission.attribute_settings(:naturalLanguage)
# Returns the following JSON object
{:namespace=>:omv, :enforce=>[:list]}
# Get the value of an attribute?
# In OntologySubmission.rb
self.naturalLanguage = "en"Generating SPARQL queries
There are 7 types of generated queries
Include/unmapped/general query
SELECT DISTINCT ?id ?attributeProperty ?attributeObject
FROM <graph_i> # for each graph from 1..n
WHERE {
?id a <type_uri> .
OPTIONAL {
{ ?id <attribute_1_uri> ?attributeObject . BIND("var_1" as ?attributeProperty) }
UNION
....
UNION
{ ?attributeObject <attribute_j_uri> ?id . BIND( "var_j" as ?attributeProperty)} # if attribute_j_uri is an inverse attribute
UNION
....
{ ?id <attribute_n_uri> ?attributeObject . BIND("var_n" as ?attributeProperty) }
}
FILTER(?id = <id_uri>)
}Aggregate query
TODO
BNODE query
SELECT DISTINCT ?id ?line1 ?line2
FROM <http://goo.org/default/PersonPersistent>
WHERE {
?id a <http://goo.org/default/PersonPersistent> .
?id <http://goo.org/default/contact_data> _:g64460 .
_:g64460 <http://goo.org/default/line1> ?line1.
_:g64460 <http://goo.org/default/line2> ?line2 .
FILTER(?id = <http://goo.org/default/person_persistent/Lewis> || ?id = <http://goo.org/default/person_persistent/John>) }FILTER query (test/test_where#test_filter)
SELECT DISTINCT ?id ?attributeProperty ?attributeObject
FROM <graph>
WHERE {
?id a <type_uri> .
?id <attribute_uri> ?internal_join_var_0 . #can alos be optional
FILTER(?internal_join_var_0 > "var")
}ORDER BY query
SELECT DISTINCT ?id ?attributeProperty ?attributeObject
FROM <graph>
WHERE {
?id a <type_uri> .
?id <attribute_uri> ?internal_join_var_0 . #can also be optional
}
ORDER BY ?internal_join_var_0Equivalent predicates case
see def self*.expand_equivalent_predicates(query, eq_p)
SELECT DISTINCT ?id ?attributeProperty ?attributeObject
FROM <graph_i>
WHERE {
?id a <type_uri> .
OPTIONAL {
{?id <equivalent_uri_1> ?attributeObject . BIND( "var_1" as ?attributeProperty)) }
UNION
...
UNION
{?id <equivalent_uri_2> ?attributeObject . BIND( "var_1" as ?attributeProperty)) }
...
}