Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eager by Default #13

Open
emmx opened this issue Sep 10, 2013 · 11 comments
Open

Eager by Default #13

emmx opened this issue Sep 10, 2013 · 11 comments

Comments

@emmx
Copy link

emmx commented Sep 10, 2013

What's the correct way to retrieve an object and all its related resources through a predicate like in:

person = Person.all.resources.first
friends = person.knows

puts firends.first.name  # This is what doesn't work because friends.first is a RDF::URI actually

I've think of a couple of ways in which it could be done but all of them requires more than one or two queries. I haven't find a way to get all at once.

How do you do that using Tripod?

Thank you.

@RicSwirrl
Copy link
Member

Hi there. Thanks for the question.

At the moment, a field will always return a uri or a literal.

I've been getting collections of resources of the relevant type by just creating extra methods on my models, and using Resource.where... or Resource.find_by_sparql in those methods to return collections of objects.

This is something I'd like to add though.

@fonji
Copy link

fonji commented Sep 19, 2013

Hello!
Just adding support to this issue.
Nice request, Matt!

@RicSwirrl
Copy link
Member

I've built a first draft of this in the links branch.

Check out links.rb for details. And there's some example uses in the spec/app/models.

@emmx
Copy link
Author

emmx commented Sep 26, 2013

I've tried the new features and it works pretty well! Now I'm going to change all my models to see how it works in a real application. More comments soon..

I've to say I found the names of the functions (linked_from and linked_to) a little bit confusing. If I'm not wrong the equivalent in ActiveRecord is has_one and belongs_to, respectively. Well, I find their functions clearer, specially given that you don't have to use "multivalued: true", it's implicit in the function you choose (has_one vs has_many for example).

@RicSwirrl
Copy link
Member

Hi. I see what you're saying regarding the method names, and I did originally consider that.

My reasoning here is that I wanted make it clear that this behaved differently to Active Record as it's RDF/Linked Data.

For example in Active Record, has_many indicates that the foreign key field is on the target class/table, but with RDF it would be the other way round. For linked_to with multivalued:true, we're saying that there are lots of triples with this class/model/type of resource as the subject, and the target type as the object. And it also set us up nicely to have a symmetric linked_from method.

When you're thinking in terms of RDF/Linked Data it made more sense (to me at least) to have linked_to/from rather than has_many/has_one/belongs to. It stops you thinking in terms of tables, prevents you from having to do an in-your-head translation of the terms each time you use it.

I guess this is sort of similar to mongoid's approach for embeds_in and embedded_in methods in that they describe how the data is stored.

@emmx
Copy link
Author

emmx commented Sep 26, 2013

Yeah, you're right. There are some differences and it could be a good idea to use another name to make it clear. Still, consider the following model using ActiveRecord:

class Person < ...
   has_many :houses
end

class House < ...
   belongs_to :person
end

What I think we -normally- do in Rails to create instances is something like this:

p = Person.new

h1 = House.new
h2 = House.new
h3 = House.new

p.houses.push h1
p.houses.push h2
p.houses.push h3

(same idea if you use .create instead to save time)

This is in fact completely equivalent to the way you would do that in RDF:

:P a :Person.

:H1 a :House.
:H2 a :House.
:H3 a :House.

:P :hasHouse :H1.
:P :hasHouse :H2.
:P :hasHouse :H3.

So, the way you think about the relation is not completely different, I would say it's pretty similar if not the same.

has_many implies the foreign key is on the target table, but that doesn't mean you think about the relation as a link from House to Person (even if it is). That depends on your use case and how you're going to use it / write your code (in fact the belongs_to line is not necessary at all in your models and you could have used :isHouseOf and write the example the other way around in RDF!).

That's why I find it intuitive to use has_many instead of "linked_to ..., multivalued: true", even if we're talking about RDF/LinkedData. It's less cumbersome too :)

@RicSwirrl
Copy link
Member

Cheers. I'll ponder this a bit :)

@fonji
Copy link

fonji commented Sep 27, 2013

Hello,

I also tried this branch (and merged it in my fork).
It works pretty well (thanks!) while both objects have the same class, but I think I did something wrong when trying to use another one. If my code is correct then it means that I shouldn't use rails 4 or OpenRDF's Sesame... or find out what's not compatible and patch it.
I didn't have much time to investigate yet. I'll try to find some today. I'll add some code in another issue if you'd like to take some time to review it, to avoid polluting the thread.

I didn't make my mind about the "linked_to ..., multivalued: true" vs "has_many" yet. As I work with a multitree I think that "linked_from ..., multivalued: true" is nice. I would need a "belongs_to_many" or something similar otherwise.
To be clear, I work in healthcare research. In the disorders classifications, a disorder has multiple "children" (to narrow the diagnosis) and multiple parents (multiple path may direct you to the same disorder).
So it doesn't make sense to have a belong_to[one] for a disorder.
I hope I didn't make the decision process worse ;)

Cheers

@RicSwirrl
Copy link
Member

It should work ok with other classes. If it doesn't, then there's a bug so please raise an issue :)

Sent from my iPhone

On 27 Sep 2013, at 08:46, Yannick Fonjallaz notifications@github.com wrote:

Hello,

I also tried this branch (and merged it in my fork).
It works pretty well (thanks!) while both objects have the same class, but I think I did something wrong when trying to use another one. If my code is correct then it means that I shouldn't use rails 4 or OpenRDF's Sesame... or find what's not compatible and patch it.
I didn't have much time to investigate yet. I'll try to find some today. I'll add some code in another issue if you'd like to take some time to review it, to avoid polluting the thread.

I didn't make my mind about the "linked_to ..., multivalued: true" vs "has_many" yet. As I work with a multitree I think that "linked_from ..., multivalued: true" is nice. I would need a "belongs_to_many" or something similar otherwise.
To be clear, I work in healthcare research. In the disorders classifications, a disorder has multiple "children" (to narrow the diagnosis) and multiple parents (multiple path may direct you to the same disorder).
So it doesn't make sense to have a belong_to[one] for a disorder.
I hope I didn't make the decision process worse ;)

Cheers


Reply to this email directly or view it on GitHub.

@emmx
Copy link
Author

emmx commented Sep 29, 2013

Ok, I'm almost done updating my models. I thought it was a good idea to come and comment something I found (and made me spent a couple of hours trying to understand).

linked_from doesn't create a new relationship, it just adds a getter to find all As given one B (ie, it assumes the association is n_A to 1_B or n_A to n_B (using multivalued), even if it could be 1_A to 1_B or 1_A to n_B, respectively.

I don't know if it was your intention or if it's a bug, but here I wrote two models that are NOT equivalent to show what I mean:

# MODEL 1 - WHAT I DID BY MISTAKE (n_A to 1_B)

class Person
    linked_to :house, 'http://example.com/#hasHouse'
end

class House
    linked_from :owner, :house, class_name: 'Person'
end

Here _jonh.house.class == House, but _jonh.house.owner.class == ResourceCollection

Now check this one, which is what I was looking for:

# MODEL 2 - WHAT I INTENDED TO DO (1_A to 1_B)

class Person
    linked_to :house, 'http://example.com/#hasHouse'
end

class House
    linked_to :owner, 'http://example.com/#isHouseOf', class_name: 'Person'
end

Here _jonh.house.class == House, and _jonh.house.owner.class == Person

If you want to have a 1-to-1 association and be able to go from both A to B and B to A, the second approach is the correct one (same for 1-to-n), but for that you must define in your ontology the inverse property of whatever property you're interested in.

Please let me know if I'm wrong or if it's a bug that is going to be fixed in the future!

Thanks,
Matt

@emmx
Copy link
Author

emmx commented Sep 29, 2013

Regarding my last post, due to the same reason there are a couple of things I couldn't do..

Let's assume:

  • The domain of :hasSchool is City UNION University
  • If you have C :hasUniversity U, and U :hasSchool S, then C :hasSchool S (ie, it's chainable).

Take this example:

class City
    linked_to :universities, 'hasUniversity'
end

class University
    linked_to :colleges, 'hasCollege'
end

class College
    # FIXME This is wrong, :isCollegeOf is going to have instances of both Universities AND Cities
    linked_to :university, 'isCollegeOf', class_name: 'University'

    # FIXME This is better but still wrong, I don't want a ResourceCollection, I want a single University
    linked_from :university, :colleges, class_name: 'University'
end

I still couldn't figure out a way to fix it. I hope linked_from is not supposed to work in the way it does right now :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants