/
jars2.rb
112 lines (90 loc) · 3.06 KB
/
jars2.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# Read-only adapter to jars2
# (experimental YARS branch for SWSE engine)
#
# Author:: Eyal Oren
# Copyright:: (c) 2005-2006
# License:: LGPL
require 'active_rdf'
require 'queryengine/query2jars2'
require 'net/http'
require 'cgi'
# TODO: add unit test
class Jars2Adapter
$log.info "loading Jars2 adapter"
ConnectionPool.register_adapter(:jars2, self)
def initialize(params = {})
@host = params[:host] || 'm3pe.org'
@port = params[:port] || 2020
$log.info "Jars2Adapter: initializing new instance with host: #{@host} port: #{@port}"
@yars = Net::HTTP.new(@host, @port)
end
def reads?; true; end
def writes?; false; end
def query(query)
qs = Query2Jars2.translate(query)
header = { 'Accept' => 'application/rdf+n3' }
# querying Jars2, adding 'eyal' parameter to get all variable bindings in
# the result
time = Time.now
response = @yars.get("/?q=#{CGI.escape(qs)}&eyal", header)
$log.debug "Jars2Adapter: query executed: #{qs}"
$log.debug "Jars2Adapter: query response from Jars took: #{Time.now - time}s"
# return empty array if no content
return [] if response.is_a?(Net::HTTPNoContent)
# return false unless HTTP OK returned
return false unless response.is_a?(Net::HTTPOK)
# parse the result
results = parse_result(response.body, query)
# remove duplicates if asked for distinct results
if query.distinct?
final_results = results.uniq
else
final_results = results
end
$log.debug "Jars2Adapter: query returned results #{final_results.join(', ')}"
return final_results
end
private
Resource = /<[^>]*>/
Literal = /"[^"]*"/
Node = Regexp.union(Resource,Literal)
# parses Jars2 results into array of ActiveRDF objects
def parse_result(response, query)
# Jars2 responses contain one result per line
results = response.split("\n")
# the first line of the response contains the variable bindings of the
# results: we look at that line to figure out which column contains the
# data we are looking for (which is the variables mentioned in the select
# clauses of the query
bindings = results[0].split(' ')
# array of found answers, will be filled by iterating over the results and
# only including the requested (i.e. selected) clauses
answers = []
# we iterate over the real results, and extract the clauses that we're
# looking for (i.e. the select clauses from the query)
results[1..-1].each do |result|
# scan row for occurence of nodes (either resources or literals)
row = result.scan(Node)
# for each select clause, we find its index, and add the value at that
# location in the result row to our answer
row = query.select_clauses.collect do |clause|
clause_index = bindings.index(clause)
convert_into_activerdf(row[clause_index])
end
answers << row
end
answers
end
# converts ntriples serialisation of resource or literal into ActiveRDF object
def convert_into_activerdf(string)
case string
when /<(.*)>/
# <http://foaf/Person> is a resource
RDFS::Resource.new($1)
when /"(.*)"/
# "30" is a literal
# TODO: handle datatypes
String.new($1)
end
end
end