redcar 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +5 -0
- data/Rakefile +1 -2
- data/lib/redcar/installer.rb +2 -1
- data/lib/redcar.rb +2 -2
- data/plugins/project_search/vendor/lucene/CHANGELOG +147 -0
- data/plugins/project_search/vendor/lucene/CONTRIBUTORS +17 -0
- data/plugins/project_search/vendor/lucene/Gemfile +9 -0
- data/plugins/project_search/vendor/lucene/Gemfile.lock +33 -0
- data/plugins/project_search/vendor/lucene/LICENSE +19 -0
- data/plugins/project_search/vendor/lucene/README.rdoc +283 -0
- data/plugins/project_search/vendor/lucene/Rakefile +35 -0
- data/plugins/project_search/vendor/lucene/examples/active_model/serializers.rb +25 -0
- data/plugins/project_search/vendor/lucene/examples/active_model/validation.rb +26 -0
- data/plugins/project_search/vendor/lucene/examples/admin/Rakefile +4 -0
- data/plugins/project_search/vendor/lucene/examples/admin/admin.rb +29 -0
- data/plugins/project_search/vendor/lucene/examples/admin/public/jquery.js +4376 -0
- data/plugins/project_search/vendor/lucene/examples/admin/public/neo4j.css +153 -0
- data/plugins/project_search/vendor/lucene/examples/admin/public/neo_admin.js +18 -0
- data/plugins/project_search/vendor/lucene/examples/admin/spec/admin_spec.rb +26 -0
- data/plugins/project_search/vendor/lucene/examples/admin/views/index.erb +21 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/README.rdoc +9 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/app.rb +7 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/batch.props +5 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/features/step_definitions/add_steps.rb +121 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/features/support/env.rb +30 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/features/support/rspec_helper.rb +50 -0
- data/plugins/project_search/vendor/lucene/examples/filetree/features/treesizes.feature +19 -0
- data/plugins/project_search/vendor/lucene/examples/imdb/1_create_neo_db.rb +66 -0
- data/plugins/project_search/vendor/lucene/examples/imdb/2_index_db.rb +23 -0
- data/plugins/project_search/vendor/lucene/examples/imdb/README +12 -0
- data/plugins/project_search/vendor/lucene/examples/imdb/find_actors.rb +56 -0
- data/plugins/project_search/vendor/lucene/examples/imdb/install.sh +12 -0
- data/plugins/project_search/vendor/lucene/examples/imdb/model.rb +37 -0
- data/plugins/project_search/vendor/lucene/examples/railway/README +111 -0
- data/plugins/project_search/vendor/lucene/examples/railway/railnet-app.rb +31 -0
- data/plugins/project_search/vendor/lucene/examples/railway/railnet-data.rb +42 -0
- data/plugins/project_search/vendor/lucene/examples/rest/example.rb +41 -0
- data/plugins/project_search/vendor/lucene/examples/you_might_know/YouMightKnow.java +60 -0
- data/plugins/project_search/vendor/lucene/examples/you_might_know/all_simple_paths.rb +34 -0
- data/plugins/project_search/vendor/lucene/examples/you_might_know/nodes.rb +34 -0
- data/plugins/project_search/vendor/lucene/examples/you_might_know/you_might_know.rb +50 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/config.rb +145 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/document.rb +96 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/field_info.rb +144 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/hits.rb +54 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/index.rb +267 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/index_info.rb +146 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/index_searcher.rb +157 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/jars.rb +5 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/query_dsl.rb +135 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/transaction.rb +117 -0
- data/plugins/project_search/vendor/lucene/lib/lucene/version.rb +3 -0
- data/plugins/project_search/vendor/lucene/lib/lucene.rb +15 -0
- data/plugins/project_search/vendor/lucene/lucene.gemspec +23 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/document_spec.rb +32 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/field_info_spec.rb +70 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/index_info_spec.rb +76 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/index_spec.rb +643 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/query_dsl_spec.rb +142 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/sort_spec.rb +101 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/spec_helper.rb +10 -0
- data/plugins/project_search/vendor/lucene/spec/lucene/transaction_spec.rb +118 -0
- metadata +62 -4
@@ -0,0 +1,111 @@
|
|
1
|
+
* Railway Network Application Example (with JRuby Neo4j bindings)
|
2
|
+
by Bert Fitié
|
3
|
+
|
4
|
+
** A. Network application
|
5
|
+
|
6
|
+
(1) Nodes. The nodes are railway stations
|
7
|
+
(2) Arcs. The arcs are the connections between the stations
|
8
|
+
(3) Paths. The (named) paths are trains
|
9
|
+
(4) Usage. The user performs the following navigation:
|
10
|
+
(4.1) The user selects (loads) a start station
|
11
|
+
(4.2) The user generates a list of outgoing trains from this station
|
12
|
+
(4.3) The user selects the train he wants to board from this station
|
13
|
+
(4.4) The user generates the train path, i.e. the sequence of all
|
14
|
+
stations visited by this train from this station
|
15
|
+
(4.5) The user selects (loads) a destination station from this path
|
16
|
+
(4.6) If this station is the final destination, the user is done,
|
17
|
+
otherwise, the user continues has travel with (4.2)
|
18
|
+
|
19
|
+
** B. Example network
|
20
|
+
|
21
|
+
(1) The example network has 8 stations:
|
22
|
+
Alpha, Bravo, Charlie, Delta, Echo, Foxtrot, Golf, Hotel
|
23
|
+
(2) The example network has 8 arcs:
|
24
|
+
(2.1) Alpha - Bravo
|
25
|
+
(2.2) Bravo - Charlie
|
26
|
+
(2.3) Charlie - Delta
|
27
|
+
(2.4) Delta - Echo
|
28
|
+
(2.5) Alpha - Foxtrot
|
29
|
+
(2.6) Foxtrot - Charlie
|
30
|
+
(2.7) Delta - Golf
|
31
|
+
(2.8) Delta - Hotel
|
32
|
+
(3) The example network has 3 trains
|
33
|
+
(3.1) Train t1_ae:
|
34
|
+
(3.1.1) Alpha (departure 11:00) - Bravo (arrival 11:45)
|
35
|
+
(3.1.2) Bravo (departure 11:50) - Charlie (arrival 12:30)
|
36
|
+
(3.1.3) Charlie (departure 12:35) - Delta (arrival 13:00)
|
37
|
+
(3.1.4) Delta (departure 13:05) - Echo (arrival 14:00)
|
38
|
+
(3.2) Train t2_ag:
|
39
|
+
(3.2.1) Alpha (departure 13:15) - Foxtrot (arrival 13:45)
|
40
|
+
(3.2.2) Foxtrot (departure 13:50) - Charlie (arrival 14:30)
|
41
|
+
(3.2.3) Charlie (departure 14:35) - Delta (arrival 15:00)
|
42
|
+
(3.2.4) Delta (departure 15:05) - Golf (arrival 15:45)
|
43
|
+
(3.3) Train t3_gh:
|
44
|
+
(3.3.1) Golf (departure 12:30) - Delta (arrival 13:10)
|
45
|
+
(3.3.2) Delta (departure 13:15) - Hotel (arrival 14:30)
|
46
|
+
|
47
|
+
** C. Demo objective
|
48
|
+
|
49
|
+
(1) The user selects start station Alpha
|
50
|
+
Result should be:
|
51
|
+
You arrived at station Alpha
|
52
|
+
(2) The user generates a list of outgoing trains from Alpha
|
53
|
+
Result should be:
|
54
|
+
Train t1_ae: departure 11:00
|
55
|
+
Train t2_ag: departure 13:15
|
56
|
+
(3) The user selects Train t1_ae to board from this station
|
57
|
+
(4) The user generates the train path for Train t1_ae from Alpha
|
58
|
+
Result should be:
|
59
|
+
Alpha (departure 11:00) - Bravo (arrival 11:45)
|
60
|
+
Bravo (departure 11:50) - Charlie (arrival 12:30)
|
61
|
+
Charlie (departure 12:35) - Delta (arrival 13:00)
|
62
|
+
Delta (departure 13:05) - Echo (arrival 14:00)
|
63
|
+
(5) The user selects destination station Delta from this path
|
64
|
+
Result should be:
|
65
|
+
You arrived at station Delta
|
66
|
+
(6) The user generates a list of outgoing trains from Delta
|
67
|
+
Result should be:
|
68
|
+
Train t1_ae: departure 13:05
|
69
|
+
Train t2_ag: departure 15:05
|
70
|
+
Train t3_gh: departure 13:15
|
71
|
+
(7) The user selects Train t3_gh to board from this station
|
72
|
+
(8) The user generates the train path for Train t3_gh from Delta
|
73
|
+
Result should be:
|
74
|
+
Delta (departure 13:15) - Hotel (arrival 14:30)
|
75
|
+
(9) The user selects final destination station Hotel from this path
|
76
|
+
Result should be:
|
77
|
+
You arrived at station Hotel
|
78
|
+
|
79
|
+
** D. Data file
|
80
|
+
See railnet-data.rb
|
81
|
+
|
82
|
+
** E. Application file
|
83
|
+
See railnet-app.rb
|
84
|
+
|
85
|
+
|
86
|
+
** F. Demo session
|
87
|
+
|
88
|
+
~ $> cd ~/private/sandbox/neo-jruby/examples/railnet
|
89
|
+
railnet $> jruby railnet-data.rb
|
90
|
+
railnet $> jirb -r railnet-app
|
91
|
+
irb(main):001:0> alpha = select_station(1)
|
92
|
+
You arrived at station Alpha
|
93
|
+
irb(main):002:0> list_trains(alpha)
|
94
|
+
Train t2_ag: departure: 13:15
|
95
|
+
Train t1_ae: departure: 11:00
|
96
|
+
irb(main):003:0> train_path(alpha, :t1_ae)
|
97
|
+
Alpha #1 (departure: 11:00) - Bravo #2 (arrival: 11:45)
|
98
|
+
Bravo #2 (departure: 11:50) - Charlie #3 (arrival: 12:30)
|
99
|
+
Charlie #3 (departure: 12:35) - Delta #4 (arrival: 13:00)
|
100
|
+
Delta #4 (departure: 13:05) - Echo #5 (arrival: 14:00)
|
101
|
+
irb(main):004:0> delta = select_station(4)
|
102
|
+
You arrived at station Delta
|
103
|
+
irb(main):005:0> list_trains(delta)
|
104
|
+
Train t3_gh: departure: 13:15
|
105
|
+
Train t2_ag: departure: 15:05
|
106
|
+
Train t1_ae: departure: 13:05
|
107
|
+
irb(main):006:0> train_path(delta, :t3_gh)
|
108
|
+
Delta #4 (departure: 13:15) - Hotel #8 (arrival: 14:30)
|
109
|
+
irb(main):007:0> hotel = select_station(8)
|
110
|
+
You arrived at station Hotel
|
111
|
+
irb(main):008:0>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'neo4j'
|
3
|
+
|
4
|
+
def select_station(id)
|
5
|
+
station = nil
|
6
|
+
Neo4j::Transaction.run do
|
7
|
+
station = Neo4j.load_node(id)
|
8
|
+
puts "You arrived at station #{station[:name]}"
|
9
|
+
end
|
10
|
+
return station
|
11
|
+
end
|
12
|
+
|
13
|
+
def list_trains(station)
|
14
|
+
Neo4j::Transaction.run do
|
15
|
+
station.rels.outgoing.each do |rel|
|
16
|
+
puts "Train #{rel[:train]}: departure: #{rel[:dep]}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def train_path(station, train)
|
22
|
+
Neo4j::Transaction.run do
|
23
|
+
station.traverse.outgoing(train).depth(:all).each do |station|
|
24
|
+
rel = station.rel(train, dir = :incoming)
|
25
|
+
puts "#{rel.start_node[:name]} ##{rel.start_node.neo_id}" +
|
26
|
+
" (departure: #{rel[:dep]})" +
|
27
|
+
" - #{rel.end_node[:name]} ##{rel.end_node.neo_id}" +
|
28
|
+
" (arrival: #{rel[:arr]})"
|
29
|
+
end;
|
30
|
+
end;
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'neo4j'
|
3
|
+
|
4
|
+
Neo4j::Transaction.run do
|
5
|
+
|
6
|
+
# Stations
|
7
|
+
alpha = Neo4j::Node.new :name => 'Alpha'
|
8
|
+
bravo = Neo4j::Node.new :name => 'Bravo'
|
9
|
+
charlie = Neo4j::Node.new :name => 'Charlie'
|
10
|
+
delta = Neo4j::Node.new :name => 'Delta'
|
11
|
+
echo = Neo4j::Node.new :name => 'Echo'
|
12
|
+
foxtrot = Neo4j::Node.new :name => 'Foxtrot'
|
13
|
+
golf = Neo4j::Node.new :name => 'Golf'
|
14
|
+
hotel = Neo4j::Node.new :name => 'Hotel'
|
15
|
+
|
16
|
+
# Train t1_ae
|
17
|
+
t1_ab = Neo4j::Relationship.new(:t1_ae, alpha, bravo)
|
18
|
+
t1_bc = Neo4j::Relationship.new(:t1_ae, bravo, charlie)
|
19
|
+
t1_cd = Neo4j::Relationship.new(:t1_ae, charlie, delta)
|
20
|
+
t1_de = Neo4j::Relationship.new(:t1_ae, delta, echo)
|
21
|
+
t1_ab[:dep] = '11:00'; t1_ab[:arr] = '11:45'; t1_ab[:train] = 't1_ae'
|
22
|
+
t1_bc[:dep] = '11:50'; t1_bc[:arr] = '12:30'; t1_bc[:train] = 't1_ae'
|
23
|
+
t1_cd[:dep] = '12:35'; t1_cd[:arr] = '13:00'; t1_cd[:train] = 't1_ae'
|
24
|
+
t1_de[:dep] = '13:05'; t1_de[:arr] = '14:00'; t1_de[:train] = 't1_ae'
|
25
|
+
|
26
|
+
# Train t2_ag
|
27
|
+
t2_af = Neo4j::Relationship.new(:t2_ag, alpha, foxtrot)
|
28
|
+
t2_fc = Neo4j::Relationship.new(:t2_ag, foxtrot, charlie)
|
29
|
+
t2_cd = Neo4j::Relationship.new(:t2_ag, charlie, delta)
|
30
|
+
t2_dg = Neo4j::Relationship.new(:t2_ag, delta, golf)
|
31
|
+
t2_af[:dep] = '13:15'; t2_af[:arr] = '13:45'; t2_af[:train] = 't2_ag'
|
32
|
+
t2_fc[:dep] = '13:50'; t2_fc[:arr] = '14:30'; t2_fc[:train] = 't2_ag'
|
33
|
+
t2_cd[:dep] = '14:35'; t2_cd[:arr] = '15:00'; t2_cd[:train] = 't2_ag'
|
34
|
+
t2_dg[:dep] = '15:05'; t2_dg[:arr] = '15:45'; t2_dg[:train] = 't2_ag'
|
35
|
+
|
36
|
+
# Train t3_gh
|
37
|
+
t3_gd = Neo4j::Relationship.new(:t3_gh, golf, delta)
|
38
|
+
t3_dh = Neo4j::Relationship.new(:t3_gh, delta, hotel)
|
39
|
+
t3_gd[:dep] = '12:30'; t3_gd[:arr] = '13:10'; t3_gd[:train] = 't3_gh'
|
40
|
+
t3_dh[:dep] = '13:15'; t3_dh[:arr] = '14:30'; t3_dh[:train] = 't3_gh'
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#####################################
|
2
|
+
#
|
3
|
+
# A simple example how to expose neo nodes as REST resources.
|
4
|
+
#
|
5
|
+
# IMPORTANT
|
6
|
+
#
|
7
|
+
# This example requires the latest version from GITHUB of the sinatra gem
|
8
|
+
# and json-jruby (>=1.1.6) (or another compatible json gem)
|
9
|
+
#
|
10
|
+
|
11
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
12
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/..")
|
13
|
+
require 'rubygems'
|
14
|
+
require 'neo4j'
|
15
|
+
require 'neo4j/extensions/rest'
|
16
|
+
|
17
|
+
FileUtils.rm_rf Neo4j::Config[:storage_path] # NEO_STORAGE
|
18
|
+
FileUtils.rm_rf Lucene::Config[:storage_path] unless Lucene::Config[:storage_path].nil?
|
19
|
+
|
20
|
+
|
21
|
+
class Person
|
22
|
+
include Neo4j::NodeMixin
|
23
|
+
# by includeing the following mixin we will expose this node as a RESTful resource
|
24
|
+
include Neo4j::RestMixin
|
25
|
+
property :name
|
26
|
+
has_n :friends
|
27
|
+
index :name
|
28
|
+
end
|
29
|
+
|
30
|
+
Neo4j.start
|
31
|
+
puts "-----------------------"
|
32
|
+
Neo4j::Transaction.run do
|
33
|
+
a = Person.new :name => 'andreas', :foo => 'bar', :fav_number => 14
|
34
|
+
b = Person.new :name => 'kalle'
|
35
|
+
c = Person.new :name => 'anders'
|
36
|
+
a.friends << b
|
37
|
+
a.rels.outgoing(:other) << c
|
38
|
+
puts "Created Nodes at URI:\n\t#{a._uri}\n\t#{b._uri}\n\t#{c._uri}"
|
39
|
+
end
|
40
|
+
|
41
|
+
Neo4j::Rest::RestServer.thread.join
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class YouMightKnow
|
2
|
+
{
|
3
|
+
List<List<Node>> result = new ArrayList<List<Node>>();
|
4
|
+
int maxDistance;
|
5
|
+
String[] features;
|
6
|
+
Object[] values;
|
7
|
+
Set<Node> buddies = new HashSet<Node>();
|
8
|
+
|
9
|
+
YouMightKnow( Node node, String[] features, int maxDistance )
|
10
|
+
{
|
11
|
+
this.features = features;
|
12
|
+
this.maxDistance = maxDistance;
|
13
|
+
values = new Object[features.length];
|
14
|
+
List<Integer> matches = new ArrayList<Integer>();
|
15
|
+
for ( int i = 0; i < features.length; i++ )
|
16
|
+
{
|
17
|
+
values[i] = node.getProperty( features[i] );
|
18
|
+
matches.add( i );
|
19
|
+
}
|
20
|
+
for ( Relationship rel : node.getRelationships( RelationshipTypes.KNOWS ) )
|
21
|
+
{
|
22
|
+
buddies.add( rel.getOtherNode( node ) );
|
23
|
+
}
|
24
|
+
findFriends( Arrays.asList( new Node[] { node } ), matches, 1 );
|
25
|
+
}
|
26
|
+
|
27
|
+
void findFriends( List<Node> path, List<Integer> matches, int depth )
|
28
|
+
{
|
29
|
+
Node prevNode = path.get( path.size() - 1 );
|
30
|
+
for ( Relationship rel : prevNode.getRelationships( RelationshipTypes.KNOWS ) )
|
31
|
+
{
|
32
|
+
Node node = rel.getOtherNode( prevNode );
|
33
|
+
if ( (depth > 1 && buddies.contains( node )) || path.contains( node ) )
|
34
|
+
{
|
35
|
+
continue;
|
36
|
+
}
|
37
|
+
List<Integer> newMatches = new ArrayList<Integer>();
|
38
|
+
for ( int match : matches )
|
39
|
+
{
|
40
|
+
if ( node.getProperty( features[match] ).equals( values[match] ) )
|
41
|
+
{
|
42
|
+
newMatches.add( match );
|
43
|
+
}
|
44
|
+
}
|
45
|
+
if ( newMatches.size() > 0 )
|
46
|
+
{
|
47
|
+
List<Node> newPath = new ArrayList<Node>( path );
|
48
|
+
newPath.add( node );
|
49
|
+
if ( depth > 1 )
|
50
|
+
{
|
51
|
+
result.add( newPath );
|
52
|
+
}
|
53
|
+
if ( depth != maxDistance )
|
54
|
+
{
|
55
|
+
findFriends( newPath, newMatches, depth + 1 );
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'neo4j'
|
3
|
+
require 'neo4j/extensions/graph_algo'
|
4
|
+
include Neo4j
|
5
|
+
|
6
|
+
# In this case we want to know the possible paths from one person in a social network to an other.
|
7
|
+
# With those paths at hand we can do things similar to the "How you're connected to N.N." feature of LinkedIn.
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
Transaction.new
|
12
|
+
|
13
|
+
load "nodes.rb"
|
14
|
+
|
15
|
+
node1,node2,node3,node4,node5,node6,node7 = create_nodes
|
16
|
+
|
17
|
+
found_nodes = GraphAlgo.all_simple_paths.from(node1).both(:knows).to(node7).depth(4).as_nodes
|
18
|
+
puts "Nodes between #{node1} and #{node7}"
|
19
|
+
found_nodes.each do |path|
|
20
|
+
puts "path"
|
21
|
+
path.each {|node| puts " #{node}" }
|
22
|
+
end
|
23
|
+
|
24
|
+
sorted = found_nodes.sort_by{|path| 10 - path.size}
|
25
|
+
|
26
|
+
puts "sorted: "
|
27
|
+
sorted.each do |path|
|
28
|
+
puts "path"
|
29
|
+
path.each {|node| puts " #{node}" }
|
30
|
+
end
|
31
|
+
|
32
|
+
Transaction.finish
|
33
|
+
|
34
|
+
Neo4j.stop
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
|
3
|
+
# Add a to string method printing the node name
|
4
|
+
class Node
|
5
|
+
include Neo4j::NodeMixin
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
"Node #{self[:name]}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_nodes
|
13
|
+
node1 = Node.new; node1[:feat1] = 'a'; node1[:feat2] = 'b'; node1[:name] = 1
|
14
|
+
node2 = Node.new; node2[:feat1] = 'a'; node2[:feat2] = 'b'; node2[:name] = 2
|
15
|
+
node3 = Node.new; node3[:feat1] = 'a'; node3[:feat2] = 'd'; node3[:name] = 3
|
16
|
+
node4 = Node.new; node4[:feat1] = 'c'; node4[:feat2] = 'd'; node4[:name] = 4
|
17
|
+
node5 = Node.new; node5[:feat1] = 'a'; node5[:feat2] = 'b'; node5[:name] = 5
|
18
|
+
node6 = Node.new; node6[:feat1] = 'a'; node6[:feat2] = 'b'; node6[:name] = 6
|
19
|
+
node7 = Node.new; node7[:feat1] = 'a'; node7[:feat2] = 'b'; node7[:name] = 7
|
20
|
+
|
21
|
+
node1.rels.outgoing(:knows) << node3
|
22
|
+
node2.rels.outgoing(:knows) << node1
|
23
|
+
node2.rels.outgoing(:knows) << node4
|
24
|
+
node3.rels.outgoing(:knows) << node5
|
25
|
+
node3.rels.outgoing(:knows) << node4
|
26
|
+
node3.rels.outgoing(:knows) << node6
|
27
|
+
node4.rels.outgoing(:knows) << node7
|
28
|
+
node5.rels.outgoing(:knows) << node6
|
29
|
+
node5.rels.outgoing(:knows) << node1
|
30
|
+
node6.rels.outgoing(:knows) << node1
|
31
|
+
|
32
|
+
[node1,node2,node3,node4,node5,node6,node7]
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'neo4j'
|
3
|
+
include Neo4j
|
4
|
+
|
5
|
+
|
6
|
+
# The challenge this time is to traverse into friends of friends (or even deeper) and find people with something in common.
|
7
|
+
# Based on this we can distill someone the user might know, or could be interested in knowing.
|
8
|
+
# The persons in our social network all have different values for two features, feat1 and feat2.
|
9
|
+
# The idea of the solution presented here is to keep track of the features that are common in each branch of the traversal
|
10
|
+
# and to stop when there is nothing in common any more or the maximum distance has been reached.
|
11
|
+
def you_might_know(node, matches, max_distance)
|
12
|
+
buddies = [*node.rels.both(:knows).nodes]
|
13
|
+
find_friends(node, [node], matches, 1, max_distance, buddies)
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_friends(root_node, path, matches, depth, max_distance, buddies)
|
17
|
+
result = []
|
18
|
+
path.last.rels.both(:knows).nodes.each do |node|
|
19
|
+
next if (depth > 1 && buddies.include?(node)) || path.include?(node)
|
20
|
+
new_matches = matches.find_all{|feature| root_node[feature] == node[feature]}
|
21
|
+
next if new_matches.empty?
|
22
|
+
new_path = path + [node]
|
23
|
+
result = [new_path] + result if depth > 1
|
24
|
+
result += find_friends(node, new_path, new_matches, depth + 1, max_distance, buddies) if depth != max_distance
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
puts "-----------------------"
|
31
|
+
puts "YOU MIGHT KNOW"
|
32
|
+
puts "-----------------------"
|
33
|
+
|
34
|
+
|
35
|
+
Transaction.new
|
36
|
+
|
37
|
+
load "nodes.rb"
|
38
|
+
|
39
|
+
node1,node2,node3,node4,node5,node6,node7 = create_nodes
|
40
|
+
|
41
|
+
result = you_might_know(node5, [:feat1, :feat2], 4)
|
42
|
+
result.each do |list|
|
43
|
+
puts "You might know nodes"
|
44
|
+
list.each {|n| puts n}
|
45
|
+
end
|
46
|
+
|
47
|
+
Transaction.finish
|
48
|
+
Neo4j.stop
|
49
|
+
|
50
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
|
2
|
+
module Lucene
|
3
|
+
|
4
|
+
|
5
|
+
#
|
6
|
+
# Keeps configuration for lucene.
|
7
|
+
# Contains both common configuration for all lucene indexes as well
|
8
|
+
# as specific configuration for each index (TODO).
|
9
|
+
# This code is copied from merb-core/config.rb.
|
10
|
+
#
|
11
|
+
# Contains three default configurations (Config.defaults)
|
12
|
+
# * :store_on_file:: default false, which will only keep the index in memory
|
13
|
+
# * :id_field:: default :id
|
14
|
+
# * :storage_path:: where the index is kept on file system if stored as a file (instead of just in memory)
|
15
|
+
#
|
16
|
+
class Config
|
17
|
+
class << self
|
18
|
+
# Returns the hash of default config values for lucene.
|
19
|
+
#
|
20
|
+
# ==== Returns
|
21
|
+
# Hash:: The defaults for the config.
|
22
|
+
#
|
23
|
+
def defaults
|
24
|
+
@defaults ||= {
|
25
|
+
:store_on_file => false,
|
26
|
+
:id_field => :id,
|
27
|
+
:storage_path => nil
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Yields the configuration.
|
33
|
+
#
|
34
|
+
# ==== Block parameters
|
35
|
+
# c<Hash>:: The configuration parameters.
|
36
|
+
#
|
37
|
+
# ==== Examples
|
38
|
+
# Lucene::Config.use do |config|
|
39
|
+
# config[:in_memory] = true
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# ==== Returns
|
43
|
+
# nil
|
44
|
+
#
|
45
|
+
def use
|
46
|
+
@configuration ||= {}
|
47
|
+
yield @configuration
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# Set the value of a config entry.
|
53
|
+
#
|
54
|
+
# ==== Parameters
|
55
|
+
# key<Object>:: The key to set the parameter for.
|
56
|
+
# val<Object>:: The value of the parameter.
|
57
|
+
#
|
58
|
+
def []=(key, val)
|
59
|
+
(@configuration ||= setup)[key] = val
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# Gets the the value of a config entry
|
64
|
+
#
|
65
|
+
# ==== Parameters
|
66
|
+
# key<Object>:: The key of the config entry value we want
|
67
|
+
#
|
68
|
+
def [](key)
|
69
|
+
(@configuration ||= setup)[key]
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# Remove the value of a config entry.
|
74
|
+
#
|
75
|
+
# ==== Parameters
|
76
|
+
# key<Object>:: The key of the parameter to delete.
|
77
|
+
#
|
78
|
+
# ==== Returns
|
79
|
+
# Object:: The value of the removed entry.
|
80
|
+
#
|
81
|
+
def delete(key)
|
82
|
+
@configuration.delete(key)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Remove all configuration. This can be useful for testing purpose.
|
87
|
+
#
|
88
|
+
#
|
89
|
+
# ==== Returns
|
90
|
+
# nil
|
91
|
+
#
|
92
|
+
def delete_all
|
93
|
+
@configuration = nil
|
94
|
+
IndexInfo.delete_all
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
# Retrieve the value of a config entry, returning the provided default if the key is not present
|
99
|
+
#
|
100
|
+
# ==== Parameters
|
101
|
+
# key<Object>:: The key to retrieve the parameter for.
|
102
|
+
# default<Object>::
|
103
|
+
# The default value to return if the parameter is not set.
|
104
|
+
#
|
105
|
+
# ==== Returns
|
106
|
+
# Object:: The value of the configuration parameter or the default.
|
107
|
+
#
|
108
|
+
def fetch(key, default)
|
109
|
+
@configuration.fetch(key, default)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Sets up the configuration
|
113
|
+
#
|
114
|
+
# ==== Returns
|
115
|
+
# The configuration as a hash.
|
116
|
+
#
|
117
|
+
def setup()
|
118
|
+
@configuration = {}
|
119
|
+
@configuration.merge!(defaults)
|
120
|
+
@configuration
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# Returns the configuration as a hash.
|
125
|
+
#
|
126
|
+
# ==== Returns
|
127
|
+
# Hash:: The config as a hash.
|
128
|
+
#
|
129
|
+
def to_hash
|
130
|
+
@configuration
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the config as YAML.
|
134
|
+
#
|
135
|
+
# ==== Returns
|
136
|
+
# String:: The config as YAML.
|
137
|
+
#
|
138
|
+
def to_yaml
|
139
|
+
require "yaml"
|
140
|
+
@configuration.to_yaml
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Lucene
|
2
|
+
|
3
|
+
#
|
4
|
+
# A document is like a record or row in a relationship database.
|
5
|
+
# Contains the field infos which can be used for type conversions or
|
6
|
+
# specifying if the field should be stored or only searchable.
|
7
|
+
#
|
8
|
+
class Document
|
9
|
+
|
10
|
+
attr_reader :id_field, :field_infos, :props
|
11
|
+
|
12
|
+
def initialize(field_infos, props = {})
|
13
|
+
@id_field = field_infos.id_field
|
14
|
+
@field_infos = field_infos
|
15
|
+
|
16
|
+
@props = {}
|
17
|
+
props.each_pair do |key,value|
|
18
|
+
@props[key] = field_infos[key].convert_to_ruby(value)
|
19
|
+
$LUCENE_LOGGER.debug{"FieldInfo #{key} type: #{field_infos[key][:type]}"}
|
20
|
+
$LUCENE_LOGGER.debug{"Converted #{key} '#{value}' type: '#{value.class.to_s}' to '#{@props[key]}' type: '#{@props[key].class.to_s}'"}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
@props[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Convert a java Document to a ruby Lucene::Document
|
30
|
+
#
|
31
|
+
def self.convert(field_infos, java_doc)
|
32
|
+
fields = {}
|
33
|
+
field_infos.each_pair do |key, field|
|
34
|
+
next unless field.store?
|
35
|
+
raise StandardError.new("expected field '#{key.to_s}' to exist in document") if java_doc.getField(key.to_s).nil?
|
36
|
+
value = java_doc.getField(key.to_s).stringValue
|
37
|
+
fields.merge!({key => value})
|
38
|
+
end
|
39
|
+
Document.new(field_infos, fields)
|
40
|
+
end
|
41
|
+
|
42
|
+
def id
|
43
|
+
raise IdFieldMissingException.new("Missing id field: '#{@id_field}'") if self[@id_field].nil?
|
44
|
+
@props[@id_field]
|
45
|
+
end
|
46
|
+
|
47
|
+
def eql?(other)
|
48
|
+
return false unless other.is_a? Document
|
49
|
+
return id == other.id
|
50
|
+
end
|
51
|
+
|
52
|
+
def ==(other)
|
53
|
+
eql?(other)
|
54
|
+
end
|
55
|
+
|
56
|
+
def hash
|
57
|
+
id.hash
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# removes the document and adds it again
|
62
|
+
#
|
63
|
+
def update(index_writer)
|
64
|
+
index_writer.updateDocument(java_key_term, java_document)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def java_key_term
|
69
|
+
org.apache.lucene.index.Term.new(@id_field.to_s, id.to_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
def java_document
|
73
|
+
java_doc = org.apache.lucene.document.Document.new
|
74
|
+
@props.each_pair do |key,value|
|
75
|
+
field_info = @field_infos[key]
|
76
|
+
# TODO value could be an array if value.kind_of? Enumerable
|
77
|
+
if (value.kind_of?(Array))
|
78
|
+
value.each do |v|
|
79
|
+
field = field_info.java_field(key,v)
|
80
|
+
java_doc.add(field) unless field.nil?
|
81
|
+
end
|
82
|
+
else
|
83
|
+
field = field_info.java_field(key,value)
|
84
|
+
java_doc.add(field) unless field.nil?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
java_doc
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s
|
91
|
+
p = ""
|
92
|
+
@props.each_pair { |key,value| p << "'#{key}' = '#{value}' " }
|
93
|
+
"Document [#@id_field='#{self[@id_field]}', #{p}]"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|