comparison rdf/SimpleSPARQLQuery.cpp @ 480:3ffce691c9bf

* Add Redland datastore support to SimpleSPARQLQuery
author Chris Cannam
date Thu, 13 Nov 2008 14:23:23 +0000
parents 2019d89ebcf9
children a82645e788fc
comparison
equal deleted inserted replaced
479:f933062a7f80 480:3ffce691c9bf
13 COPYING included with this distribution for more information. 13 COPYING included with this distribution for more information.
14 */ 14 */
15 15
16 #include "SimpleSPARQLQuery.h" 16 #include "SimpleSPARQLQuery.h"
17 #include "base/ProgressReporter.h" 17 #include "base/ProgressReporter.h"
18 #include "base/Profiler.h"
19
20 #include <QMutex>
21 #include <QMutexLocker>
22
23 #include <set>
18 24
19 #ifdef USE_NEW_RASQAL_API 25 #ifdef USE_NEW_RASQAL_API
20 #include <rasqal/rasqal.h> 26 #include <rasqal/rasqal.h>
21 #else 27 #else
22 #include <rasqal.h> 28 #include <rasqal.h>
23 #endif 29 #endif
24 30
31 #ifdef HAVE_REDLAND
32 #include <redland.h>
33 #endif
34
25 //#define DEBUG_SIMPLE_SPARQL_QUERY 1 35 //#define DEBUG_SIMPLE_SPARQL_QUERY 1
26 36
27 #include <iostream> 37 #include <iostream>
28 38
29 using std::cerr; 39 using std::cerr;
34 { 44 {
35 public: 45 public:
36 WrasqalWorldWrapper() : m_world(rasqal_new_world()) { } 46 WrasqalWorldWrapper() : m_world(rasqal_new_world()) { }
37 ~WrasqalWorldWrapper() { rasqal_free_world(m_world); } 47 ~WrasqalWorldWrapper() { rasqal_free_world(m_world); }
38 48
39 rasqal_world *getWorld() const { return m_world; } 49 rasqal_world *getWorld() { return m_world; }
50 const rasqal_world *getWorld() const { return m_world; }
40 51
41 private: 52 private:
42 rasqal_world *m_world; 53 rasqal_world *m_world;
43 }; 54 };
44 #endif 55 #endif
45 56
57 #ifdef HAVE_REDLAND
58 class WredlandWorldWrapper
59 {
60 public:
61 WredlandWorldWrapper() :
62 m_world(0), m_storage(0), m_model(0)
63 {
64 m_world = librdf_new_world();
65 librdf_world_open(m_world);
66 m_storage = librdf_new_storage(m_world, NULL, NULL, NULL);
67 // m_storage = librdf_new_storage(m_world, "hashes", NULL,
68 //. "hash-type='memory',indexes=1");
69 if (!m_storage) {
70 std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland hashes datastore, falling back to memory store" << std::endl;
71 m_storage = librdf_new_storage(m_world, NULL, NULL, NULL);
72 if (!m_storage) {
73 std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland memory datastore" << std::endl;
74 return;
75 }
76 }
77 m_model = librdf_new_model(m_world, m_storage, NULL);
78 if (!m_model) {
79 std::cerr << "SimpleSPARQLQuery: ERROR: Failed to initialise Redland data model" << std::endl;
80 return;
81 }
82 }
83
84 ~WredlandWorldWrapper()
85 {
86 while (!m_parsedUris.empty()) {
87 librdf_free_uri(m_parsedUris.begin()->second);
88 m_parsedUris.erase(m_parsedUris.begin());
89 }
90 if (m_model) librdf_free_model(m_model);
91 if (m_storage) librdf_free_storage(m_storage);
92 if (m_world) librdf_free_world(m_world);
93 }
94
95 bool isOK() const { return (m_model != 0); }
96
97 librdf_uri *getUri(QString uriString, QString &errorString)
98 {
99 QMutexLocker locker(&m_mutex);
100
101 if (m_parsedUris.find(uriString) != m_parsedUris.end()) {
102 return m_parsedUris[uriString];
103 }
104
105 librdf_uri *uri = librdf_new_uri
106 (m_world, (const unsigned char *)uriString.toUtf8().data());
107 if (!uri) {
108 errorString = "Failed to construct librdf_uri!";
109 return 0;
110 }
111
112 librdf_parser *parser = librdf_new_parser(m_world, "guess", NULL, NULL);
113 if (!parser) {
114 errorString = "Failed to initialise Redland parser";
115 return 0;
116 }
117
118 std::cerr << "About to parse \"" << uriString.toStdString() << "\"" << std::endl;
119
120 Profiler p("SimpleSPARQLQuery: Parse URI into LIBRDF model");
121
122 if (librdf_parser_parse_into_model(parser, uri, NULL, m_model)) {
123
124 errorString = QString("Failed to parse RDF from URI \"%1\"")
125 .arg(uriString);
126 librdf_free_parser(parser);
127 librdf_free_uri(uri);
128 return 0;
129
130 } else {
131
132 librdf_free_parser(parser);
133 m_parsedUris[uriString] = uri;
134 return uri;
135 }
136 }
137
138 librdf_world *getWorld() { return m_world; }
139 const librdf_world *getWorld() const { return m_world; }
140
141 librdf_model *getModel() { return m_model; }
142 const librdf_model *getModel() const { return m_model; }
143
144 private:
145 librdf_world *m_world;
146 librdf_storage *m_storage;
147 librdf_model *m_model;
148
149 QMutex m_mutex;
150 std::map<QString, librdf_uri *> m_parsedUris;
151 };
152 #endif
153
46 class SimpleSPARQLQuery::Impl 154 class SimpleSPARQLQuery::Impl
47 { 155 {
48 public: 156 public:
49 Impl(QString query); 157 Impl(QString fromUri, QString query);
50 ~Impl(); 158 ~Impl();
51 159
52 void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; } 160 void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; }
53 bool wasCancelled() const { return m_cancelled; } 161 bool wasCancelled() const { return m_cancelled; }
54 162
55 ResultList execute(); 163 ResultList execute();
56 164
57 bool isOK() const; 165 bool isOK() const;
58 QString getErrorString() const; 166 QString getErrorString() const;
59 167
168 static void setImplementationPreference
169 (SimpleSPARQLQuery::ImplementationPreference p) {
170 m_preference = p;
171 }
172
60 protected: 173 protected:
61 static void errorHandler(void *, raptor_locator *, const char *); 174 static void errorHandler(void *, raptor_locator *, const char *);
62 175
176 static QMutex m_mutex;
177
63 #ifdef USE_NEW_RASQAL_API 178 #ifdef USE_NEW_RASQAL_API
64 static WrasqalWorldWrapper m_www; 179 static WrasqalWorldWrapper *m_rasqal;
65 #else 180 #else
66 static bool m_initialised; 181 static bool m_rasqalInitialised;
67 #endif 182 #endif
68 183
184 #ifdef HAVE_REDLAND
185 static WredlandWorldWrapper *m_redland;
186 #endif
187
188 static SimpleSPARQLQuery::ImplementationPreference m_preference;
189
190 ResultList executeDirectParser();
191 ResultList executeDatastore();
192
193 QString m_fromUri;
69 QString m_query; 194 QString m_query;
70 QString m_errorString; 195 QString m_errorString;
71 ProgressReporter *m_reporter; 196 ProgressReporter *m_reporter;
72 bool m_cancelled; 197 bool m_cancelled;
73 }; 198 };
74 199
75 #ifdef USE_NEW_RASQAL_API 200 #ifdef USE_NEW_RASQAL_API
76 WrasqalWorldWrapper 201 WrasqalWorldWrapper *SimpleSPARQLQuery::Impl::m_rasqal = 0;
77 SimpleSPARQLQuery::Impl::m_www;
78 #else 202 #else
79 bool 203 bool SimpleSPARQLQuery::Impl::m_rasqalInitialised = false;
80 SimpleSPARQLQuery::Impl::m_initialised = false; 204 #endif
81 #endif 205
82 206 #ifdef HAVE_REDLAND
83 SimpleSPARQLQuery::SimpleSPARQLQuery(QString query) : 207 WredlandWorldWrapper *SimpleSPARQLQuery::Impl::m_redland = 0;
84 m_impl(new Impl(query)) { } 208 #endif
209
210 QMutex SimpleSPARQLQuery::Impl::m_mutex;
211
212 SimpleSPARQLQuery::ImplementationPreference
213 SimpleSPARQLQuery::Impl::m_preference = SimpleSPARQLQuery::UseDirectParser;
214
215 SimpleSPARQLQuery::SimpleSPARQLQuery(QString fromUri, QString query) :
216 m_impl(new Impl(fromUri, query))
217 {
218 }
85 219
86 SimpleSPARQLQuery::~SimpleSPARQLQuery() 220 SimpleSPARQLQuery::~SimpleSPARQLQuery()
87 { 221 {
88 delete m_impl; 222 delete m_impl;
89 } 223 }
116 SimpleSPARQLQuery::getErrorString() const 250 SimpleSPARQLQuery::getErrorString() const
117 { 251 {
118 return m_impl->getErrorString(); 252 return m_impl->getErrorString();
119 } 253 }
120 254
121 SimpleSPARQLQuery::Impl::Impl(QString query) : 255 void
256 SimpleSPARQLQuery::setImplementationPreference(ImplementationPreference p)
257 {
258 SimpleSPARQLQuery::Impl::setImplementationPreference(p);
259 }
260
261 SimpleSPARQLQuery::Impl::Impl(QString fromUri, QString query) :
262 m_fromUri(fromUri),
122 m_query(query), 263 m_query(query),
123 m_reporter(0), 264 m_reporter(0),
124 m_cancelled(false) 265 m_cancelled(false)
125 { 266 {
126 #ifdef DEBUG_SIMPLE_SPARQL_QUERY 267 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
163 SimpleSPARQLQuery::ResultList 304 SimpleSPARQLQuery::ResultList
164 SimpleSPARQLQuery::Impl::execute() 305 SimpleSPARQLQuery::Impl::execute()
165 { 306 {
166 ResultList list; 307 ResultList list;
167 308
309 ImplementationPreference preference;
310
311 m_mutex.lock();
312
313 if (m_preference == UseDatastore) {
314 #ifdef HAVE_REDLAND
315 if (!m_redland) {
316 m_redland = new WredlandWorldWrapper();
317 if (!m_redland->isOK()) {
318 cerr << "WARNING: SimpleSPARQLQuery::execute: Failed to initialise Redland datastore, falling back to direct parser implementation" << endl;
319 delete m_redland;
320 m_preference = UseDirectParser;
321 }
322 }
323 #else
324 cerr << "WARNING: SimpleSPARQLQuery::execute: Datastore implementation preference indicated, but no datastore compiled in; using direct parser" << endl;
325 m_preference = UseDirectParser;
326 #endif
327 }
328
329 if (m_preference == UseDirectParser) {
168 #ifdef USE_NEW_RASQAL_API 330 #ifdef USE_NEW_RASQAL_API
169 rasqal_query *query = rasqal_new_query(m_www.getWorld(), "sparql", NULL); 331 if (!m_rasqal) m_rasqal = new WrasqalWorldWrapper();
170 #else 332 #else
171 if (!m_initialised) { 333 if (!m_rasqalInitialised) {
172 m_initialised = true; 334 rasqal_init();
173 rasqal_init(); 335 m_rasqalInitialised = true;
174 } 336 }
337 #endif
338 }
339
340 preference = m_preference;
341 m_mutex.unlock();
342
343 if (preference == SimpleSPARQLQuery::UseDirectParser) {
344 return executeDirectParser();
345 } else {
346 return executeDatastore();
347 }
348 }
349
350 SimpleSPARQLQuery::ResultList
351 SimpleSPARQLQuery::Impl::executeDirectParser()
352 {
353 ResultList list;
354
355 Profiler profiler("SimpleSPARQLQuery::executeDirectParser");
356
357 #ifdef USE_NEW_RASQAL_API
358 rasqal_query *query = rasqal_new_query(m_rasqal->getWorld(), "sparql", NULL);
359 #else
175 rasqal_query *query = rasqal_new_query("sparql", NULL); 360 rasqal_query *query = rasqal_new_query("sparql", NULL);
176 #endif 361 #endif
177 if (!query) { 362 if (!query) {
178 m_errorString = "Failed to construct query"; 363 m_errorString = "Failed to construct query";
179 cerr << "SimpleSPARQLQuery: ERROR: " << m_errorString.toStdString() << endl; 364 cerr << "SimpleSPARQLQuery: ERROR: " << m_errorString.toStdString() << endl;
181 } 366 }
182 367
183 rasqal_query_set_error_handler(query, this, errorHandler); 368 rasqal_query_set_error_handler(query, this, errorHandler);
184 rasqal_query_set_fatal_error_handler(query, this, errorHandler); 369 rasqal_query_set_fatal_error_handler(query, this, errorHandler);
185 370
186 if (rasqal_query_prepare 371 {
187 (query, (const unsigned char *)m_query.toUtf8().data(), NULL)) { 372 Profiler p("SimpleSPARQLQuery: Prepare RASQAL query");
188 cerr << "SimpleSPARQLQuery: Failed to prepare query" << endl; 373
189 rasqal_free_query(query); 374 if (rasqal_query_prepare
190 return list; 375 (query, (const unsigned char *)m_query.toUtf8().data(), NULL)) {
191 } 376 cerr << "SimpleSPARQLQuery: Failed to prepare query" << endl;
192 377 rasqal_free_query(query);
193 rasqal_query_results *results = rasqal_query_execute(query); 378 return list;
379 }
380 }
381
382 rasqal_query_results *results;
383
384 {
385 Profiler p("SimpleSPARQLQuery: Execute RASQAL query");
386 results = rasqal_query_execute(query);
387 }
194 388
195 // cerr << "Query executed" << endl; 389 // cerr << "Query executed" << endl;
196 390
197 if (!results) { 391 if (!results) {
198 cerr << "SimpleSPARQLQuery: RASQAL query failed" << endl; 392 cerr << "SimpleSPARQLQuery: RASQAL query failed" << endl;
270 rasqal_free_query(query); 464 rasqal_free_query(query);
271 465
272 return list; 466 return list;
273 } 467 }
274 468
469 SimpleSPARQLQuery::ResultList
470 SimpleSPARQLQuery::Impl::executeDatastore()
471 {
472 ResultList list;
473 #ifndef HAVE_REDLAND
474 // This should have been caught by execute()
475 cerr << "SimpleSPARQLQuery: INTERNAL ERROR: Datastore not compiled in" << endl;
476 return list;
477 #else
478 Profiler profiler("SimpleSPARQLQuery::executeDatastore");
479
480 librdf_uri *uri = m_redland->getUri(m_fromUri, m_errorString);
481 if (!uri) return list;
482
483 std::cerr << "SimpleSPARQLQuery: Query is: \"" << m_query.toStdString() << "\"" << std::endl;
484 static std::map<QString, int> counter;
485 if (counter.find(m_query) == counter.end()) counter[m_query] = 1;
486 else ++counter[m_query];
487 std::cerr << "Counter for this query: " << counter[m_query] << std::endl;
488
489 librdf_query *query;
490
491 {
492 Profiler p("SimpleSPARQLQuery: Prepare LIBRDF query");
493 query = librdf_new_query
494 (m_redland->getWorld(), "sparql", NULL,
495 (const unsigned char *)m_query.toUtf8().data(), uri);
496 }
497 std::cerr << "Prepared" << std::endl;
498
499 if (!query) {
500 m_errorString = "Failed to construct query";
501 return list;
502 }
503
504 librdf_query_results *results;
505 {
506 Profiler p("SimpleSPARQLQuery: Execute LIBRDF query");
507 results = librdf_query_execute(query, m_redland->getModel());
508 }
509 std::cerr << "Executed" << std::endl;
510
511 if (!results) {
512 cerr << "SimpleSPARQLQuery: LIBRDF query failed" << endl;
513 librdf_free_query(query);
514 return list;
515 }
516
517 if (!librdf_query_results_is_bindings(results)) {
518 cerr << "SimpleSPARQLQuery: LIBRDF query has wrong result type (not bindings)" << endl;
519 librdf_free_query_results(results);
520 librdf_free_query(query);
521 return list;
522 }
523
524 int resultCount = 0;
525 int resultTotal = librdf_query_results_get_count(results); // probably wrong
526 m_cancelled = false;
527
528 while (!librdf_query_results_finished(results)) {
529
530 int count = librdf_query_results_get_bindings_count(results);
531
532 KeyValueMap resultmap;
533
534 for (int i = 0; i < count; ++i) {
535
536 const char *name =
537 librdf_query_results_get_binding_name(results, i);
538
539 librdf_node *node =
540 librdf_query_results_get_binding_value(results, i);
541
542 QString key = (const char *)name;
543
544 if (!node) {
545 resultmap[key] = Value();
546 continue;
547 }
548
549 ValueType type = LiteralValue;
550 if (librdf_node_is_resource(node)) type = URIValue;
551 else if (librdf_node_is_literal(node)) type = LiteralValue;
552 else if (librdf_node_is_blank(node)) type = BlankValue;
553 else {
554 cerr << "SimpleSPARQLQuery: LIBRDF query returned unknown node type (not resource, literal, or blank)" << endl;
555 resultmap[key] = Value();
556 librdf_free_node(node);
557 continue;
558 }
559
560 QString text = (const char *)librdf_node_get_literal_value(node);
561
562 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
563 std::cerr << i << ". " << key.toStdString() << " -> " << text.toStdString() << " (type " << type << ")" << std::endl;
564 #endif
565
566 resultmap[key] = Value(type, text);
567
568 librdf_free_node(node);
569 }
570
571 list.push_back(resultmap);
572
573 librdf_query_results_next(results);
574
575 resultCount++;
576
577 if (m_reporter) {
578 if (resultCount >= resultTotal) {
579 if (m_reporter->isDefinite()) m_reporter->setDefinite(false);
580 m_reporter->setProgress(resultCount);
581 } else {
582 m_reporter->setProgress((resultCount * 100) / resultTotal);
583 }
584
585 if (m_reporter->wasCancelled()) {
586 m_cancelled = true;
587 break;
588 }
589 }
590 }
591
592 librdf_free_query_results(results);
593 librdf_free_query(query);
594
595 std::cerr << "All results retrieved" << std::endl;
596
597 return list;
598 #endif
599 }
600
275 SimpleSPARQLQuery::Value 601 SimpleSPARQLQuery::Value
276 SimpleSPARQLQuery::singleResultQuery(QString query, QString binding) 602 SimpleSPARQLQuery::singleResultQuery(QString fromUri,
277 { 603 QString query, QString binding)
278 SimpleSPARQLQuery q(query); 604 {
605 SimpleSPARQLQuery q(fromUri, query);
279 ResultList results = q.execute(); 606 ResultList results = q.execute();
280 if (!q.isOK()) { 607 if (!q.isOK()) {
281 cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: " 608 cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: "
282 << q.getErrorString().toStdString() << endl; 609 << q.getErrorString().toStdString() << endl;
283 return Value(); 610 return Value();