activerdf_net7 1.6.16 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +63 -0
- data/activerdf-jena/lib/activerdf_jena/jena.rb +4 -4
- data/activerdf-jena/lib/activerdf_jena/jena_adapter.rb +55 -55
- data/activerdf-jena/lib/activerdf_jena/lucene.rb +1 -1
- data/activerdf-jena/lib/activerdf_jena/ng4j.rb +7 -7
- data/activerdf-jena/lib/activerdf_jena/ng4j_adapter.rb +47 -47
- data/activerdf-jena/lib/activerdf_jena/pellet.rb +1 -1
- data/activerdf-jena/test/test_jena_adapter.rb +121 -120
- data/activerdf-jena/test/test_ng4j_adapter.rb +111 -110
- data/activerdf-rdflite/lib/activerdf_rdflite/fetching.rb +23 -19
- data/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +153 -277
- data/activerdf-rdflite/lib/activerdf_rdflite/suggesting.rb +2 -2
- data/activerdf-rdflite/test/test_fetching.rb +7 -22
- data/activerdf-rdflite/test/test_rdflite.rb +44 -257
- data/activerdf-redland/lib/activerdf_redland/redland.rb +246 -282
- data/activerdf-redland/test/test_redland_adapter.rb +62 -224
- data/activerdf-sesame/ext/wrapper-sesame2.jar +0 -0
- data/activerdf-sesame/java/build.number +2 -2
- data/activerdf-sesame/java/build.xml +0 -0
- data/activerdf-sesame/java/lib/junit-3.8.2.jar +0 -0
- data/activerdf-sesame/java/settings.xml +0 -0
- data/activerdf-sesame/java/src/org/activerdf/wrapper/sesame2/WrapperForSesame2.java +0 -0
- data/activerdf-sesame/java/temp/build/org/activerdf/wrapper/sesame2/WrapperForSesame2.class +0 -0
- data/activerdf-sesame/java/temp/manifest/MANIFEST.MF +2 -2
- data/activerdf-sesame/java/test-src/org/activerdf/wrapper/sesame2/TestWrapperForSesame2.java +0 -0
- data/activerdf-sesame/lib/activerdf_sesame/sesame.rb +360 -364
- data/activerdf-sesame/test/test_sesame_adapter.rb +85 -83
- data/activerdf-sparql/lib/activerdf_sparql/sparql.rb +147 -148
- data/activerdf-sparql/lib/activerdf_sparql/sparql_result_parser.rb +5 -5
- data/activerdf-sparql/test/test_sparql_adapter.rb +2 -0
- data/activerdf-yars/lib/activerdf_yars/jars2.rb +85 -83
- data/lib/active_rdf/federation/active_rdf_adapter.rb +26 -39
- data/lib/active_rdf/federation/connection_pool.rb +119 -110
- data/lib/active_rdf/federation/federation_manager.rb +51 -51
- data/lib/active_rdf/objectmanager/bnode.rb +8 -2
- data/lib/active_rdf/objectmanager/literal.rb +81 -50
- data/lib/active_rdf/objectmanager/namespace.rb +117 -84
- data/lib/active_rdf/objectmanager/object_manager.rb +101 -96
- data/lib/active_rdf/objectmanager/ordered_set.rb +1 -1
- data/lib/active_rdf/objectmanager/property.rb +345 -0
- data/lib/active_rdf/objectmanager/property_list.rb +4 -4
- data/lib/active_rdf/objectmanager/property_lookup.rb +57 -0
- data/lib/active_rdf/objectmanager/resource.rb +293 -501
- data/lib/active_rdf/objectmanager/resource_like.rb +2 -2
- data/lib/active_rdf/objectmanager/resource_query.rb +85 -0
- data/lib/active_rdf/queryengine/ntriples_parser.rb +75 -68
- data/lib/active_rdf/queryengine/query.rb +237 -183
- data/lib/active_rdf/queryengine/query2jars2.rb +17 -15
- data/lib/active_rdf/queryengine/query2sparql.rb +107 -101
- data/lib/active_rdf.rb +28 -17
- data/lib/active_rdf_helpers.rb +37 -5
- data/lib/active_rdf_log.rb +11 -11
- data/test/adapters/test_activerdf_adapter.rb +138 -0
- data/test/{test_adapters.rb → adapters/test_adapters.rb} +6 -24
- data/test/adapters/test_bnode_capable_adapter.rb +31 -0
- data/test/adapters/test_context_aware_adapter.rb +31 -0
- data/test/adapters/test_network_aware_adapter.rb +29 -0
- data/test/adapters/test_persistent_adapter.rb +21 -0
- data/test/adapters/test_read_only_adapter.rb +15 -0
- data/test/adapters/test_reasoning_adapter.rb +11 -0
- data/test/adapters/test_writable_adapter.rb +163 -0
- data/test/common.rb +78 -96
- data/test/federation/test_connection_pool.rb +25 -44
- data/test/federation/test_federation_manager.rb +45 -45
- data/test/objectmanager/test_literal.rb +47 -26
- data/test/objectmanager/test_namespace.rb +3 -1
- data/test/objectmanager/test_object_manager.rb +35 -45
- data/test/objectmanager/test_ordered_set.rb +1 -1
- data/test/objectmanager/test_property.rb +261 -0
- data/test/objectmanager/test_resource_reading.rb +196 -104
- data/test/objectmanager/test_resource_reasoning.rb +26 -0
- data/test/objectmanager/test_resource_writing.rb +34 -25
- data/test/queryengine/my_external_resource.rb +5 -1
- data/test/queryengine/test_external_resource_class.rb +1 -8
- data/test/queryengine/test_ntriples_parser.rb +5 -3
- data/test/queryengine/test_query.rb +3 -3
- data/test/queryengine/test_query2jars2.rb +2 -2
- data/test/queryengine/test_query2sparql.rb +2 -2
- data/test/queryengine/test_query_engine.rb +46 -28
- metadata +16 -8
- data/activerdf-rdflite/test/test_bnode_data.nt +0 -5
- data/activerdf-rdflite/test/test_data.nt +0 -32
- data/activerdf-rdflite/test/test_escaped_data.nt +0 -2
- data/activerdf-redland/test/test_person_data.nt +0 -42
- data/test/objectmanager/test_talia_syntax.rb +0 -68
@@ -10,28 +10,19 @@ require 'queryengine/ntriples_parser'
|
|
10
10
|
require 'open-uri'
|
11
11
|
require 'mime/types'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# RDFLite is a lightweight RDF database on top of sqlite3. It can act as adapter
|
18
|
-
# in ActiveRDF. It supports on-disk and in-memory usage, and allows keyword
|
13
|
+
# RDFLite is a lightweight RDF database on top of sqlite3. It can act as adapter
|
14
|
+
# in ActiveRDF. It supports on-disk and in-memory usage, and allows keyword
|
19
15
|
# search if ferret is installed.
|
20
|
-
|
16
|
+
module ActiveRDF
|
17
|
+
class RDFLite < ActiveRdfAdapter
|
18
|
+
ActiveRdfLogger::log_info "Loading RDFLite adapter", self
|
21
19
|
|
22
|
-
|
23
|
-
begin
|
20
|
+
begin
|
24
21
|
require 'ferret'
|
25
|
-
|
22
|
+
@@have_ferret = true
|
26
23
|
rescue LoadError
|
27
|
-
ActiveRdfLogger::log_info "Keyword search is disabled since we could not load Ferret. To
|
28
|
-
|
29
|
-
@have_ferret = false
|
30
|
-
end
|
31
|
-
|
32
|
-
def has_ferret?
|
33
|
-
@have_ferret
|
34
|
-
end
|
24
|
+
ActiveRdfLogger::log_info "Keyword search is disabled since we could not load Ferret. To enable, please do \"gem install ferret\"", self
|
25
|
+
@@have_ferret = false
|
35
26
|
end
|
36
27
|
|
37
28
|
ConnectionPool.register_adapter(:rdflite,self)
|
@@ -46,19 +37,27 @@ class RDFLite < ActiveRdfAdapter
|
|
46
37
|
super()
|
47
38
|
ActiveRdfLogger::log_info(self) { "Initialised rdflite with params #{params.to_s}" }
|
48
39
|
|
49
|
-
@
|
50
|
-
@
|
40
|
+
@reasoning = truefalse(params[:reasoning], false)
|
41
|
+
@subprops = {} if @reasoning
|
51
42
|
|
52
43
|
# if no file-location given, we use in-memory store
|
53
44
|
file = params[:location] || ':memory:'
|
54
|
-
@db = SQLite3::Database.new(file)
|
45
|
+
@db = SQLite3::Database.new(file)
|
55
46
|
|
56
47
|
# disable keyword search by default, enable only if ferret is found
|
57
|
-
@keyword_search = params[:keyword]
|
58
|
-
@keyword_search &= self.class.has_ferret?
|
48
|
+
@keyword_search = truefalse(params[:keyword], false) && @@have_ferret
|
59
49
|
|
60
|
-
|
61
|
-
@
|
50
|
+
# turn off filesystem synchronisation for speed
|
51
|
+
@db.synchronous = 'off'
|
52
|
+
|
53
|
+
# drop the table if a new datastore is requested
|
54
|
+
@db.execute('drop table if exists triple') if truefalse(params[:new],false)
|
55
|
+
|
56
|
+
# create triples table. ignores duplicated triples
|
57
|
+
@db.execute('create table if not exists triple(s,p,o,c, unique(s,p,o,c) on conflict ignore)')
|
58
|
+
|
59
|
+
create_indices(params)
|
60
|
+
@db
|
62
61
|
|
63
62
|
if keyword_search?
|
64
63
|
# we initialise the ferret index, either as a file or in memory
|
@@ -74,15 +73,6 @@ class RDFLite < ActiveRdfAdapter
|
|
74
73
|
Ferret::I.new(:field_infos => infos)
|
75
74
|
end
|
76
75
|
end
|
77
|
-
|
78
|
-
# turn off filesystem synchronisation for speed
|
79
|
-
@db.synchronous = 'off'
|
80
|
-
|
81
|
-
# create triples table. ignores duplicated triples
|
82
|
-
@db.execute('create table if not exists triple(s,p,o,c, unique(s,p,o,c) on conflict ignore)')
|
83
|
-
|
84
|
-
create_indices(params)
|
85
|
-
@db
|
86
76
|
end
|
87
77
|
|
88
78
|
# returns the number of triples in the datastore (incl. possible duplicates)
|
@@ -110,19 +100,16 @@ class RDFLite < ActiveRdfAdapter
|
|
110
100
|
|
111
101
|
# deletes triple(s,p,o,c) from datastore
|
112
102
|
# symbol parameters match anything: delete(:s,:p,:o) will delete all triples
|
113
|
-
# you can specify a context to limit deletion to that context:
|
103
|
+
# you can specify a context to limit deletion to that context:
|
114
104
|
# delete(:s,:p,:o, 'http://context') will delete all triples with that context
|
115
|
-
def delete(s, p, o, c=nil)
|
116
|
-
# convert non-nil input to internal format
|
117
|
-
quad = [s,p,o,c].collect {|r| r.nil? ? nil : internalise(r) }
|
118
|
-
|
119
|
-
# construct where clause for deletion (for all non-nil input)
|
105
|
+
def delete(s, p, o=nil, c=nil)
|
120
106
|
where_clauses = []
|
121
|
-
conditions = []
|
122
|
-
|
123
|
-
|
124
|
-
|
107
|
+
conditions = []
|
108
|
+
|
109
|
+
[s,p,o,c].each_with_index do |r,i|
|
110
|
+
unless r.nil? or check_type(r, Symbol)
|
125
111
|
where_clauses << "#{SPOC[i]} = ?"
|
112
|
+
conditions << r.to_literal_s
|
126
113
|
end
|
127
114
|
end
|
128
115
|
|
@@ -130,7 +117,7 @@ class RDFLite < ActiveRdfAdapter
|
|
130
117
|
ds = 'delete from triple'
|
131
118
|
ds << " where #{where_clauses.join(' and ')}" unless where_clauses.empty?
|
132
119
|
|
133
|
-
# execute delete string with possible deletion conditions (for each
|
120
|
+
# execute delete string with possible deletion conditions (for each
|
134
121
|
# non-empty where clause)
|
135
122
|
ActiveRdfLogger::log_debug(self) { "Deleting #{[s,p,o,c].join(' ')}" }
|
136
123
|
@db.execute(ds, *conditions)
|
@@ -150,14 +137,10 @@ class RDFLite < ActiveRdfAdapter
|
|
150
137
|
raise(ActiveRdfError, "adding non-resource #{s} while adding (#{s},#{p},#{o},#{c})") unless s.respond_to?(:uri)
|
151
138
|
raise(ActiveRdfError, "adding non-resource #{p} while adding (#{s},#{p},#{o},#{c})") unless p.respond_to?(:uri)
|
152
139
|
|
153
|
-
|
154
|
-
add_ntriples(triple.join(' ') + " .\n", serialise(c) )
|
155
|
-
|
156
|
-
## get internal representation (array)
|
157
|
-
#quad = [s,p,o,c].collect {|r| internalise(r) }
|
140
|
+
c = c.to_literal_s unless c.nil?
|
158
141
|
|
159
|
-
|
160
|
-
|
142
|
+
# insert triple into database
|
143
|
+
@db.execute('insert into triple values (?,?,?,?);',s.to_literal_s,p.to_literal_s,o.to_literal_s,c)
|
161
144
|
|
162
145
|
## if keyword-search available, insert the object into keyword search
|
163
146
|
#@ferret << {:subject => s, :object => o} if keyword_search?
|
@@ -165,28 +148,31 @@ class RDFLite < ActiveRdfAdapter
|
|
165
148
|
|
166
149
|
# flushes openstanding changes to underlying sqlite3
|
167
150
|
def flush
|
168
|
-
# since we always write changes into sqlite3 immediately, we don't do
|
151
|
+
# since we always write changes into sqlite3 immediately, we don't do
|
169
152
|
# anything here
|
170
153
|
true
|
171
154
|
end
|
172
155
|
|
173
156
|
# loads triples from file in ntriples format
|
174
|
-
def load(location)
|
175
|
-
context = if
|
176
|
-
location
|
157
|
+
def load(location, syntax = nil)
|
158
|
+
context = if @contexts
|
159
|
+
if URI.parse(location).host
|
160
|
+
RDFS::Resource.new(location)
|
161
|
+
else
|
162
|
+
RDFS::Resource.new("file:#{location}")
|
163
|
+
end
|
177
164
|
else
|
178
|
-
|
165
|
+
nil
|
179
166
|
end
|
180
167
|
|
181
|
-
|
182
|
-
when MIME::Types['application/rdf+xml']
|
168
|
+
if MIME::Types.of(location) == MIME::Types['application/rdf+xml'] or syntax == 'rdfxml'
|
183
169
|
# check if rapper available
|
184
|
-
begin
|
170
|
+
begin
|
185
171
|
# can only parse rdf/xml with redland
|
186
172
|
# die otherwise
|
187
173
|
require 'rdf/redland'
|
188
174
|
model = Redland::Model.new
|
189
|
-
Redland::Parser.new.parse_into_model(model, location)
|
175
|
+
Redland::Parser.new(syntax).parse_into_model(model, location)
|
190
176
|
add_ntriples(model.to_string('ntriples'), location)
|
191
177
|
rescue LoadError
|
192
178
|
raise ActiveRdfError, "cannot parse remote rdf/xml file without Redland: please install Redland (librdf.org) and its Ruby bindings"
|
@@ -198,21 +184,16 @@ class RDFLite < ActiveRdfAdapter
|
|
198
184
|
end
|
199
185
|
|
200
186
|
# adds ntriples from given context into datastore
|
201
|
-
def add_ntriples(ntriples, context)
|
187
|
+
def add_ntriples(ntriples, context = nil)
|
202
188
|
# add each triple to db
|
203
189
|
@db.transaction
|
204
|
-
insert = @db.prepare('insert into triple values (?,?,?,?);')
|
205
190
|
|
206
191
|
ntriples = NTriplesParser.parse(ntriples)
|
207
192
|
ntriples.each do |s,p,o|
|
208
|
-
|
209
|
-
subject, predicate, object = [s,p,o].collect {|r| internalise(r) }
|
210
|
-
|
211
|
-
# insert triple into database
|
212
|
-
insert.execute(subject, predicate, object, context)
|
193
|
+
add(s,p,o,context)
|
213
194
|
|
214
195
|
# if keyword-search available, insert the object into keyword search
|
215
|
-
@ferret << {:subject =>
|
196
|
+
@ferret << {:subject => s.to_s, :object => o.to_s} if keyword_search?
|
216
197
|
end
|
217
198
|
|
218
199
|
@db.commit
|
@@ -220,11 +201,11 @@ class RDFLite < ActiveRdfAdapter
|
|
220
201
|
end
|
221
202
|
|
222
203
|
# executes ActiveRDF query on datastore
|
223
|
-
def
|
204
|
+
def execute(query)
|
224
205
|
# construct query clauses
|
225
206
|
sql, conditions = translate(query)
|
226
207
|
|
227
|
-
# executing query, passing all where-clause values as parameters (so that
|
208
|
+
# executing query, passing all where-clause values as parameters (so that
|
228
209
|
# sqlite will encode quotes correctly)
|
229
210
|
results = @db.execute(sql, *conditions)
|
230
211
|
|
@@ -288,91 +269,68 @@ class RDFLite < ActiveRdfAdapter
|
|
288
269
|
if not query.sort_clauses.empty?
|
289
270
|
sort = query.sort_clauses.collect { |term| variable_name(query, term) }
|
290
271
|
" order by (#{sort.join(',')})"
|
291
|
-
elsif not query.reverse_sort_clauses.empty?
|
292
|
-
sort = query.reverse_sort_clauses.collect { |term| variable_name(query, term) }
|
293
|
-
" order by (#{sort.join(',')}) DESC"
|
294
272
|
else
|
295
273
|
""
|
296
274
|
end
|
297
275
|
end
|
298
276
|
|
299
277
|
# construct join clause
|
300
|
-
#
|
301
|
-
# only, and we should only alias tables we didnt alias yet)
|
302
|
-
# we should only look for one join clause in each where-clause: when we find
|
303
|
-
# one, we skip the rest of the variables in this clause.
|
278
|
+
# begins with first element of construct traverses tables referenced by
|
304
279
|
def construct_join(query)
|
305
|
-
join_stmt =
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
280
|
+
join_stmt = []
|
281
|
+
seen_aliases = ['t0'] # first table already seen
|
282
|
+
seen_vars = []
|
283
|
+
|
284
|
+
# get a hash with indices for for all terms
|
285
|
+
# if the term doesnt have a join-buddy, we can skip it
|
286
|
+
occurances = term_occurances(query).reject{|var,terms| terms.size < 2}
|
287
|
+
|
288
|
+
# start with variables in first where clause
|
289
|
+
var_queue = query.where_clauses[0].find_all{|obj| check_type(obj, Symbol) and occurances.include?(obj)}
|
290
|
+
|
291
|
+
while !var_queue.empty? do
|
292
|
+
var = var_queue.shift
|
293
|
+
seen_vars << var
|
294
|
+
terms = occurances[var]
|
295
|
+
|
296
|
+
# look for a term in a table that has already been seen
|
297
|
+
table,field = terms.find{|table,field| seen_aliases.include?(table)}
|
298
|
+
raise ActiveRdfError, "query is confused. haven't seen #{table} for :#{var} yet." unless table
|
299
|
+
terms -= [[table,field]] # ignore this previously seen buddy term table
|
300
|
+
first_term = "#{table}.#{field}"
|
301
|
+
|
302
|
+
terms.each do |table,field|
|
303
|
+
join = ''
|
304
|
+
unless seen_aliases.include?(table)
|
305
|
+
seen_aliases << table
|
306
|
+
join << "join triple as #{table} on "
|
307
|
+
else
|
308
|
+
join << "and "
|
309
|
+
end
|
310
|
+
join << "#{first_term}=#{table}.#{field} "
|
311
|
+
join_stmt << join
|
312
312
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
where_clauses.each_with_index do |term, index|
|
317
|
-
ary = (term_occurrences[term] ||= [])
|
318
|
-
ary << index
|
313
|
+
# add any terms from this table that haven't been seen yet to the queue
|
314
|
+
var_queue.concat query.where_clauses[table[1..-1].to_i].find_all{|obj| check_type(obj, Symbol) and !seen_vars.include?(obj) and occurances.include?(obj)}
|
315
|
+
end
|
319
316
|
end
|
320
317
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
# if the term has been joined with his buddy already, we can skip it
|
325
|
-
next unless considering.include?(term)
|
326
|
-
|
327
|
-
# we find all (other) occurrences of this term
|
328
|
-
indices = term_occurrences[term]
|
329
|
-
|
330
|
-
# if the term doesnt have a join-buddy, we can skip it
|
331
|
-
next if indices.size == 1
|
332
|
-
|
333
|
-
# construct t0,t1,... as aliases for term
|
334
|
-
# and construct join condition, e.g. t0.s
|
335
|
-
termalias = "t#{index / 4}"
|
336
|
-
termjoin = "#{termalias}.#{SPOC[index % 4]}"
|
337
|
-
|
338
|
-
join = if join_stmt.include?(termalias)
|
339
|
-
""
|
340
|
-
else
|
341
|
-
"triple as #{termalias}"
|
342
|
-
end
|
318
|
+
join = ' from triple as t0 '
|
319
|
+
join_stmt.empty? ? join : join + "#{join_stmt.join(' ')} "
|
320
|
+
end
|
343
321
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
# TODO: fix reuse of same table names as aliases, e.g.
|
354
|
-
# "from triple as t1 join triple as t2 on ... join t1 on ..."
|
355
|
-
# is not allowed as such by sqlite
|
356
|
-
# but on the other hand, restating the aliases gives ambiguity:
|
357
|
-
# "from triple as t1 join triple as t2 on ... join triple as t1 ..."
|
358
|
-
# is ambiguous
|
359
|
-
if join_stmt.include?(buddyalias)
|
360
|
-
join << "and #{termjoin} = #{buddyjoin}"
|
361
|
-
else
|
362
|
-
join << " join triple as #{buddyalias} on #{termjoin} = #{buddyjoin} "
|
322
|
+
# Returns a hash of arrays, keyed by the term symbol. Each element of the array is nested array of a pair of values: [table alias, field('s'|'p'|'o'|'c')]
|
323
|
+
# {:s => [[table,field],['t0','s'],...], :p => [['t0','p'],['t1','p']]}
|
324
|
+
def term_occurances(query)
|
325
|
+
term_occurances = {}
|
326
|
+
query.where_clauses.each_with_index do |clause, table_index|
|
327
|
+
clause.zip(SPOC).each do |obj,field|
|
328
|
+
if check_type(obj, Symbol)
|
329
|
+
(term_occurances[obj] ||= []) << ["t#{table_index}",field]
|
363
330
|
end
|
364
331
|
end
|
365
|
-
join_stmt << join
|
366
|
-
|
367
|
-
# remove term from 'todo' list of still-considered terms
|
368
|
-
considering.delete(term)
|
369
|
-
end
|
370
|
-
|
371
|
-
if join_stmt == ''
|
372
|
-
return " from triple as t0 "
|
373
|
-
else
|
374
|
-
return " from #{join_stmt} "
|
375
332
|
end
|
333
|
+
term_occurances
|
376
334
|
end
|
377
335
|
|
378
336
|
# construct where clause
|
@@ -380,25 +338,45 @@ class RDFLite < ActiveRdfAdapter
|
|
380
338
|
# collecting where clauses, these will be added to the sql string later
|
381
339
|
where = []
|
382
340
|
|
383
|
-
# collecting all the right-hand sides of where clauses (e.g. where name =
|
384
|
-
# 'abc'), to add to query string later using ?-notation, because then
|
341
|
+
# collecting all the right-hand sides of where clauses (e.g. where name =
|
342
|
+
# 'abc'), to add to query string later using ?-notation, because then
|
385
343
|
# sqlite will automatically encode quoted literals correctly
|
386
344
|
right_hand_sides = []
|
387
345
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
346
|
+
query.where_clauses.each_with_index do |clause, table_index|
|
347
|
+
clause.zip(SPOC).each do |clause_elem,field|
|
348
|
+
if !(check_type(clause_elem, Symbol) or clause_elem.nil?)
|
349
|
+
# include querying on subproperty fields
|
350
|
+
if field == 'p' and query.reasoning? and $activerdf_internal_reasoning
|
351
|
+
predicate = clause_elem
|
352
|
+
predicates = [predicate] + predicate.sub_predicates
|
353
|
+
if predicates.size > 1
|
354
|
+
where << "t#{table_index}.#{field} in ('#{predicates.collect{|res| res.to_literal_s}.join("','")}')"
|
355
|
+
else
|
356
|
+
where << "t#{table_index}.#{field} = ?"
|
357
|
+
right_hand_sides << predicates[0].to_literal_s
|
358
|
+
end
|
399
359
|
else
|
400
|
-
|
401
|
-
|
360
|
+
# match plain strings to all strings
|
361
|
+
if query.all_types? and !clause_elem.respond_to?(:uri) # dont wildcard resources
|
362
|
+
where << "t#{table_index}.#{field} like ?"
|
363
|
+
right_hand_sides << "\"#{clause_elem.to_s}\"%"
|
364
|
+
else
|
365
|
+
where << "t#{table_index}.#{field} = ?"
|
366
|
+
right_hand_sides << clause_elem.to_literal_s
|
367
|
+
end
|
368
|
+
end
|
369
|
+
# process filters
|
370
|
+
elsif field == 'o' and check_type(clause_elem, Symbol) and (filter = query.filter_clauses[clause_elem])
|
371
|
+
operator, operand = filter
|
372
|
+
case operator
|
373
|
+
when :datatype
|
374
|
+
where << "t#{table_index}.o like ?"
|
375
|
+
right_hand_sides << "%\"^^<#{operand}>"
|
376
|
+
when :lang
|
377
|
+
lang, exact = operand
|
378
|
+
where << "t#{table_index}.o like ?"
|
379
|
+
right_hand_sides << (exact ? "%\"@#{lang}" : "%\"@%#{lang}%")
|
402
380
|
end
|
403
381
|
end
|
404
382
|
end
|
@@ -426,100 +404,34 @@ class RDFLite < ActiveRdfAdapter
|
|
426
404
|
end
|
427
405
|
end
|
428
406
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
case index
|
435
|
-
when 0: ;
|
436
|
-
# no rule for subjects
|
437
|
-
when 1:
|
438
|
-
# expand properties to include all subproperties
|
439
|
-
conditions = subproperties(subclause) if subclause.respond_to?(:uri)
|
440
|
-
when 2:
|
441
|
-
# no rule for objects
|
442
|
-
when 3:
|
443
|
-
# no rule for contexts
|
444
|
-
end
|
445
|
-
end
|
446
|
-
|
447
|
-
# convert conditions into internal format
|
448
|
-
#conditions.collect { |c| c.respond_to?(:uri) ? "<#{c.uri}>" : c.to_s }
|
449
|
-
conditions.collect { |c| internalise(c) }
|
450
|
-
end
|
451
|
-
|
452
|
-
def subproperties(resource)
|
453
|
-
# compute and store subproperties of this resource
|
454
|
-
# or use earlier computed value if available
|
455
|
-
unless @subprops[resource]
|
456
|
-
subproperty = Namespace.lookup(:rdfs,:subPropertyOf)
|
457
|
-
children_query = Query.new.distinct(:sub).where(:sub, subproperty, resource)
|
458
|
-
children_query.reasoning = false
|
459
|
-
children = children_query.execute
|
460
|
-
|
461
|
-
if children.empty?
|
462
|
-
@subprops[resource] = [resource]
|
463
|
-
else
|
464
|
-
@subprops[resource] = [resource] + children.collect{|c| subproperties(c)}.flatten.compact
|
465
|
-
end
|
407
|
+
# returns first sql variable name found for a queryterm
|
408
|
+
def variable_name(query,term)
|
409
|
+
if (indices = term_occurances(query)[term])
|
410
|
+
table, field = indices[0]
|
411
|
+
"#{table}.#{field}"
|
466
412
|
end
|
467
|
-
@subprops[resource]
|
468
413
|
end
|
469
414
|
|
470
|
-
#
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
# but maybe it appears in a keyword clause
|
479
|
-
|
480
|
-
# index would not be nil if we had:
|
481
|
-
# select(:o).where(knud, knows, :o).where(:o, :keyword, 'eyal')
|
482
|
-
#
|
483
|
-
# the only possibility that index is nil is if we have:
|
484
|
-
# select(:o).where(:o, :keyword, :eyal) (selecting subject)
|
485
|
-
# or if we use a select clause that does not appear in any where clause
|
486
|
-
|
487
|
-
# so we check if we find the term in the keyword clauses, otherwise we throw
|
488
|
-
# an error
|
489
|
-
if query.keywords.keys.include?(term)
|
490
|
-
return "t0.s"
|
491
|
-
else
|
492
|
-
raise ActiveRdfError, "unbound variable :#{term.to_s} in select of #{query.to_sp}"
|
493
|
-
end
|
415
|
+
# "safe" type checking that will not trigger additional queries
|
416
|
+
# on RDFS::Resource. This assumes that the klass is not a Resource
|
417
|
+
# type itself
|
418
|
+
def check_type(item, klass)
|
419
|
+
if(item.respond_to?(:uri))
|
420
|
+
item.class == klass
|
421
|
+
else
|
422
|
+
item.is_a?(klass)
|
494
423
|
end
|
495
|
-
|
496
|
-
termtable = "t#{index / 4}"
|
497
|
-
termspo = SPOC[index % 4]
|
498
|
-
return "#{termtable}.#{termspo}"
|
499
424
|
end
|
500
425
|
|
501
|
-
# wrap resources into ActiveRDF resources, literals into Strings
|
502
|
-
# is the type that should be used for ActiveRDF resources
|
426
|
+
# wrap resources into ActiveRDF resources, literals into Strings
|
503
427
|
def wrap(results, result_type)
|
504
428
|
results.collect do |row|
|
505
429
|
row.collect { |result| parse(result, result_type) }
|
506
430
|
end
|
507
431
|
end
|
508
432
|
|
509
|
-
|
510
|
-
|
511
|
-
def parse(result, result_type = RDFS::Resource)
|
512
|
-
NTriplesParser.parse_node(result, result_type) || result
|
513
|
-
# case result
|
514
|
-
# when Literal
|
515
|
-
# # replace special characters to allow string interpolation for e.g. 'test\nbreak'
|
516
|
-
# $1.double_quote
|
517
|
-
# when Resource
|
518
|
-
# result_type.new($1)
|
519
|
-
# else
|
520
|
-
# # when we do a count(*) query we get a number, not a resource/literal
|
521
|
-
# result
|
522
|
-
# end
|
433
|
+
def parse(result, result_type)
|
434
|
+
NTriplesParser.parse_node(result, result_type)
|
523
435
|
end
|
524
436
|
|
525
437
|
def create_indices(params)
|
@@ -532,7 +444,7 @@ class RDFLite < ActiveRdfAdapter
|
|
532
444
|
opidx = params[:opidx] || false
|
533
445
|
|
534
446
|
# creating lookup indices
|
535
|
-
@db.transaction do
|
447
|
+
@db.transaction do
|
536
448
|
@db.execute('create index if not exists sidx on triple(s)') if sidx
|
537
449
|
@db.execute('create index if not exists pidx on triple(p)') if pidx
|
538
450
|
@db.execute('create index if not exists oidx on triple(o)') if oidx
|
@@ -542,41 +454,5 @@ class RDFLite < ActiveRdfAdapter
|
|
542
454
|
@db.execute('create index if not exists opidx on triple(o,p)') if opidx
|
543
455
|
end
|
544
456
|
end
|
545
|
-
|
546
|
-
# transform triple into internal format <uri> and "literal"
|
547
|
-
def internalise(r)
|
548
|
-
if r.nil? or r.is_a? Symbol
|
549
|
-
nil
|
550
|
-
else
|
551
|
-
r.to_ntriple
|
552
|
-
end
|
553
|
-
end
|
554
|
-
|
555
|
-
# transform resource/literal into ntriples format
|
556
|
-
def serialise(r)
|
557
|
-
# Fixme: r is most likely NOT a resource
|
558
|
-
if r.nil?
|
559
|
-
nil
|
560
|
-
else
|
561
|
-
r.to_ntriple
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
Resource = /<([^>]*)>/
|
566
|
-
Literal = /"((?:\\"|[^"])*)"/
|
567
|
-
|
568
|
-
public :subproperties
|
569
|
-
end
|
570
|
-
|
571
|
-
class String
|
572
|
-
def double_quote
|
573
|
-
Thread.new do
|
574
|
-
$SAFE = 12
|
575
|
-
begin
|
576
|
-
eval('"%s"' % self)
|
577
|
-
rescue Exception => e
|
578
|
-
self
|
579
|
-
end
|
580
|
-
end.value
|
581
|
-
end
|
582
457
|
end
|
458
|
+
end
|
@@ -26,7 +26,7 @@ class SuggestingAdapter < FetchingAdapter
|
|
26
26
|
|
27
27
|
# suggests additional predicates that might be applicable for the given resource
|
28
28
|
def suggest(resource)
|
29
|
-
|
29
|
+
ActiveRdfLogger::log_debug(self) { "Starting suggestions for #{size} triples" }
|
30
30
|
time = Time.now
|
31
31
|
|
32
32
|
predicates = []
|
@@ -53,7 +53,7 @@ class SuggestingAdapter < FetchingAdapter
|
|
53
53
|
end
|
54
54
|
[candidate, score]
|
55
55
|
end
|
56
|
-
|
56
|
+
ActiveRdfLogger::log_debug(self) { "Suggestions for #{resource} took #{Time.now-time}s" }
|
57
57
|
suggestions
|
58
58
|
end
|
59
59
|
|
@@ -2,32 +2,17 @@
|
|
2
2
|
# Copyright:: (c) 2005-2006
|
3
3
|
# License:: LGPL
|
4
4
|
|
5
|
-
require 'rubygems'
|
6
5
|
require 'test/unit'
|
7
6
|
require 'active_rdf'
|
7
|
+
common_test_dir = File.dirname(File.expand_path(__FILE__)) + '/../../test'
|
8
|
+
require "#{common_test_dir}/common"
|
9
|
+
require "#{common_test_dir}/adapters/test_network_aware_adapter"
|
8
10
|
|
9
11
|
class TestFetchingAdapter < Test::Unit::TestCase
|
10
|
-
|
11
|
-
|
12
|
-
@adapter = ConnectionPool.add(:type => :fetching)
|
13
|
-
end
|
14
|
-
|
15
|
-
def teardown
|
16
|
-
end
|
12
|
+
include SetupAdapter
|
13
|
+
include TestNetworkAwareAdapter
|
17
14
|
|
18
|
-
def
|
19
|
-
|
20
|
-
assert @adapter.size > 0
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_sioc_schema
|
24
|
-
@adapter.fetch("http://rdfs.org/sioc/ns#")
|
25
|
-
assert_equal 560, @adapter.size
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_foaf_schema
|
29
|
-
@adapter.fetch("http://xmlns.com/foaf/0.1/")
|
30
|
-
# foaf contains 563 triples but with two duplicates
|
31
|
-
assert_equal 561, @adapter.size
|
15
|
+
def setup
|
16
|
+
super(:type => :fetching)
|
32
17
|
end
|
33
18
|
end
|