activerdf_rdflite 1.1 → 1.2
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/Rakefile +8 -7
- data/lib/activerdf_rdflite/fetching.rb +18 -12
- data/lib/activerdf_rdflite/rdflite.rb +45 -54
- data/lib/activerdf_rdflite/suggesting.rb +15 -1
- data/test/test_bnode_data.nt +5 -0
- data/test/test_rdflite.rb +30 -11
- metadata +14 -4
data/Rakefile
CHANGED
@@ -13,19 +13,20 @@ setup_rdoc ['README', 'LICENSE', 'lib/**/*.rb', 'doc/**/*.rdoc']
|
|
13
13
|
desc "test and package gem"
|
14
14
|
task :default => [:test, :package]
|
15
15
|
|
16
|
-
# get
|
17
|
-
|
16
|
+
# get VERSION from commandline
|
17
|
+
VERSION = '1.2'
|
18
18
|
NAME="activerdf_rdflite"
|
19
|
-
GEMNAME="#{NAME}-#{
|
19
|
+
GEMNAME="#{NAME}-#{VERSION}.gem"
|
20
20
|
|
21
21
|
# define package task
|
22
|
-
setup_gem(NAME,
|
22
|
+
setup_gem(NAME,VERSION) do |spec|
|
23
23
|
spec.summary = "an RDF database for usage in ActiveRDF (based on sqlite3)"
|
24
24
|
spec.description = spec.summary
|
25
25
|
spec.author="Eyal Oren <eyal.oren@deri.org"
|
26
26
|
spec.add_dependency('gem_plugin', '>= 0.2.1')
|
27
|
-
spec.add_dependency('
|
28
|
-
spec.add_dependency('
|
27
|
+
spec.add_dependency('uuidtools')
|
28
|
+
spec.add_dependency('activerdf', '>= 1.2')
|
29
|
+
spec.add_dependency('sqlite3-ruby', '>= 1.1.0.1')
|
29
30
|
end
|
30
31
|
|
31
32
|
task :install => [:package] do
|
@@ -39,6 +40,6 @@ end
|
|
39
40
|
task :reinstall => [:uninstall, :install]
|
40
41
|
|
41
42
|
task :upload => :package do |task|
|
42
|
-
sh "scp pkg/#{GEMNAME} eyal@
|
43
|
+
sh "scp pkg/#{GEMNAME} eyal@activerdf.org:/home/eyal/webs/activerdf/gems/"
|
43
44
|
end
|
44
45
|
|
@@ -1,16 +1,8 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# m = _match(args.first)
|
5
|
-
# if m && m.length > 1
|
6
|
-
# args[1..-1].each_with_index do |name, index|
|
7
|
-
# m.instance_eval "def #{name}; self[#{index+1}] end"
|
8
|
-
# end
|
9
|
-
# end
|
10
|
-
# m
|
11
|
-
# end
|
12
|
-
#end
|
1
|
+
# Author:: Eyal Oren
|
2
|
+
# Copyright:: (c) 2005-2006 Eyal Oren
|
3
|
+
# License:: LGPL
|
13
4
|
|
5
|
+
# FetchingAdapter is an extension to rdflite for fetching RDF from online sources.
|
14
6
|
class FetchingAdapter < RDFLite
|
15
7
|
ConnectionPool.register_adapter(:fetching,self)
|
16
8
|
|
@@ -41,3 +33,17 @@ class FetchingAdapter < RDFLite
|
|
41
33
|
add_ntriples(triples, context)
|
42
34
|
end
|
43
35
|
end
|
36
|
+
|
37
|
+
#class String
|
38
|
+
# alias _match match
|
39
|
+
# def match(*args)
|
40
|
+
# m = _match(args.first)
|
41
|
+
# if m && m.length > 1
|
42
|
+
# args[1..-1].each_with_index do |name, index|
|
43
|
+
# m.instance_eval "def #{name}; self[#{index+1}] end"
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# m
|
47
|
+
# end
|
48
|
+
#end
|
49
|
+
|
@@ -5,6 +5,7 @@
|
|
5
5
|
require 'sqlite3'
|
6
6
|
require 'active_rdf'
|
7
7
|
require 'federation/connection_pool'
|
8
|
+
require_gem 'uuidtools'
|
8
9
|
|
9
10
|
$activerdflog.info "loading RDFLite adapter"
|
10
11
|
|
@@ -91,9 +92,9 @@ class RDFLite < ActiveRdfAdapter
|
|
91
92
|
# symbol parameters match anything: delete(:s,:p,:o) will delete all triples
|
92
93
|
# you can specify a context to limit deletion to that context:
|
93
94
|
# delete(:s,:p,:o, 'http://context') will delete all triples with that context
|
94
|
-
def delete(s,p,o,c=nil)
|
95
|
-
# convert input to internal format
|
96
|
-
quad = [s,p,o,c].collect {|r| internalise(r) }
|
95
|
+
def delete(s, p, o, c=nil)
|
96
|
+
# convert non-nil input to internal format
|
97
|
+
quad = [s,p,o,c].collect {|r| r.nil? ? nil : internalise(r) }
|
97
98
|
|
98
99
|
# construct where clause for deletion (for all non-nil input)
|
99
100
|
where_clauses = []
|
@@ -132,8 +133,11 @@ class RDFLite < ActiveRdfAdapter
|
|
132
133
|
# get internal representation (array)
|
133
134
|
quad = [s,p,o,c].collect {|r| internalise(r) }
|
134
135
|
|
135
|
-
#
|
136
|
-
|
136
|
+
# insert the triple into the datastore
|
137
|
+
@db.execute('insert into triple values (?,?,?,?)', *quad)
|
138
|
+
|
139
|
+
# if keyword-search available, insert the object into keyword search
|
140
|
+
@ferret << {:subject => s, :object => o} if keyword_search?
|
137
141
|
end
|
138
142
|
|
139
143
|
# flushes openstanding changes to underlying sqlite3
|
@@ -148,48 +152,48 @@ class RDFLite < ActiveRdfAdapter
|
|
148
152
|
ntriples = File.readlines(file)
|
149
153
|
$activerdflog.debug "read #{ntriples.size} triples from file #{file}"
|
150
154
|
|
151
|
-
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
# adds string of ntriples from given context to database
|
156
|
-
def add_ntriples(ntriples, context=nil)
|
157
|
-
# convert context to internal format if RDFS::Resource
|
158
|
-
context = internalise(context)
|
155
|
+
# use filename as context
|
156
|
+
context = internalise(RDFS::Resource.new("file:#{file}"))
|
159
157
|
|
160
158
|
# need unique identifier for this batch of triples (to detect occurence of
|
161
159
|
# same bnodes _:#1
|
162
|
-
uuid =
|
160
|
+
uuid = UUID.random_create.to_s
|
163
161
|
|
164
162
|
# add each triple to db
|
165
|
-
@db.transaction
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
163
|
+
@db.transaction
|
164
|
+
insert = @db.prepare('insert into triple values (?,?,?,?);')
|
165
|
+
|
166
|
+
ntriples.each do |triple|
|
167
|
+
nodes = triple.scan(Node)
|
168
|
+
|
169
|
+
# handle bnodes if necessary (bnodes need to have uri generated)
|
170
|
+
subject = case nodes[0]
|
171
|
+
when BNode
|
172
|
+
"<http://www.activerdf.org/bnode/#{uuid}/#$1>"
|
173
|
+
else
|
174
|
+
nodes[0]
|
175
|
+
end
|
176
|
+
|
177
|
+
predicate = nodes[1]
|
178
|
+
|
179
|
+
# handle bnodes and literals if necessary (literals need unicode fixing)
|
180
|
+
object = case nodes[2]
|
181
|
+
when BNode
|
182
|
+
"<http://www.activerdf.org/bnode/#$1/#{uuid}>"
|
183
|
+
when Literal
|
184
|
+
fix_unicode(nodes[2])
|
185
|
+
else
|
186
|
+
nodes[2]
|
187
|
+
end
|
188
|
+
|
189
|
+
# insert triple into database
|
190
|
+
insert.execute(subject, predicate, object, context)
|
191
|
+
|
192
|
+
# if keyword-search available, insert the object into keyword search
|
193
|
+
@ferret << {:subject => subject, :object => object} if keyword_search?
|
191
194
|
end
|
192
195
|
|
196
|
+
@db.commit
|
193
197
|
@db
|
194
198
|
end
|
195
199
|
|
@@ -200,9 +204,6 @@ class RDFLite < ActiveRdfAdapter
|
|
200
204
|
|
201
205
|
# executing query, passing all where-clause values as parameters (so that
|
202
206
|
# sqlite will encode quotes correctly)
|
203
|
-
#constraints = right_hand_sides.collect { |value| value.to_s }
|
204
|
-
|
205
|
-
# executing query
|
206
207
|
results = @db.execute(sql, *conditions)
|
207
208
|
|
208
209
|
# if ASK query, we check whether we received a positive result count
|
@@ -230,16 +231,6 @@ class RDFLite < ActiveRdfAdapter
|
|
230
231
|
Node = Regexp.union(/_:\S*/,/<[^>]*>/,/"[^"]*"/)
|
231
232
|
SPOC = ['s','p','o','c']
|
232
233
|
|
233
|
-
# adds s,p,o into sqlite and ferret
|
234
|
-
# s,p,o should be in internal format: <uri> and "literal"
|
235
|
-
def add_internal(db, s, p, o, c)
|
236
|
-
# insert the triple into the datastore
|
237
|
-
db.execute('insert into triple values (?,?,?,?)', s,p,o,c)
|
238
|
-
|
239
|
-
# if keyword-search available, insert the object into keyword search
|
240
|
-
@ferret << {:subject => s, :object => o} if keyword_search?
|
241
|
-
end
|
242
|
-
|
243
234
|
# construct select clause
|
244
235
|
def construct_select(query)
|
245
236
|
# ASK queries counts the results, and return true if results > 0
|
@@ -375,7 +366,7 @@ class RDFLite < ActiveRdfAdapter
|
|
375
366
|
raise ActiveRdfError, "where clause #{clause} is not a triple" unless clause.is_a?(Array)
|
376
367
|
clause.each_with_index do |subclause, i|
|
377
368
|
# dont add where clause for variables
|
378
|
-
unless subclause.is_a?(Symbol)
|
369
|
+
unless subclause.is_a?(Symbol) || subclause.nil?
|
379
370
|
conditions = compute_where_condition(i, subclause, query.reasoning? && reasoning?)
|
380
371
|
if conditions.size == 1
|
381
372
|
where << "t#{level}.#{SPOC[i]} = ?"
|
@@ -1,9 +1,20 @@
|
|
1
|
-
|
1
|
+
# Author:: Eyal Oren
|
2
|
+
# Copyright:: (c) 2005-2006 Eyal Oren
|
3
|
+
# License:: LGPL
|
4
|
+
|
5
|
+
# The SuggestingAdapter is an extension to rdflite that can recommand
|
6
|
+
# additional predicates for a given resource, based on usage statistics in the
|
7
|
+
# whole dataset. E.g. given a dataset with FOAF data, one can ask a suggestion
|
8
|
+
# for a person and get a recommendation for this person to also use
|
9
|
+
# foaf:birthday. You can use this adapter in any collaborative editing setting:
|
10
|
+
# it leads the community to converge on terminology (everybody will use the
|
11
|
+
# same foaf:birthday to define somebody's birthday).
|
2
12
|
class SuggestingAdapter < FetchingAdapter
|
3
13
|
ConnectionPool.register_adapter(:suggesting,self)
|
4
14
|
|
5
15
|
alias _old_initialize initialize
|
6
16
|
|
17
|
+
# initialises the adapter, see RDFLite for description of possible parameters.
|
7
18
|
def initialize params
|
8
19
|
_old_initialize(params)
|
9
20
|
@db.execute('drop view if exists occurrence')
|
@@ -13,6 +24,7 @@ class SuggestingAdapter < FetchingAdapter
|
|
13
24
|
@db.execute('create view cooccurrence as select t0.p as p1,t1.p as p2, count(distinct t0.s) as count from triple as t0 join triple as t1 on t0.s=t1.s and t0.p!=t1.p group by t0.p, t1.p')
|
14
25
|
end
|
15
26
|
|
27
|
+
# suggests additional predicates that might be applicable for the given resource
|
16
28
|
def suggest(resource)
|
17
29
|
$activerdflog.debug "starting suggestions for #{size} triples"
|
18
30
|
time = Time.now
|
@@ -29,6 +41,7 @@ class SuggestingAdapter < FetchingAdapter
|
|
29
41
|
|
30
42
|
# fetch all predicates co-occurring with our predicates
|
31
43
|
candidates = predicates.collect {|p| cooccurring(p) }
|
44
|
+
return nil if candidates.empty?
|
32
45
|
|
33
46
|
# perform set intersection
|
34
47
|
candidates = candidates.inject {|intersect, n| intersect & n }.flatten
|
@@ -44,6 +57,7 @@ class SuggestingAdapter < FetchingAdapter
|
|
44
57
|
suggestions
|
45
58
|
end
|
46
59
|
|
60
|
+
private
|
47
61
|
def construct_occurrence_matrix
|
48
62
|
@occurrence = {}
|
49
63
|
@db.execute('select * from occurrence where count > 1') do |p,count|
|
@@ -0,0 +1,5 @@
|
|
1
|
+
_:1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://activerdf.org/test/Person> .
|
2
|
+
_:1 <http://activerdf.org/test/age> "27" .
|
3
|
+
_:1 <http://activerdf.org/test/name> "Eyal Oren" .
|
4
|
+
_:2 <http://activerdf.org/test/age> "27" .
|
5
|
+
_:2 <http://activerdf.org/test/eye> "blue" .
|
data/test/test_rdflite.rb
CHANGED
@@ -19,6 +19,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
19
19
|
def test_registration
|
20
20
|
adapter = ConnectionPool.add_data_source(:type => :rdflite)
|
21
21
|
assert_instance_of RDFLite, adapter
|
22
|
+
assert adapter.keyword_search?
|
22
23
|
end
|
23
24
|
|
24
25
|
def test_initialise
|
@@ -48,7 +49,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
48
49
|
|
49
50
|
adapter.add(eyal, age, test)
|
50
51
|
|
51
|
-
result = Query.new.distinct(:s).where(:s, :p, :o).execute
|
52
|
+
result = Query.new.distinct(:s).where(:s, :p, :o).execute(:flatten => true)
|
52
53
|
assert_instance_of RDFS::Resource, result
|
53
54
|
assert_equal 'eyaloren.org', result.uri
|
54
55
|
end
|
@@ -66,7 +67,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
66
67
|
adapter2.add(eyal, age, test2)
|
67
68
|
|
68
69
|
# assert only one distinct subject is found (same one in both adapters)
|
69
|
-
assert_equal 1, Query.new.distinct(:s).where(:s, :p, :o).execute
|
70
|
+
assert_equal 1, Query.new.distinct(:s).where(:s, :p, :o).execute.size
|
70
71
|
|
71
72
|
# assert two distinct objects are found
|
72
73
|
results = Query.new.distinct(:o).where(:s, :p, :o).execute
|
@@ -83,7 +84,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
83
84
|
test = RDFS::Resource.new 'test'
|
84
85
|
|
85
86
|
adapter.add(eyal, age, test)
|
86
|
-
Query.new.select(:s,:p).where(:s,:p,:o).execute do |s,p|
|
87
|
+
Query.new.select(:s,:p).where(:s,:p,:o).execute(:flatten => false) do |s,p|
|
87
88
|
assert_equal 'eyaloren.org', s.uri
|
88
89
|
assert_equal 'foaf:age', p.uri
|
89
90
|
end
|
@@ -95,6 +96,24 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
95
96
|
assert_equal 32, adapter.size
|
96
97
|
end
|
97
98
|
|
99
|
+
def test_load_bnodes
|
100
|
+
adapter = ConnectionPool.add_data_source :type => :rdflite
|
101
|
+
adapter.load(File.dirname(File.expand_path(__FILE__)) + '/test_bnode_data.nt')
|
102
|
+
|
103
|
+
# loaded five triples in total
|
104
|
+
assert_equal 5, adapter.size
|
105
|
+
|
106
|
+
# triples contain two distinct bnodes
|
107
|
+
assert_equal 2, Query.new.count.distinct(:s).where(:s,:p,:o).execute
|
108
|
+
|
109
|
+
# collecting the bnodes
|
110
|
+
bnodes = Query.new.distinct(:s).where(:s,:p,:o).execute
|
111
|
+
# assert that _:#1 occurs in three triples
|
112
|
+
assert_equal 3, Query.new.select(:p,:o).where(bnodes[0], :p, :o).execute.size
|
113
|
+
# assert that _:#2 occurs in two triples
|
114
|
+
assert_equal 2, Query.new.select(:p,:o).where(bnodes[1], :p, :o).execute.size
|
115
|
+
end
|
116
|
+
|
98
117
|
def test_count_query
|
99
118
|
adapter = ConnectionPool.add_data_source :type => :rdflite
|
100
119
|
adapter.load(File.dirname(File.expand_path(__FILE__)) + '/test_data.nt')
|
@@ -107,7 +126,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
107
126
|
file = File.dirname(File.expand_path(__FILE__)) + '/test_data.nt'
|
108
127
|
adapter.load(file)
|
109
128
|
|
110
|
-
context = Query.new.distinct(:c).where(:s,:p,:o,:c).execute
|
129
|
+
context = Query.new.distinct(:c).where(:s,:p,:o,:c).execute(:flatten => true)
|
111
130
|
assert_instance_of RDFS::Resource, context
|
112
131
|
assert_equal RDFS::Resource.new("file:#{file}"), context
|
113
132
|
end
|
@@ -127,8 +146,8 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
127
146
|
assert_equal file_context, context[0]
|
128
147
|
assert_equal '', context[1]
|
129
148
|
|
130
|
-
n1 = Query.new.distinct(:s).where(:s
|
131
|
-
n2 = Query.new.distinct(:s).where(:s
|
149
|
+
n1 = Query.new.distinct(:s).where(:s, :p, :o, '').execute
|
150
|
+
n2 = Query.new.distinct(:s).where(:s, :p, :o, file_context).execute
|
132
151
|
assert_equal 1, n1.size
|
133
152
|
assert_equal 9, n2.size
|
134
153
|
end
|
@@ -144,7 +163,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
144
163
|
type = Namespace.lookup(:rdf, :type)
|
145
164
|
resource = Namespace.lookup(:rdfs,:resource)
|
146
165
|
|
147
|
-
color = Query.new.select(:o).where(eyal, eye,:o).execute
|
166
|
+
color = Query.new.select(:o).where(eyal, eye,:o).execute(:flatten => true)
|
148
167
|
assert 'blue', color
|
149
168
|
assert_instance_of String, color
|
150
169
|
|
@@ -162,7 +181,7 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
162
181
|
adapter.delete(eyal, nil, nil)
|
163
182
|
assert_equal 27, adapter.size
|
164
183
|
|
165
|
-
adapter.delete(nil,nil,nil)
|
184
|
+
adapter.delete(nil, nil, nil)
|
166
185
|
assert_equal 0, adapter.size
|
167
186
|
end
|
168
187
|
|
@@ -171,9 +190,9 @@ class TestRdfLiteAdapter < Test::Unit::TestCase
|
|
171
190
|
adapter.load(File.dirname(File.expand_path(__FILE__)) + '/test_data.nt')
|
172
191
|
|
173
192
|
eyal = RDFS::Resource.new('http://activerdf.org/test/eyal')
|
174
|
-
assert_equal eyal, Query.new.distinct(:s).where(:s,:keyword,"blue").execute
|
175
|
-
assert_equal eyal, Query.new.distinct(:s).where(:s,:keyword,"27").execute
|
176
|
-
assert_equal eyal, Query.new.distinct(:s).where(:s,:keyword,"eyal oren").execute
|
193
|
+
assert_equal eyal, Query.new.distinct(:s).where(:s,:keyword,"blue").execute(:flatten => true)
|
194
|
+
assert_equal eyal, Query.new.distinct(:s).where(:s,:keyword,"27").execute(:flatten => true)
|
195
|
+
assert_equal eyal, Query.new.distinct(:s).where(:s,:keyword,"eyal oren").execute(:flatten => true)
|
177
196
|
end
|
178
197
|
|
179
198
|
def test_bnodes
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activerdf_rdflite
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "1.
|
7
|
-
date: 2006-12-
|
6
|
+
version: "1.2"
|
7
|
+
date: 2006-12-21 00:00:00 +01:00
|
8
8
|
summary: an RDF database for usage in ActiveRDF (based on sqlite3)
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -34,6 +34,7 @@ files:
|
|
34
34
|
- Rakefile
|
35
35
|
- test/test_rdflite.rb
|
36
36
|
- test/test_data.nt
|
37
|
+
- test/test_bnode_data.nt
|
37
38
|
- lib/activerdf_rdflite
|
38
39
|
- lib/activerdf_rdflite/init.rb
|
39
40
|
- lib/activerdf_rdflite/rdflite.rb
|
@@ -61,6 +62,15 @@ dependencies:
|
|
61
62
|
- !ruby/object:Gem::Version
|
62
63
|
version: 0.2.1
|
63
64
|
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: uuidtools
|
67
|
+
version_requirement:
|
68
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 0.0.0
|
73
|
+
version:
|
64
74
|
- !ruby/object:Gem::Dependency
|
65
75
|
name: activerdf
|
66
76
|
version_requirement:
|
@@ -68,7 +78,7 @@ dependencies:
|
|
68
78
|
requirements:
|
69
79
|
- - ">="
|
70
80
|
- !ruby/object:Gem::Version
|
71
|
-
version:
|
81
|
+
version: "1.2"
|
72
82
|
version:
|
73
83
|
- !ruby/object:Gem::Dependency
|
74
84
|
name: sqlite3-ruby
|
@@ -77,5 +87,5 @@ dependencies:
|
|
77
87
|
requirements:
|
78
88
|
- - ">="
|
79
89
|
- !ruby/object:Gem::Version
|
80
|
-
version: 1.1.0
|
90
|
+
version: 1.1.0.1
|
81
91
|
version:
|