Giter VIP home page Giter VIP logo

index_tree's Introduction

Build Status Coverage Status

IndexTree

This Gem eagerly loads trees by indexing the nodes of the tree. The number of queries needed for loading a tree is N, Where N is the number of different models(ActiveRecords) in the tree.

Each inner object in the tree have an index node instance that is connecting it to the root. When the root of the tree is loaded, only the objects that are in the tree are fetched(Pruning). The index nodes are created when the root element is saved and stored in the IndexNode model.

Example:

Models definitions:

class Equation < ActiveRecord::Base
    acts_as_indexed_node :root => true do
        has_many :expressions
    end
  
    has_one :not_tree_association_a
    
    def traverse
       expression.traverse
    end        
end


class Expression < ActiveRecord::Base
    belongs_to :equation, inverse_of: :expressions
    
    acts_as_indexed_node do
        has_many :expressions
    end
    
    has_one :not_tree_association_b
    
    def traverse
        expressions.map(&:traverse)
    end
end

Database initialization:

                 +-----------+                               +-----------+
                 |Equation  1|                               |Equation  2|
                 +-----+-----+                               +-----+-----+
                       |                                           |
                       v                                           v
                 +-----------+                               +-----------+
                 |Expression1|                               |Expression6|
                 +-+-------+-+                               +-+-------+-+
                   ^       ^                                   ^       ^
                   |       |                                   |       |
           +-------+       +-------+                   +-------+       +-------+
           |                       |                   |                       |
           |                       |                   |                       |
     +-----+-----+           +-----+-----+       +-----+-----+           +-----+-----+
     |Expression3|           |Expression2|       |Expression8|           |Expression7|
     +-----------+           +-----------+       +-----------+           +-----------+
                               ^       ^                                   ^       ^
                               |       |                                   |       |
                       +-------+       +-------+                   +-------+       +-------+
                       |                       |                   |                       |
                       |                       |                   |                       |
                 +-----+-----+           +-----+-----+       +-----+-----+          +------+-----+
                 |Expression4|           |Expression5|       |Expression9|          |Expression10|
                 +-----------+           +-----------+       +-----------+          +------------+                       

Traversal example without tree pre-loading:

Equation.find(1).traverse

Those are the queries that is executed:

Equation Load (0.2ms)  SELECT  "equations".* FROM "equations"   ORDER BY "equations"."id" ASC LIMIT 1
Expression Load (0.2ms)  SELECT  "expressions".* FROM "expressions"  WHERE "expressions"."id" = ? LIMIT 1  [["id", 1]]
Expression Load (0.1ms)  SELECT "expressions".* FROM "expressions"  WHERE "expressions"."expression_id" = ?  [["expression_id", 1]]
Expression Load (0.1ms)  SELECT "expressions".* FROM "expressions"  WHERE "expressions"."expression_id" = ?  [["expression_id", 2]]
Expression Load (0.1ms)  SELECT "expressions".* FROM "expressions"  WHERE "expressions"."expression_id" = ?  [["expression_id", 4]]
Expression Load (0.1ms)  SELECT "expressions".* FROM "expressions"  WHERE "expressions"."expression_id" = ?  [["expression_id", 5]]
Expression Load (0.1ms)  SELECT "expressions".* FROM "expressions"  WHERE "expressions"."expression_id" = ?  [["expression_id", 3]]

It can be improved with eager loading such as 'includes', but eager loading will be fixed to the tree height.

Traversal example with tree pre-loading:

Equation.find(1).preload_tree.traverse

The statement fetches only the objects in the Equation1 tree in two queries:

Equation Load (0.1ms)  SELECT  "equations".* FROM "equations"   ORDER BY "equations"."id" ASC LIMIT 1
Expression Load (0.2ms)  SELECT "expressions".* FROM "expressions" 
INNER JOIN "index_tree_index_nodes" ON "index_tree_index_nodes"."node_element_id" = "expressions"."id" 
AND "index_tree_index_nodes"."node_element_type" = 'Expression' 
WHERE "index_tree_index_nodes"."root_element_type" = 'Equation' AND "index_tree_index_nodes"."root_element_id" IN (1)

One query to fetch Equations, and the second query is to fetch Expressions(Doesn't matter how deep is the tree it is still one query)

Installation

Add this line to your application's Gemfile:

gem 'index_tree'

And then execute:

$ bundle
$ rake db:migrate 

There is a migration which creates index_tree_index_node table(IndexNode model)

Declaration

All the models should be loaded in the Rails application, before using the preload_tree.

class RootNode < ActiveRecord::Base
   acts_as_indexed_node :root => true do
     has_many :child_nodes, dependent: :destroy
   end
end

The following associations are supported:

 belongs_to
 belongs_to :class, polymorphic: true
 has_one
 has_many

The following types of inheritance are supported:

STI 
Polymorphic associations

Options:

:root   Used to declare a root model(default is false)

Usage

RootModel.find(1).preload_tree
RootModel.all.preload_tree
RootModel.where(color: 'red').all.preload_tree

index_tree's People

Contributors

alexstanovsky avatar 23seriy avatar

Stargazers

Toan Tran avatar Dan Frenette avatar H. Can Yıldırım avatar  avatar

Watchers

Simon Levin avatar Oren Bajayo avatar James Cloos avatar Nitzan Aviram avatar Ohad avatar Sefi Eini avatar  avatar Shahar Shelly avatar  avatar  avatar Kobi Shitrit avatar Imri Barr avatar  avatar Itai Ganot avatar meir.kempler avatar Ran Kiselstein avatar Moran Zabatani avatar Simon Faiman avatar

index_tree's Issues

Using this with ancestry gem

Hey
How can we use this with the ancestry gem? Since there are no specific children class defined for the the root_node, there is no child_node we can specify.

How can we do this?

Can't use gem with Rails 6

Hello! I'm trying to use this gem with Rails 6. When I run db:migrate I get this error:

StandardError: An error has occurred, this and all later migrations canceled:

Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:

class CreateIndexTreeIndexNodes < ActiveRecord::Migration[4.2]

I tried tracking down the CreateIndexTreeIndexNodes migration in the gem folder and adding a version number onto it. When I did that, I got this error:

Index name 'index_index_tree_index_nodes_on_root_element_type_and_root_element_id' on table 'index_tree_index_nodes' is too long; the limit is 63 characters

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.