acts_as_oqgraph 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +36 -31
- data/VERSION +1 -1
- data/acts_as_oqgraph.gemspec +56 -0
- data/lib/graph_edge.rb +2 -1
- metadata +3 -2
data/README.rdoc
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
ActsAsOQGraph
|
2
|
-
|
1
|
+
*ActsAsOQGraph*
|
2
|
+
|
3
3
|
This gem can be used with ActiveRecord to access the features of the OQGraph
|
4
4
|
MySQL plugin.
|
5
5
|
|
@@ -11,10 +11,11 @@ pros and cons of both approaches, It really depends on your needs. Both librarie
|
|
11
11
|
use the C++ Boost graph library at the bottom layers. OQGraph has expensive
|
12
12
|
insert operations but is very fast at delivering the graph data and finding paths in a single SQL query.
|
13
13
|
|
14
|
-
Concepts
|
14
|
+
*Concepts*
|
15
|
+
|
15
16
|
The term graph we are using here is a mathematical one not a pretty picture (sorry designers).
|
16
17
|
For more see: http://en.wikipedia.org/wiki/Graph_(mathematics)
|
17
|
-
A graph consists of nodes (aka vertices) connected by edges (aka
|
18
|
+
A graph consists of nodes (aka vertices) connected by edges (aka links, paths).
|
18
19
|
In a directed graph an edge has a direction. That is, it has an 'from' node and and a 'to' node.
|
19
20
|
When tracing a path on the graph you can only go in the direction of the edge.
|
20
21
|
The OQGraph gem operates on directed graphs. To create a non directed graph you have to create two edges,
|
@@ -23,7 +24,8 @@ one each way between each node.
|
|
23
24
|
Edges can be assigned positive floating point values called weights. Weights default to 1.0
|
24
25
|
The weights are used in shortest path calculations, a path is shorter if the sum of weights over each edge is smaller.
|
25
26
|
|
26
|
-
What you can do with OQGraph
|
27
|
+
*What you can do with OQGraph?*
|
28
|
+
|
27
29
|
Imagine your shiny new social networking app, FarceBook.
|
28
30
|
You have lots and lots of users each with several friends. How do you find the friends of friends?
|
29
31
|
Or even the friends of friends of friends...right up to the six degrees of separation perhaps?
|
@@ -31,35 +33,37 @@ Or even the friends of friends of friends...right up to the six degrees of separ
|
|
31
33
|
Well you can do it, with some really slow and nasty SQL queries. Relational databases are good at set
|
32
34
|
based queries but no good at graph or tree based queries. The OQGraph engine is good at graph based queries,
|
33
35
|
it enables you in one simple SQL query to find all friends of friends.
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
Do this:
|
37
|
+
user.reachable
|
38
|
+
If you really want to you can rename the reachable method so you can do this in your User model:
|
39
|
+
alias friends, reachable
|
40
|
+
Then I can call:
|
41
|
+
user.friends
|
42
|
+
and I get the whole tree of friends of friends etc...
|
40
43
|
|
41
|
-
TODO: Perhaps I should hook into ActiveRecord associations somehow so these can be named associations instead of methods.
|
42
|
-
Not really sure of how to go about this as yet
|
43
|
-
.
|
44
44
|
Imagine you have a maze to solve. With OQGraph the solution is as simple as: start_cell.shortest_path_to(finish_cell).
|
45
45
|
|
46
46
|
It's good for representing tree structures, networks, routes between cities, roads etc.
|
47
47
|
|
48
|
-
Usage
|
48
|
+
*Usage*
|
49
|
+
|
50
|
+
In your node model file:
|
51
|
+
|
52
|
+
Class Foo < ActiveRecord::Base
|
53
|
+
acts_as_oqgraph
|
54
|
+
end
|
49
55
|
|
50
|
-
|
51
|
-
acts_as_oqgraph +options+
|
52
|
-
end
|
56
|
+
*Options*
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
* class_name - The name of the edge class, defaults to current class name appended with Edge. eg FooEdge
|
59
|
+
* table_name - The name of the edge table, defaults to table name of the specified class, eg foo_edges
|
60
|
+
* oqgraph_table_name - the name of the volatile oqgraph table. Default foo_edge_oqgraph
|
61
|
+
* from_key - The from key field in the edge table. Default 'from_id'
|
62
|
+
* to_key - The to key field in the edge table. Default: 'to_id'
|
63
|
+
* weight_column - The weight field in the edge table.
|
64
|
+
|
65
|
+
*Setup*
|
61
66
|
|
62
|
-
Setup:
|
63
67
|
This gem requires the use of MySQL or MariaDB with the OQGraph engine plugin.
|
64
68
|
For details of this see: http://openquery.com/products/graph-engine
|
65
69
|
|
@@ -71,7 +75,6 @@ You will need a table for the edges with the following schema:
|
|
71
75
|
end
|
72
76
|
The field names and table name can be changed via the options listed above.
|
73
77
|
You should be able also to extend the edge model as you wish.
|
74
|
-
|
75
78
|
The gem will automatically create the oqgraph table and the associations to it from your node model.
|
76
79
|
The associations are:
|
77
80
|
node_model.outgoing_edges
|
@@ -80,14 +83,15 @@ The associations are:
|
|
80
83
|
node_model.incoming_nodes
|
81
84
|
edge_model.to
|
82
85
|
edge_model.from
|
83
|
-
|
84
|
-
|
86
|
+
|
87
|
+
|
88
|
+
*Examples of use*
|
85
89
|
|
86
90
|
Creating edges:
|
87
91
|
foo.create_edge_to(bar)
|
88
92
|
foo.create_edge_to_and_from(bar)
|
89
93
|
|
90
|
-
|
94
|
+
Edge creation using ActiveRecord associations:
|
91
95
|
foo.outgoing_nodes << bar
|
92
96
|
or equivalently:
|
93
97
|
bar.incoming_nodes << foo
|
@@ -122,7 +126,8 @@ Path Finding:
|
|
122
126
|
All these methods return the node object with an additional weight field.
|
123
127
|
This enables you to query the weights associated with the edges found.
|
124
128
|
|
125
|
-
Behind the Scenes
|
129
|
+
*Behind the Scenes*
|
130
|
+
|
126
131
|
When you declare acts_as_oqgraph then the edge class gets created. You can add extra functionality
|
127
132
|
if you wish to the edge class by the usual Ruby monkey patching methods.
|
128
133
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{acts_as_oqgraph}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Stuart Coyle"]
|
12
|
+
s.date = %q{2010-07-21}
|
13
|
+
s.description = %q{Acts As OQGraph allows ActiveRecord models to use the fast ans powerful OQGraph engine for MYSQL.}
|
14
|
+
s.email = %q{stuart.coyle@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"acts_as_oqgraph.gemspec",
|
27
|
+
"lib/acts_as_oqgraph.rb",
|
28
|
+
"lib/graph_edge.rb",
|
29
|
+
"test/helper.rb",
|
30
|
+
"test/models/custom_test_model.rb",
|
31
|
+
"test/models/test_model.rb",
|
32
|
+
"test/test_acts_as_oqgraph.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/stuart/acts_as_oqgraph}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.6}
|
38
|
+
s.summary = %q{Use the Open Query Graph engine with Active Record}
|
39
|
+
s.test_files = [
|
40
|
+
"test/helper.rb",
|
41
|
+
"test/models/custom_test_model.rb",
|
42
|
+
"test/models/test_model.rb",
|
43
|
+
"test/test_acts_as_oqgraph.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
else
|
52
|
+
end
|
53
|
+
else
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
data/lib/graph_edge.rb
CHANGED
@@ -85,7 +85,6 @@ class GraphEdge < ActiveRecord::Base
|
|
85
85
|
node_class.find_by_sql select_for_node << sql
|
86
86
|
end
|
87
87
|
|
88
|
-
private
|
89
88
|
def add_to_graph
|
90
89
|
connection.execute <<-EOS
|
91
90
|
INSERT INTO #{oqgraph_table_name} (origid, destid, weight)
|
@@ -93,6 +92,8 @@ class GraphEdge < ActiveRecord::Base
|
|
93
92
|
EOS
|
94
93
|
end
|
95
94
|
|
95
|
+
private
|
96
|
+
|
96
97
|
def remove_from_graph
|
97
98
|
connection.execute <<-EOS
|
98
99
|
DELETE FROM #{oqgraph_table_name} WHERE origid = #{self.send(self.class.from_key)} AND destid = #{self.send(self.class.to_key)};
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Stuart Coyle
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- README.rdoc
|
35
35
|
- Rakefile
|
36
36
|
- VERSION
|
37
|
+
- acts_as_oqgraph.gemspec
|
37
38
|
- lib/acts_as_oqgraph.rb
|
38
39
|
- lib/graph_edge.rb
|
39
40
|
- test/helper.rb
|