activerdf_net7 1.6.11
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +79 -0
- data/LICENSE +504 -0
- data/README.rdoc +34 -0
- data/activerdf-jena/CHANGELOG +14 -0
- data/activerdf-jena/LICENSE +504 -0
- data/activerdf-jena/README +57 -0
- data/activerdf-jena/Rakefile +87 -0
- data/activerdf-jena/TODO +18 -0
- data/activerdf-jena/VERSION +1 -0
- data/activerdf-jena/ext/antlr-2.7.5.jar +0 -0
- data/activerdf-jena/ext/arq-extra.jar +0 -0
- data/activerdf-jena/ext/arq.jar +0 -0
- data/activerdf-jena/ext/aterm-java-1.6.jar +0 -0
- data/activerdf-jena/ext/commons-logging-1.1.jar +0 -0
- data/activerdf-jena/ext/concurrent.jar +0 -0
- data/activerdf-jena/ext/icu4j_3_4.jar +0 -0
- data/activerdf-jena/ext/iri.jar +0 -0
- data/activerdf-jena/ext/jena.jar +0 -0
- data/activerdf-jena/ext/jenatest.jar +0 -0
- data/activerdf-jena/ext/json.jar +0 -0
- data/activerdf-jena/ext/junit.jar +0 -0
- data/activerdf-jena/ext/log4j-1.2.12.jar +0 -0
- data/activerdf-jena/ext/lucene-core-2.0.0.jar +0 -0
- data/activerdf-jena/ext/ng4j.jar +0 -0
- data/activerdf-jena/ext/pellet.jar +0 -0
- data/activerdf-jena/ext/relaxngDatatype.jar +0 -0
- data/activerdf-jena/ext/stax-api-1.0.jar +0 -0
- data/activerdf-jena/ext/wstx-asl-3.0.0.jar +0 -0
- data/activerdf-jena/ext/xercesImpl.jar +0 -0
- data/activerdf-jena/ext/xml-apis.jar +0 -0
- data/activerdf-jena/ext/xsdlib.jar +0 -0
- data/activerdf-jena/lib/activerdf_jena/init.rb +26 -0
- data/activerdf-jena/lib/activerdf_jena/jena.rb +59 -0
- data/activerdf-jena/lib/activerdf_jena/jena_adapter.rb +515 -0
- data/activerdf-jena/lib/activerdf_jena/lucene.rb +22 -0
- data/activerdf-jena/lib/activerdf_jena/ng4j.rb +50 -0
- data/activerdf-jena/lib/activerdf_jena/ng4j_adapter.rb +379 -0
- data/activerdf-jena/lib/activerdf_jena/pellet.rb +25 -0
- data/activerdf-jena/test/bnode_org_rss.rdf +793 -0
- data/activerdf-jena/test/eyal-foaf.nt +39 -0
- data/activerdf-jena/test/fun_with_bnodes.nt +2 -0
- data/activerdf-jena/test/s1.n3 +18 -0
- data/activerdf-jena/test/test_data.nt +32 -0
- data/activerdf-jena/test/test_jena_adapter.rb +451 -0
- data/activerdf-jena/test/test_ng4j_adapter.rb +354 -0
- data/activerdf-rdflite/CHANGELOG +31 -0
- data/activerdf-rdflite/LICENSE +504 -0
- data/activerdf-rdflite/README +16 -0
- data/activerdf-rdflite/Rakefile +73 -0
- data/activerdf-rdflite/VERSION +1 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/fetching.rb +34 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/init.rb +13 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +582 -0
- data/activerdf-rdflite/lib/activerdf_rdflite/suggesting.rb +87 -0
- data/activerdf-rdflite/test/test_bnode_data.nt +5 -0
- data/activerdf-rdflite/test/test_data.nt +32 -0
- data/activerdf-rdflite/test/test_escaped_data.nt +2 -0
- data/activerdf-rdflite/test/test_fetching.rb +33 -0
- data/activerdf-rdflite/test/test_rdflite.rb +277 -0
- data/activerdf-redland/CHANGELOG +12 -0
- data/activerdf-redland/LICENSE +504 -0
- data/activerdf-redland/README +9 -0
- data/activerdf-redland/Rakefile +72 -0
- data/activerdf-redland/VERSION +1 -0
- data/activerdf-redland/lib/activerdf_redland/init.rb +10 -0
- data/activerdf-redland/lib/activerdf_redland/redland.rb +362 -0
- data/activerdf-redland/test/test_person_data.nt +42 -0
- data/activerdf-redland/test/test_redland_adapter.rb +242 -0
- data/activerdf-sesame/CHANGELOG +6 -0
- data/activerdf-sesame/LICENSE +10 -0
- data/activerdf-sesame/LICENSE-aduna +10 -0
- data/activerdf-sesame/LICENSE-lgpl +504 -0
- data/activerdf-sesame/README +33 -0
- data/activerdf-sesame/Rakefile +77 -0
- data/activerdf-sesame/VERSION +1 -0
- data/activerdf-sesame/ext/commons-codec-1.3.jar +0 -0
- data/activerdf-sesame/ext/commons-dbcp-1.2.2.jar +0 -0
- data/activerdf-sesame/ext/commons-httpclient-3.1.jar +0 -0
- data/activerdf-sesame/ext/commons-logging-1.1.1.jar +0 -0
- data/activerdf-sesame/ext/commons-pool-1.3.jar +0 -0
- data/activerdf-sesame/ext/commons-pool-1.5.2.jar +0 -0
- data/activerdf-sesame/ext/junit-3.8.2.jar +0 -0
- data/activerdf-sesame/ext/openrdf-sesame-2.0-onejar.jar +0 -0
- data/activerdf-sesame/ext/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
- data/activerdf-sesame/ext/slf4j-api-1.4.3.jar +0 -0
- data/activerdf-sesame/ext/slf4j-nop-1.4.3.jar +0 -0
- data/activerdf-sesame/ext/wrapper-sesame2.jar +0 -0
- data/activerdf-sesame/java/build.number +3 -0
- data/activerdf-sesame/java/build.xml +313 -0
- data/activerdf-sesame/java/javadoc/allclasses-frame.html +31 -0
- data/activerdf-sesame/java/javadoc/allclasses-noframe.html +31 -0
- data/activerdf-sesame/java/javadoc/constant-values.html +146 -0
- data/activerdf-sesame/java/javadoc/deprecated-list.html +146 -0
- data/activerdf-sesame/java/javadoc/help-doc.html +223 -0
- data/activerdf-sesame/java/javadoc/index-files/index-1.html +150 -0
- data/activerdf-sesame/java/javadoc/index-files/index-10.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-2.html +157 -0
- data/activerdf-sesame/java/javadoc/index-files/index-3.html +146 -0
- data/activerdf-sesame/java/javadoc/index-files/index-4.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-5.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-6.html +142 -0
- data/activerdf-sesame/java/javadoc/index-files/index-7.html +145 -0
- data/activerdf-sesame/java/javadoc/index-files/index-8.html +152 -0
- data/activerdf-sesame/java/javadoc/index-files/index-9.html +146 -0
- data/activerdf-sesame/java/javadoc/index.html +36 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/WrapperForSesame2.html +665 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/class-use/WrapperForSesame2.html +144 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-frame.html +32 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-summary.html +157 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-tree.html +150 -0
- data/activerdf-sesame/java/javadoc/org/activerdf/wrapper/sesame2/package-use.html +144 -0
- data/activerdf-sesame/java/javadoc/overview-summary.html +156 -0
- data/activerdf-sesame/java/javadoc/overview-tree.html +152 -0
- data/activerdf-sesame/java/javadoc/package-list +1 -0
- data/activerdf-sesame/java/javadoc/resources/inherit.gif +0 -0
- data/activerdf-sesame/java/javadoc/stylesheet.css +29 -0
- data/activerdf-sesame/java/lib/commons-codec-1.3.jar +0 -0
- data/activerdf-sesame/java/lib/commons-dbcp-1.2.2.jar +0 -0
- data/activerdf-sesame/java/lib/commons-httpclient-3.1.jar +0 -0
- data/activerdf-sesame/java/lib/commons-logging-1.1.1.jar +0 -0
- data/activerdf-sesame/java/lib/commons-pool-1.3.jar +0 -0
- data/activerdf-sesame/java/lib/commons-pool-1.5.2.jar +0 -0
- data/activerdf-sesame/java/lib/junit-3.8.2.jar +0 -0
- data/activerdf-sesame/java/lib/openrdf-sesame-2.0-onejar.jar +0 -0
- data/activerdf-sesame/java/lib/openrdf-sesame-2.3-pr1-onejar.jar +0 -0
- data/activerdf-sesame/java/lib/slf4j-api-1.4.3.jar +0 -0
- data/activerdf-sesame/java/lib/slf4j-nop-1.4.3.jar +0 -0
- data/activerdf-sesame/java/manifest.mf +3 -0
- data/activerdf-sesame/java/settings.xml +135 -0
- data/activerdf-sesame/java/src/org/activerdf/wrapper/sesame2/WrapperForSesame2.java +145 -0
- data/activerdf-sesame/java/test-src/org/activerdf/wrapper/sesame2/TestWrapperForSesame2.java +41 -0
- data/activerdf-sesame/lib/activerdf_sesame/init.rb +11 -0
- data/activerdf-sesame/lib/activerdf_sesame/sesame.rb +400 -0
- data/activerdf-sesame/test/eyal-foaf.nt +39 -0
- data/activerdf-sesame/test/eyal-foaf.rdf +65 -0
- data/activerdf-sesame/test/test_sesame_adapter.rb +341 -0
- data/activerdf-sparql/CHANGELOG +35 -0
- data/activerdf-sparql/LICENSE +504 -0
- data/activerdf-sparql/README +10 -0
- data/activerdf-sparql/Rakefile +78 -0
- data/activerdf-sparql/VERSION +1 -0
- data/activerdf-sparql/lib/activerdf_sparql/init.rb +10 -0
- data/activerdf-sparql/lib/activerdf_sparql/sparql.rb +212 -0
- data/activerdf-sparql/lib/activerdf_sparql/sparql_result_parser.rb +55 -0
- data/activerdf-sparql/test/test_sparql_adapter.rb +108 -0
- data/activerdf-yars/LICENSE +504 -0
- data/activerdf-yars/README +10 -0
- data/activerdf-yars/Rakefile +38 -0
- data/activerdf-yars/lib/activerdf_yars/init.rb +10 -0
- data/activerdf-yars/lib/activerdf_yars/jars2.rb +119 -0
- data/lib/active_rdf.rb +85 -0
- data/lib/active_rdf/directaccess/direct_access.rb +49 -0
- data/lib/active_rdf/federation/active_rdf_adapter.rb +47 -0
- data/lib/active_rdf/federation/connection_pool.rb +156 -0
- data/lib/active_rdf/federation/federation_manager.rb +112 -0
- data/lib/active_rdf/instance_exec.rb +13 -0
- data/lib/active_rdf/objectmanager/bnode.rb +7 -0
- data/lib/active_rdf/objectmanager/literal.rb +71 -0
- data/lib/active_rdf/objectmanager/namespace.rb +106 -0
- data/lib/active_rdf/objectmanager/object_manager.rb +119 -0
- data/lib/active_rdf/objectmanager/ordered_set.rb +116 -0
- data/lib/active_rdf/objectmanager/property_list.rb +76 -0
- data/lib/active_rdf/objectmanager/resource.rb +609 -0
- data/lib/active_rdf/objectmanager/resource_like.rb +28 -0
- data/lib/active_rdf/queryengine/ntriples_parser.rb +90 -0
- data/lib/active_rdf/queryengine/query.rb +245 -0
- data/lib/active_rdf/queryengine/query2jars2.rb +22 -0
- data/lib/active_rdf/queryengine/query2sparql.rb +139 -0
- data/lib/active_rdf_helpers.rb +30 -0
- data/lib/active_rdf_log.rb +100 -0
- data/test/common.rb +119 -0
- data/test/directaccess/test_direct_access.rb +64 -0
- data/test/federation/test_connection_pool.rb +86 -0
- data/test/federation/test_federation_manager.rb +145 -0
- data/test/objectmanager/test_literal.rb +52 -0
- data/test/objectmanager/test_namespace.rb +83 -0
- data/test/objectmanager/test_object_manager.rb +96 -0
- data/test/objectmanager/test_ordered_set.rb +110 -0
- data/test/objectmanager/test_resource_reading.rb +150 -0
- data/test/objectmanager/test_resource_writing.rb +39 -0
- data/test/objectmanager/test_talia_syntax.rb +68 -0
- data/test/queryengine/my_external_resource.rb +24 -0
- data/test/queryengine/test_external_resource_class.rb +49 -0
- data/test/queryengine/test_ntriples_parser.rb +71 -0
- data/test/queryengine/test_query.rb +55 -0
- data/test/queryengine/test_query2jars2.rb +51 -0
- data/test/queryengine/test_query2sparql.rb +76 -0
- data/test/queryengine/test_query_engine.rb +52 -0
- data/test/test_adapters.rb +58 -0
- metadata +266 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
== Welcome to rdflite
|
2
|
+
|
3
|
+
rdflite is a small RDF datastore, based on sqlite3. It can be used as a
|
4
|
+
datastore for ActiveRDF: it acts as a gemplugin for ActiveRDF. rdflite does not
|
5
|
+
scale well for large datasets, but is very fast for small ones. It supports the
|
6
|
+
full ActiveRDF query grammar (basically, select/distinct/count with arbitrary
|
7
|
+
joins in the where clauses) and offers full-text search over the literals if
|
8
|
+
ferret is installed.
|
9
|
+
|
10
|
+
See http://www.activerdf.org/ for more information.
|
11
|
+
|
12
|
+
== License
|
13
|
+
rdflite is distributed under the LGPL license.
|
14
|
+
|
15
|
+
== Authors
|
16
|
+
* Eyal Oren
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'meta_project'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
require 'rake/contrib/xforge'
|
8
|
+
require 'rubygems'
|
9
|
+
require 'fileutils'
|
10
|
+
require '../tools/rakehelp'
|
11
|
+
|
12
|
+
$version = IO.read('VERSION').strip
|
13
|
+
$name = 'activerdf_rdflite'
|
14
|
+
$project = MetaProject::Project::XForge::RubyForge.new('activerdf')
|
15
|
+
|
16
|
+
# setup tests
|
17
|
+
setup_tests
|
18
|
+
setup_clean ["pkg", "lib/*.bundle", "*.gem", ".config"]
|
19
|
+
|
20
|
+
# setup rdoc
|
21
|
+
Rake::RDocTask.new do |rdoc|
|
22
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
23
|
+
rdoc.options << '--line-numbers'
|
24
|
+
rdoc.rdoc_files.add ['README', 'LICENSE', 'lib/**/*.rb', 'doc/**/*.rdoc']
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Does a full compile, test run"
|
28
|
+
task :default => [:test, :package]
|
29
|
+
|
30
|
+
setup_gem($name, $version) do |spec|
|
31
|
+
spec.summary = "an RDF database for usage in ActiveRDF (based on sqlite3)"
|
32
|
+
spec.description = spec.summary
|
33
|
+
spec.author="Eyal Oren <eyal.oren@deri.org"
|
34
|
+
spec.add_dependency('gem_plugin', '>= 0.2.1')
|
35
|
+
spec.add_dependency('uuidtools')
|
36
|
+
spec.add_dependency('activerdf', '>= 1.6.4')
|
37
|
+
spec.add_dependency('mime-types')
|
38
|
+
spec.add_dependency('sqlite3-ruby', '>= 1.2.1')
|
39
|
+
end
|
40
|
+
|
41
|
+
task :verify_rubyforge do
|
42
|
+
raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
|
43
|
+
raise "RUBYFORGE_PASSWORD environment variable not set!" unless ENV['RUBYFORGE_PASSWORD']
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Release files on RubyForge."
|
47
|
+
task :release => [:clean, :verify_rubyforge, :package ] do
|
48
|
+
release_files = FileList["pkg/#$name-#$version.gem"]
|
49
|
+
|
50
|
+
Rake::XForge::Release.new($project) do |release|
|
51
|
+
release.user_name = ENV['RUBYFORGE_USER']
|
52
|
+
release.password = ENV['RUBYFORGE_PASSWORD']
|
53
|
+
release.files = release_files.to_a
|
54
|
+
release.release_name = "#$name #$version"
|
55
|
+
release.package_name = "activerdf-rdflite"
|
56
|
+
release.release_notes = ""
|
57
|
+
|
58
|
+
changes = []
|
59
|
+
File.open("CHANGELOG") do |file|
|
60
|
+
current = true
|
61
|
+
|
62
|
+
file.each do |line|
|
63
|
+
line.chomp!
|
64
|
+
if current and line =~ /^==/
|
65
|
+
current = false; next
|
66
|
+
end
|
67
|
+
break if line.empty? and not current
|
68
|
+
changes << line
|
69
|
+
end
|
70
|
+
end
|
71
|
+
release.release_changes = changes.join("\n")
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
1.4.1
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Author:: Eyal Oren
|
2
|
+
# Copyright:: (c) 2005-2006 Eyal Oren
|
3
|
+
# License:: LGPL
|
4
|
+
|
5
|
+
# FetchingAdapter is an extension to rdflite for fetching RDF from online sources.
|
6
|
+
class FetchingAdapter < RDFLite
|
7
|
+
ConnectionPool.register_adapter(:fetching, self)
|
8
|
+
|
9
|
+
# TODO: check that rapper is installed
|
10
|
+
|
11
|
+
# fetches RDF/XML data from given url and adds it to the datastore, using the
|
12
|
+
# source url as context identifier.
|
13
|
+
def fetch url
|
14
|
+
# check if url starts with http://
|
15
|
+
return unless url.match(/http:\/\/(.*)/)
|
16
|
+
|
17
|
+
ActiveRdfLogger::log_debug(self) { "Fetching from #{url}" }
|
18
|
+
|
19
|
+
#model = Redland::Model.new
|
20
|
+
#parser = Redland::Parser.new('rdfxml')
|
21
|
+
#scan = Redland::Uri.new('http://feature.librdf.org/raptor-scanForRDF')
|
22
|
+
#enable = Redland::Literal.new('1')
|
23
|
+
#Redland::librdf_parser_set_feature(parser, scan.uri, enable.node)
|
24
|
+
#parser.parse_into_model(model, url)
|
25
|
+
#triples = Redland::Serializer.ntriples.model_to_string(nil, model)
|
26
|
+
|
27
|
+
triples = `rapper --scan --quiet "#{url}"`
|
28
|
+
lines = triples.split($/)
|
29
|
+
ActiveRdfLogger::log_debug(self) { "Found #{lines.size} triples" }
|
30
|
+
|
31
|
+
context = Query.resource_class.new(url)
|
32
|
+
add_ntriples(triples, context)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
# add the directory in which this file is located to the ruby loadpath
|
3
|
+
file =
|
4
|
+
if File.symlink?(__FILE__)
|
5
|
+
File.readlink(__FILE__)
|
6
|
+
else
|
7
|
+
__FILE__
|
8
|
+
end
|
9
|
+
$: << File.dirname(File.expand_path(file))
|
10
|
+
|
11
|
+
require 'rdflite'
|
12
|
+
require 'fetching'
|
13
|
+
require 'suggesting'
|
@@ -0,0 +1,582 @@
|
|
1
|
+
# Author:: Eyal Oren
|
2
|
+
# Copyright:: (c) 2005-2006 Eyal Oren
|
3
|
+
# License:: LGPL
|
4
|
+
|
5
|
+
require 'sqlite3'
|
6
|
+
require 'active_rdf'
|
7
|
+
require 'federation/connection_pool'
|
8
|
+
require 'uuidtools'
|
9
|
+
require 'queryengine/ntriples_parser'
|
10
|
+
require 'open-uri'
|
11
|
+
require 'mime/types'
|
12
|
+
|
13
|
+
ActiveRdfLogger::log_info "Loading RDFLite adapter", self
|
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
|
19
|
+
# search if ferret is installed.
|
20
|
+
class RDFLite < ActiveRdfAdapter
|
21
|
+
|
22
|
+
class << self
|
23
|
+
begin
|
24
|
+
require 'ferret'
|
25
|
+
@have_ferret = true
|
26
|
+
rescue LoadError
|
27
|
+
ActiveRdfLogger::log_info "Keyword search is disabled since we could not load Ferret. To
|
28
|
+
enable, please do \"gem install ferret\"", self
|
29
|
+
@have_ferret = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_ferret?
|
33
|
+
@have_ferret
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
ConnectionPool.register_adapter(:rdflite,self)
|
38
|
+
bool_accessor :keyword_search, :reasoning
|
39
|
+
|
40
|
+
# instantiates RDFLite database
|
41
|
+
# available parameters:
|
42
|
+
# * :location => filepath (defaults to memory)
|
43
|
+
# * :keyword => true/false (defaults to false)
|
44
|
+
# * :pidx, :oidx, etc. => true/false (enable/disable these indices)
|
45
|
+
def initialize(params = {})
|
46
|
+
super()
|
47
|
+
ActiveRdfLogger::log_info(self) { "Initialised rdflite with params #{params.to_s}" }
|
48
|
+
|
49
|
+
@reads = true
|
50
|
+
@writes = true
|
51
|
+
|
52
|
+
# if no file-location given, we use in-memory store
|
53
|
+
file = params[:location] || ':memory:'
|
54
|
+
@db = SQLite3::Database.new(file)
|
55
|
+
|
56
|
+
# disable keyword search by default, enable only if ferret is found
|
57
|
+
@keyword_search = params[:keyword].nil? ? false : params[:keyword]
|
58
|
+
@keyword_search &= self.class.has_ferret?
|
59
|
+
|
60
|
+
@reasoning = params[:reasoning] || false
|
61
|
+
@subprops = {} if @reasoning
|
62
|
+
|
63
|
+
if keyword_search?
|
64
|
+
# we initialise the ferret index, either as a file or in memory
|
65
|
+
infos = Ferret::Index::FieldInfos.new
|
66
|
+
|
67
|
+
# we setup the fields not to store object's contents
|
68
|
+
infos.add_field(:subject, :store => :yes, :index => :no, :term_vector => :no)
|
69
|
+
infos.add_field(:object, :store => :no) #, :index => :omit_norms)
|
70
|
+
|
71
|
+
@ferret = if params[:location]
|
72
|
+
Ferret::I.new(:path => params[:location] + '.ferret', :field_infos => infos)
|
73
|
+
else
|
74
|
+
Ferret::I.new(:field_infos => infos)
|
75
|
+
end
|
76
|
+
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
|
+
end
|
87
|
+
|
88
|
+
# returns the number of triples in the datastore (incl. possible duplicates)
|
89
|
+
def size
|
90
|
+
@db.execute('select count(*) from triple')[0][0].to_i
|
91
|
+
end
|
92
|
+
|
93
|
+
# returns all triples in the datastore
|
94
|
+
def dump
|
95
|
+
@db.execute('select s,p,o,c from triple').collect do |s,p,o,c|
|
96
|
+
[s,p,o,c].join(' ')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# deletes all triples from datastore
|
101
|
+
def clear
|
102
|
+
@db.execute('delete from triple')
|
103
|
+
end
|
104
|
+
|
105
|
+
# close adapter and remove it from the ConnectionPool
|
106
|
+
def close
|
107
|
+
ConnectionPool.remove_data_source(self)
|
108
|
+
@db.close
|
109
|
+
end
|
110
|
+
|
111
|
+
# deletes triple(s,p,o,c) from datastore
|
112
|
+
# symbol parameters match anything: delete(:s,:p,:o) will delete all triples
|
113
|
+
# you can specify a context to limit deletion to that context:
|
114
|
+
# 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)
|
120
|
+
where_clauses = []
|
121
|
+
conditions = []
|
122
|
+
quad.each_with_index do |r,i|
|
123
|
+
unless r.nil?
|
124
|
+
conditions << r
|
125
|
+
where_clauses << "#{SPOC[i]} = ?"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# construct delete string
|
130
|
+
ds = 'delete from triple'
|
131
|
+
ds << " where #{where_clauses.join(' and ')}" unless where_clauses.empty?
|
132
|
+
|
133
|
+
# execute delete string with possible deletion conditions (for each
|
134
|
+
# non-empty where clause)
|
135
|
+
ActiveRdfLogger::log_debug(self) { "Deleting #{[s,p,o,c].join(' ')}" }
|
136
|
+
@db.execute(ds, *conditions)
|
137
|
+
|
138
|
+
# delete literal from ferret index
|
139
|
+
@ferret.search_each("subject:\"#{s}\", object:\"#{o}\"") do |idx, score|
|
140
|
+
@ferret.delete(idx)
|
141
|
+
end if keyword_search?
|
142
|
+
|
143
|
+
@db
|
144
|
+
end
|
145
|
+
|
146
|
+
# adds triple(s,p,o) to datastore
|
147
|
+
# s,p must be resources, o can be primitive data or resource
|
148
|
+
def add(s,p,o,c=nil)
|
149
|
+
# check illegal input
|
150
|
+
raise(ActiveRdfError, "adding non-resource #{s} while adding (#{s},#{p},#{o},#{c})") unless s.respond_to?(:uri)
|
151
|
+
raise(ActiveRdfError, "adding non-resource #{p} while adding (#{s},#{p},#{o},#{c})") unless p.respond_to?(:uri)
|
152
|
+
|
153
|
+
triple = [s, p, o].collect{|r| serialise(r) }
|
154
|
+
add_ntriples(triple.join(' ') + " .\n", serialise(c) )
|
155
|
+
|
156
|
+
## get internal representation (array)
|
157
|
+
#quad = [s,p,o,c].collect {|r| internalise(r) }
|
158
|
+
|
159
|
+
## insert the triple into the datastore
|
160
|
+
#@db.execute('insert into triple values (?,?,?,?)', *quad)
|
161
|
+
|
162
|
+
## if keyword-search available, insert the object into keyword search
|
163
|
+
#@ferret << {:subject => s, :object => o} if keyword_search?
|
164
|
+
end
|
165
|
+
|
166
|
+
# flushes openstanding changes to underlying sqlite3
|
167
|
+
def flush
|
168
|
+
# since we always write changes into sqlite3 immediately, we don't do
|
169
|
+
# anything here
|
170
|
+
true
|
171
|
+
end
|
172
|
+
|
173
|
+
# loads triples from file in ntriples format
|
174
|
+
def load(location)
|
175
|
+
context = if URI.parse(location).host
|
176
|
+
location
|
177
|
+
else
|
178
|
+
internalise(RDFS::Resource.new("file:#{location}"))
|
179
|
+
end
|
180
|
+
|
181
|
+
case MIME::Types.of(location)
|
182
|
+
when MIME::Types['application/rdf+xml']
|
183
|
+
# check if rapper available
|
184
|
+
begin
|
185
|
+
# can only parse rdf/xml with redland
|
186
|
+
# die otherwise
|
187
|
+
require 'rdf/redland'
|
188
|
+
model = Redland::Model.new
|
189
|
+
Redland::Parser.new.parse_into_model(model, location)
|
190
|
+
add_ntriples(model.to_string('ntriples'), location)
|
191
|
+
rescue LoadError
|
192
|
+
raise ActiveRdfError, "cannot parse remote rdf/xml file without Redland: please install Redland (librdf.org) and its Ruby bindings"
|
193
|
+
end
|
194
|
+
else
|
195
|
+
data = open(location).read
|
196
|
+
add_ntriples(data, context)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# adds ntriples from given context into datastore
|
201
|
+
def add_ntriples(ntriples, context)
|
202
|
+
# add each triple to db
|
203
|
+
@db.transaction
|
204
|
+
insert = @db.prepare('insert into triple values (?,?,?,?);')
|
205
|
+
|
206
|
+
ntriples = NTriplesParser.parse(ntriples)
|
207
|
+
ntriples.each do |s,p,o|
|
208
|
+
# convert triples into internal db format
|
209
|
+
subject, predicate, object = [s,p,o].collect {|r| internalise(r) }
|
210
|
+
|
211
|
+
# insert triple into database
|
212
|
+
insert.execute(subject, predicate, object, context)
|
213
|
+
|
214
|
+
# if keyword-search available, insert the object into keyword search
|
215
|
+
@ferret << {:subject => subject, :object => object} if keyword_search?
|
216
|
+
end
|
217
|
+
|
218
|
+
@db.commit
|
219
|
+
@db
|
220
|
+
end
|
221
|
+
|
222
|
+
# executes ActiveRDF query on datastore
|
223
|
+
def query(query)
|
224
|
+
# construct query clauses
|
225
|
+
sql, conditions = translate(query)
|
226
|
+
|
227
|
+
# executing query, passing all where-clause values as parameters (so that
|
228
|
+
# sqlite will encode quotes correctly)
|
229
|
+
results = @db.execute(sql, *conditions)
|
230
|
+
|
231
|
+
# if ASK query, we check whether we received a positive result count
|
232
|
+
if query.ask?
|
233
|
+
return [[results[0][0].to_i > 0]]
|
234
|
+
elsif query.count?
|
235
|
+
return [[results[0][0].to_i]]
|
236
|
+
else
|
237
|
+
# otherwise we convert results to ActiveRDF nodes and return them
|
238
|
+
return wrap(results, query.resource_class)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# translates ActiveRDF query into internal sqlite query string
|
243
|
+
def translate(query)
|
244
|
+
where, conditions = construct_where(query)
|
245
|
+
[construct_select(query) + construct_join(query) + where + construct_sort(query) + construct_limit(query), conditions]
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
# constants for extracting resources/literals from sql results
|
250
|
+
SPOC = ['s','p','o','c']
|
251
|
+
|
252
|
+
# construct select clause
|
253
|
+
def construct_select(query)
|
254
|
+
# ASK queries counts the results, and return true if results > 0
|
255
|
+
return "select count(*)" if query.ask?
|
256
|
+
|
257
|
+
# add select terms for each selectclause in the query
|
258
|
+
# the term names depend on the join conditions, e.g. t0.s or t1.p
|
259
|
+
select = query.select_clauses.collect do |term|
|
260
|
+
variable_name(query, term)
|
261
|
+
end
|
262
|
+
|
263
|
+
# add possible distinct and count functions to select clause
|
264
|
+
select_clause = ''
|
265
|
+
select_clause << 'distinct ' if query.distinct?
|
266
|
+
select_clause << select.join(', ')
|
267
|
+
select_clause = "count(#{select_clause})" if query.count?
|
268
|
+
|
269
|
+
"select " + select_clause
|
270
|
+
end
|
271
|
+
|
272
|
+
# construct (optional) limit and offset clauses
|
273
|
+
def construct_limit(query)
|
274
|
+
clause = ""
|
275
|
+
|
276
|
+
# if no limit given, use limit -1 (no limit)
|
277
|
+
limit = query.limits.nil? ? -1 : query.limits
|
278
|
+
|
279
|
+
# if no offset given, use offset 0
|
280
|
+
offset = query.offsets.nil? ? 0 : query.offsets
|
281
|
+
|
282
|
+
clause << " limit #{limit} offset #{offset}"
|
283
|
+
clause
|
284
|
+
end
|
285
|
+
|
286
|
+
# sort query results on variable clause (optionally)
|
287
|
+
def construct_sort(query)
|
288
|
+
if not query.sort_clauses.empty?
|
289
|
+
sort = query.sort_clauses.collect { |term| variable_name(query, term) }
|
290
|
+
" 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
|
+
else
|
295
|
+
""
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# construct join clause
|
300
|
+
# TODO: joins don't work this way, they have to be linear (in one direction
|
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.
|
304
|
+
def construct_join(query)
|
305
|
+
join_stmt = ''
|
306
|
+
|
307
|
+
# no join necessary if only one where clause given
|
308
|
+
return ' from triple as t0 ' if query.where_clauses.size == 1
|
309
|
+
|
310
|
+
where_clauses = query.where_clauses.flatten
|
311
|
+
considering = where_clauses.uniq.select{|w| w.is_a?(Symbol)}
|
312
|
+
|
313
|
+
# constructing hash with indices for all terms
|
314
|
+
# e.g. {?s => [1,3,5], ?p => [2], ... }
|
315
|
+
term_occurrences = Hash.new()
|
316
|
+
where_clauses.each_with_index do |term, index|
|
317
|
+
ary = (term_occurrences[term] ||= [])
|
318
|
+
ary << index
|
319
|
+
end
|
320
|
+
|
321
|
+
aliases = {}
|
322
|
+
|
323
|
+
where_clauses.each_with_index do |term, index|
|
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
|
343
|
+
|
344
|
+
indices.each do |i|
|
345
|
+
# skip the current term itself
|
346
|
+
next if i==index
|
347
|
+
|
348
|
+
# construct t0,t1, etc. as aliases for buddy,
|
349
|
+
# and construct join condition, e.g. t0.s = t1.p
|
350
|
+
buddyalias = "t#{i/4}"
|
351
|
+
buddyjoin = "#{buddyalias}.#{SPOC[i%4]}"
|
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} "
|
363
|
+
end
|
364
|
+
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
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# construct where clause
|
379
|
+
def construct_where(query)
|
380
|
+
# collecting where clauses, these will be added to the sql string later
|
381
|
+
where = []
|
382
|
+
|
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
|
385
|
+
# sqlite will automatically encode quoted literals correctly
|
386
|
+
right_hand_sides = []
|
387
|
+
|
388
|
+
# convert each where clause to SQL:
|
389
|
+
# add where clause for each subclause, except if it's a variable
|
390
|
+
query.where_clauses.each_with_index do |clause,level|
|
391
|
+
raise ActiveRdfError, "where clause #{clause} is not a triple" unless clause.is_a?(Array)
|
392
|
+
clause.each_with_index do |subclause, i|
|
393
|
+
# dont add where clause for variables
|
394
|
+
unless subclause.is_a?(Symbol) || subclause.nil?
|
395
|
+
conditions = compute_where_condition(i, subclause, query.reasoning? && reasoning?)
|
396
|
+
if conditions.size == 1
|
397
|
+
where << "t#{level}.#{SPOC[i]} = ?"
|
398
|
+
right_hand_sides << conditions.first
|
399
|
+
else
|
400
|
+
conditions = conditions.collect {|c| "'#{c}'"}
|
401
|
+
where << "t#{level}.#{SPOC[i]} in (#{conditions.join(',')})"
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# if keyword clause given, convert it using keyword index
|
408
|
+
if query.keyword? && keyword_search?
|
409
|
+
subjects = []
|
410
|
+
select_subject = query.keywords.collect {|subj,key| subj}.uniq
|
411
|
+
raise ActiveRdfError, "cannot do keyword search over multiple subjects" if select_subject.size > 1
|
412
|
+
|
413
|
+
keywords = query.keywords.collect {|subj,key| key}
|
414
|
+
@ferret.search_each("object:#{keywords}") do |idx,score|
|
415
|
+
subjects << @ferret[idx][:subject]
|
416
|
+
end
|
417
|
+
subjects.uniq! if query.distinct?
|
418
|
+
where << "#{variable_name(query,select_subject.first)} in (#{subjects.collect {'?'}.join(',')})"
|
419
|
+
right_hand_sides += subjects
|
420
|
+
end
|
421
|
+
|
422
|
+
if where.empty?
|
423
|
+
['',[]]
|
424
|
+
else
|
425
|
+
["where " + where.join(' and '), right_hand_sides]
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def compute_where_condition(index, subclause, reasoning)
|
430
|
+
conditions = [subclause]
|
431
|
+
|
432
|
+
# expand conditions with rdfs rules if reasoning enabled
|
433
|
+
if reasoning
|
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
|
466
|
+
end
|
467
|
+
@subprops[resource]
|
468
|
+
end
|
469
|
+
|
470
|
+
# returns sql variable name for a queryterm
|
471
|
+
def variable_name(query,term)
|
472
|
+
# look up the first occurence of this term in the where clauses, and compute
|
473
|
+
# the level and s/p/o position of it
|
474
|
+
index = query.where_clauses.flatten.index(term)
|
475
|
+
|
476
|
+
if index.nil?
|
477
|
+
# term does not appear in where clause
|
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
|
494
|
+
end
|
495
|
+
|
496
|
+
termtable = "t#{index / 4}"
|
497
|
+
termspo = SPOC[index % 4]
|
498
|
+
return "#{termtable}.#{termspo}"
|
499
|
+
end
|
500
|
+
|
501
|
+
# wrap resources into ActiveRDF resources, literals into Strings. result_type
|
502
|
+
# is the type that should be used for ActiveRDF resources
|
503
|
+
def wrap(results, result_type)
|
504
|
+
results.collect do |row|
|
505
|
+
row.collect { |result| parse(result, result_type) }
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# Return the result as a correct type. result_type is the type that should
|
510
|
+
# be used for "resouce" elements
|
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
|
523
|
+
end
|
524
|
+
|
525
|
+
def create_indices(params)
|
526
|
+
sidx = params[:sidx] || false
|
527
|
+
pidx = params[:pidx] || false
|
528
|
+
oidx = params[:oidx] || false
|
529
|
+
spidx = params[:spidx] || true
|
530
|
+
soidx = params[:soidx] || false
|
531
|
+
poidx = params[:poidx] || true
|
532
|
+
opidx = params[:opidx] || false
|
533
|
+
|
534
|
+
# creating lookup indices
|
535
|
+
@db.transaction do
|
536
|
+
@db.execute('create index if not exists sidx on triple(s)') if sidx
|
537
|
+
@db.execute('create index if not exists pidx on triple(p)') if pidx
|
538
|
+
@db.execute('create index if not exists oidx on triple(o)') if oidx
|
539
|
+
@db.execute('create index if not exists spidx on triple(s,p)') if spidx
|
540
|
+
@db.execute('create index if not exists soidx on triple(s,o)') if soidx
|
541
|
+
@db.execute('create index if not exists poidx on triple(p,o)') if poidx
|
542
|
+
@db.execute('create index if not exists opidx on triple(o,p)') if opidx
|
543
|
+
end
|
544
|
+
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
|
+
end
|