On Tuesday, December 3, 2013 2:38:35 PM UTC-6, Jeremy Evans wrote:
>
> On Mon, Dec 2, 2013 at 9:00 PM, Nels Nelson wrote:
>
>> Thank you!  I completely failed to find that in the docs.  I'm sure it's 
>> there, and I just missed it.  It is exactly ideal, and it works perfectly.
>>
>
> Great!
>

Oops, I spoke too soon.  So, the after_load method applies exclusively to 
the artist node's albums association after the album association loads, and 
is defined with a proc on the association definition.  What I really need 
is something that runs after the artist node loads, and then iterates over 
the album association members for that node.  Removing the 
after_initializemethod and instead trying to use the 
after_load method on the album association resulted only in my custom code 
not getting invoked at all, resulting in the perceived performance 
improvement.


[...] only the main model instance seems to get loaded into cache, and none 
>> of its non-rcte tree associations -- that is, ideally I would prefer that 
>> the non-child many-to-many associations get automatically loaded along with 
>> the model instance.
>>
>
> I'm not exactly sure what you are describing (example code would help). 
>  Is it that the model instance is cached without any associations, or 
> cached with some associations and not others (even though those 
> associations were present in @associations at time of caching), or that in 
> the uncached case @associations is not prepopulated with some associations 
> that you want to be prepopulated.
>  
>
>>
>> use Dataset#eager on the dataset that creates the objects, or the 
>>> tactical_eager_loading plugin, in conjuction with Dataset#all to load the 
>>> objects.
>>>
>>
>> Is it possible to do this automatically? [*] That is, upon retrieving the 
>> children of a node, and dealing with an individual instance within that 
>> set, is it possible to specify that all of that node instance's normal 
>> many-to-many association members (non-rcte tree associations) get 
>> implicitly included in the query which fetches those children?
>>
>
> Again, I'm not exactly sure what you are asking for here.  If you want to 
> eagerly load associations for associated objects, you can use the :eager 
> option.  Note that like usual eager loading, this is an additional query. 
>  Something like this after loading the rcte_tree plugin may help:
>
> one_to_many :children, :clone=>:children, :eager=>:other_assoc
>  
> Note that if you use the tactical_eager_loading plugin, you shouldn't need 
> to do this, as it will eager load implicitly in most cases.  In either the 
> :eager or tactical_eager_loading case, obj.children.each{|c| c.other_assoc} 
> should be only 2 queries regardless of the number of children).
>
> The query you post does not make sense in rcte_tree context, since it 
>>> appears to be using a join table, and the rcte_tree plugin does not.
>>>
>>
>> Yes.  So, Artists could be considered to be nodes in the tree, and albums 
>> are normal non-hierarchical many-to-many associations, joined through an 
>> artist_to_album table and entity.
>>
>
> That makes sense.
>

Cool!  I'll try to provide a simplified example.

class Artist < Sequel::Model
  plugin :rcte_tree
  plugin :caching, GloballyDefinedConcurrentHashMapInstance
  plugin :tactical_eager_loading
  many_to_many :albums,
               :class => Album,
               :join_table => :artists_to_albums,
               :left_key => :artist_id,
               :right_key => :album_id

  def after_initialize
    for influenced in self.children
      for album in influenced.albums
        something_special_with(album)
      end
    end
  end
end

Many Artists, may be associated to many Albums.  Artists are nodes in a 
tree.  Upon loading of an Artist node's children Artist nodes, I would like 
each of the children Artist nodes to have included each of their respective 
associated Albums so that they are available immediately, and without 
additional SQL queries.

So when I do,

  jimi = Artist.where(:name => 'Jimi Hendrix')
  # Meanwhile, the after_initialize hook method is executed.

(For the sake of this example, please ignore the fact that in the real 
world, artists may of course have more than one influencer.)

It would be nice if at most only two queries were executed here.  Only one 
query would be even better, but I can never keep straight whether or not 
the children association can be loaded eagerly using rcte_tree -- let alone 
loaded eagerly while also eagerly loaded with their respective albums 
association members.  I'm pretty sure the answer is no.

Furthermore, it would be even nicer if after_initialize only ran one time 
ever, or until the model instances were marked as modified, or until the 
cached instances were explicitly cleared.  Unfortunately, the only instance 
that winds up making it into the cache is the instance that gets assigned 
to jimi.  And of course, none of jimi's albums make it into the cache 
either.

I hope this helps clear things up.  I'm having trouble being as clear as 
I'd like to be.

I did try using the suggested

one_to_many :children, :clone=>:children, :eager=>:albums


on the Artist model definition, but not only does it not seem to achieve 
the desired performance improvements, it also causes some weird errors when 
attempting to access a count of the cloned Artist.children association.  I 
can investigate more about that, if need be.


... a given node's branch is programmatically pre-order traversed, and 
>> information retrieved.  I may have to rework this, because it is bit of a 
>> performance pain point for the application.
>>
>
> That sounds interesting.  If you want to provide details, I may be able to 
> give advice in that area. 
>

The algorithm is an adaptation from another program, and it is rather 
convoluted.  Basically, it performs a pre-order traversal of a branch 
starting from a given node, and then does some complex book-keeping along 
the way, foregoing recursive pre-order traversals of certain nodes meeting 
specific criteria.

The reason this routine is so slow is because some hundreds of queries and 
after_initialize hooks get executed against the datasource backend, even if 
there are only a couple dozen nodes in the branch.

I'm pretty certain that if the loading and caching problem with the example 
above is solved, then this routine's performance will improve as well. 
 Furthermore, if I were able to leverage the descendants dataset of the 
given branch node, and somehow managed to devise a filter based on the 
algorithm's criteria, then I imagine this bottleneck would be solved 
completely.

But this is a bit of a rabbit hole for now.


However, the associations with which I am concerned are not the children 
>> associations.  They are just the normal many-to-many associations on the 
>> individual nodes.
>>
>
> OK.  I think the standard association :eager option or the 
> tactical_eager_loading plugin should help in those cases, modulo caching 
> issues.
>

I am having difficulty finding example of how to apply the :eager option to 
a many_to_many association definition.  Does this involve defining and 
specifying a proc?  Or is it as simple as

  many_to_many :albums, :eager => true

Thanks again for your time, Jeremy.  I hope that you are not the only one 
in this forum who ever replies to questions?  :D

Cheers,
-Nels

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to