comparison rdf/SimpleSPARQLQuery.cpp @ 489:82ab61fa9223

* Reorganise our sparql queries on the basis that Redland must be available, not only optional. So for anything querying the pool of data about plugins, we use a single datastore and model which is initialised at the outset by PluginRDFIndexer and then queried directly; for anything that "reads from a file" (e.g. loading annotations) we query directly using Rasqal, going to the datastore when we need additional plugin-related information. This may improve performance, but mostly it simplifies the code and fixes a serious issue with RDF import in the previous versions (namely that multiple sequential RDF imports would end up sharing the same RDF data pool!)
author Chris Cannam
date Fri, 21 Nov 2008 16:12:29 +0000
parents a82645e788fc
children c3fb8258e34d
comparison
equal deleted inserted replaced
488:1c66e199e7d9 489:82ab61fa9223
27 #include <rasqal/rasqal.h> 27 #include <rasqal/rasqal.h>
28 #else 28 #else
29 #include <rasqal.h> 29 #include <rasqal.h>
30 #endif 30 #endif
31 31
32 #ifdef HAVE_REDLAND
33 #include <redland.h> 32 #include <redland.h>
34 #endif
35 33
36 //#define DEBUG_SIMPLE_SPARQL_QUERY 1 34 //#define DEBUG_SIMPLE_SPARQL_QUERY 1
37 35
38 #include <iostream> 36 #include <iostream>
39 37
62 ~WrasqalWorldWrapper() 60 ~WrasqalWorldWrapper()
63 { 61 {
64 rasqal_free_world(m_world); 62 rasqal_free_world(m_world);
65 } 63 }
66 64
65 bool isOK() const { return (m_world != 0); }
66
67 rasqal_world *getWorld() { return m_world; } 67 rasqal_world *getWorld() { return m_world; }
68 const rasqal_world *getWorld() const { return m_world; } 68 const rasqal_world *getWorld() const { return m_world; }
69 69
70 private: 70 private:
71 rasqal_world *m_world; 71 rasqal_world *m_world;
72 }; 72 };
73 #endif 73 #endif
74 74
75 #ifdef HAVE_REDLAND
76 class WredlandWorldWrapper 75 class WredlandWorldWrapper
77 { 76 {
78 public: 77 public:
79 WredlandWorldWrapper() : 78 WredlandWorldWrapper() :
80 m_world(0), m_storage(0), m_model(0) 79 m_world(0), m_storage(0), m_model(0)
167 librdf_model *m_model; 166 librdf_model *m_model;
168 167
169 QMutex m_mutex; 168 QMutex m_mutex;
170 std::map<QString, librdf_uri *> m_parsedUris; 169 std::map<QString, librdf_uri *> m_parsedUris;
171 }; 170 };
172 #endif
173 171
174 class SimpleSPARQLQuery::Impl 172 class SimpleSPARQLQuery::Impl
175 { 173 {
176 public: 174 public:
177 Impl(QString fromUri, QString query); 175 Impl(SimpleSPARQLQuery::QueryType, QString query);
178 ~Impl(); 176 ~Impl();
177
178 static bool addSourceToModel(QString sourceUri);
179 179
180 void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; } 180 void setProgressReporter(ProgressReporter *reporter) { m_reporter = reporter; }
181 bool wasCancelled() const { return m_cancelled; } 181 bool wasCancelled() const { return m_cancelled; }
182 182
183 ResultList execute(); 183 ResultList execute();
184 184
185 bool isOK() const; 185 bool isOK() const;
186 QString getErrorString() const; 186 QString getErrorString() const;
187
188 static void setBackEnd(SimpleSPARQLQuery::BackEndPreference p) {
189 m_preference = p;
190 }
191 187
192 protected: 188 protected:
193 static void errorHandler(void *, raptor_locator *, const char *); 189 static void errorHandler(void *, raptor_locator *, const char *);
194 190
195 static QMutex m_mutex; 191 static QMutex m_mutex;
198 static WrasqalWorldWrapper *m_rasqal; 194 static WrasqalWorldWrapper *m_rasqal;
199 #else 195 #else
200 static bool m_rasqalInitialised; 196 static bool m_rasqalInitialised;
201 #endif 197 #endif
202 198
203 #ifdef HAVE_REDLAND
204 static WredlandWorldWrapper *m_redland; 199 static WredlandWorldWrapper *m_redland;
205 #endif
206
207 static SimpleSPARQLQuery::BackEndPreference m_preference;
208 200
209 ResultList executeDirectParser(); 201 ResultList executeDirectParser();
210 ResultList executeDatastore(); 202 ResultList executeDatastore();
211 203
212 QString m_fromUri; 204 QueryType m_type;
213 QString m_query; 205 QString m_query;
214 QString m_errorString; 206 QString m_errorString;
215 ProgressReporter *m_reporter; 207 ProgressReporter *m_reporter;
216 bool m_cancelled; 208 bool m_cancelled;
217 }; 209 };
220 WrasqalWorldWrapper *SimpleSPARQLQuery::Impl::m_rasqal = 0; 212 WrasqalWorldWrapper *SimpleSPARQLQuery::Impl::m_rasqal = 0;
221 #else 213 #else
222 bool SimpleSPARQLQuery::Impl::m_rasqalInitialised = false; 214 bool SimpleSPARQLQuery::Impl::m_rasqalInitialised = false;
223 #endif 215 #endif
224 216
225 #ifdef HAVE_REDLAND
226 WredlandWorldWrapper *SimpleSPARQLQuery::Impl::m_redland = 0; 217 WredlandWorldWrapper *SimpleSPARQLQuery::Impl::m_redland = 0;
227 #endif
228 218
229 QMutex SimpleSPARQLQuery::Impl::m_mutex; 219 QMutex SimpleSPARQLQuery::Impl::m_mutex;
230 220
231 SimpleSPARQLQuery::BackEndPreference 221 SimpleSPARQLQuery::SimpleSPARQLQuery(QueryType type, QString query) :
232 SimpleSPARQLQuery::Impl::m_preference = SimpleSPARQLQuery::AutoSelectBackEnd; 222 m_impl(new Impl(type, query))
233
234 SimpleSPARQLQuery::SimpleSPARQLQuery(QString fromUri, QString query) :
235 m_impl(new Impl(fromUri, query))
236 { 223 {
237 } 224 }
238 225
239 SimpleSPARQLQuery::~SimpleSPARQLQuery() 226 SimpleSPARQLQuery::~SimpleSPARQLQuery()
240 { 227 {
269 SimpleSPARQLQuery::getErrorString() const 256 SimpleSPARQLQuery::getErrorString() const
270 { 257 {
271 return m_impl->getErrorString(); 258 return m_impl->getErrorString();
272 } 259 }
273 260
274 void 261 bool
275 SimpleSPARQLQuery::setBackEnd(BackEndPreference p) 262 SimpleSPARQLQuery::addSourceToModel(QString sourceUri)
276 { 263 {
277 SimpleSPARQLQuery::Impl::setBackEnd(p); 264 return SimpleSPARQLQuery::Impl::addSourceToModel(sourceUri);
278 } 265 }
279 266
280 SimpleSPARQLQuery::Impl::Impl(QString fromUri, QString query) : 267 SimpleSPARQLQuery::Impl::Impl(QueryType type, QString query) :
281 m_fromUri(fromUri), 268 m_type(type),
282 m_query(query), 269 m_query(query),
283 m_reporter(0), 270 m_reporter(0),
284 m_cancelled(false) 271 m_cancelled(false)
285 { 272 {
286 #ifdef DEBUG_SIMPLE_SPARQL_QUERY 273 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
326 SimpleSPARQLQuery::ResultList 313 SimpleSPARQLQuery::ResultList
327 SimpleSPARQLQuery::Impl::execute() 314 SimpleSPARQLQuery::Impl::execute()
328 { 315 {
329 ResultList list; 316 ResultList list;
330 317
331 BackEndPreference preference;
332
333 m_mutex.lock(); 318 m_mutex.lock();
334 319
335 if (m_preference == AutoSelectBackEnd) { 320 if (m_type == QueryFromModel) {
336 #ifdef HAVE_REDLAND
337 // cerr << "librdf version: " << librdf_version_major << "." << librdf_version_minor << "." << librdf_version_release << endl;
338 if (librdf_version_major > 1 ||
339 (librdf_version_major == 1 &&
340 (librdf_version_minor > 0 ||
341 (librdf_version_minor == 0 &&
342 librdf_version_release > 7)))) {
343 cerr << "SimpleSPARQLQuery: Auto-selecting LIBRDF back-end for tree-based storage" << endl;
344 m_preference = DatastoreBackEnd;
345 }
346 #endif
347 if (m_preference == AutoSelectBackEnd) {
348 cerr << "SimpleSPARQLQuery: Auto-selecting RASQAL back-end" << endl;
349 m_preference = DirectParserBackEnd;
350 }
351 }
352
353 if (m_preference == DatastoreBackEnd) {
354 #ifdef HAVE_REDLAND
355 if (!m_redland) { 321 if (!m_redland) {
356 m_redland = new WredlandWorldWrapper(); 322 // There can be no results, because no sources have been
357 if (!m_redland->isOK()) { 323 // added to the model yet (m_redland is only created when
358 cerr << "WARNING: SimpleSPARQLQuery::execute: Failed to initialise Redland datastore, falling back to direct parser implementation" << endl; 324 // addSourceToModel is called)
359 delete m_redland; 325 cerr << "SimpleSPARQLQuery::execute: NOTE: No sources have been added to data model yet, so no results are possible" << endl;
360 m_preference = DirectParserBackEnd; 326 m_mutex.unlock();
361 } 327 return list;
362 } 328 }
363 #else 329 }
364 cerr << "WARNING: SimpleSPARQLQuery::execute: Datastore implementation preference indicated, but no datastore compiled in; using direct parser" << endl; 330
365 m_preference = DirectParserBackEnd; 331 if (m_type == QueryFromSingleSource) {
366 #endif
367 }
368
369 if (m_preference == DirectParserBackEnd) {
370 #ifdef USE_NEW_RASQAL_API 332 #ifdef USE_NEW_RASQAL_API
371 if (!m_rasqal) m_rasqal = new WrasqalWorldWrapper(); 333 if (!m_rasqal) {
334 m_rasqal = new WrasqalWorldWrapper();
335 if (!m_rasqal->isOK()) {
336 cerr << "ERROR: SimpleSPARQLQuery::execute: Failed to initialise Rasqal query engine" << endl;
337 delete m_rasqal;
338 m_rasqal = 0;
339 m_mutex.unlock();
340 return list;
341 }
342 }
372 #else 343 #else
373 if (!m_rasqalInitialised) { 344 if (!m_rasqalInitialised) {
374 rasqal_init(); 345 rasqal_init();
375 m_rasqalInitialised = true; 346 m_rasqalInitialised = true;
376 } 347 }
377 #endif 348 #endif
378 } 349 }
379 350
380 preference = m_preference;
381 m_mutex.unlock(); 351 m_mutex.unlock();
382 352
383 if (preference == SimpleSPARQLQuery::DirectParserBackEnd) { 353 if (m_type == QueryFromSingleSource) {
384 return executeDirectParser(); 354 return executeDirectParser();
385 } else { 355 } else {
386 return executeDatastore(); 356 return executeDatastore();
387 } 357 }
388 } 358 }
508 478
509 SimpleSPARQLQuery::ResultList 479 SimpleSPARQLQuery::ResultList
510 SimpleSPARQLQuery::Impl::executeDatastore() 480 SimpleSPARQLQuery::Impl::executeDatastore()
511 { 481 {
512 ResultList list; 482 ResultList list;
513 #ifndef HAVE_REDLAND 483
514 // This should have been caught by execute()
515 cerr << "SimpleSPARQLQuery: INTERNAL ERROR: Datastore not compiled in" << endl;
516 return list;
517 #else
518 Profiler profiler("SimpleSPARQLQuery::executeDatastore"); 484 Profiler profiler("SimpleSPARQLQuery::executeDatastore");
519 485
520 librdf_uri *uri = m_redland->getUri(m_fromUri, m_errorString);
521 if (!uri) return list;
522
523 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
524 std::cerr << "SimpleSPARQLQuery: Query is: \"" << m_query.toStdString() << "\"" << std::endl;
525 #endif
526 /*!!! 486 /*!!!
527 static std::map<QString, int> counter; 487 static std::map<QString, int> counter;
528 if (counter.find(m_query) == counter.end()) counter[m_query] = 1; 488 if (counter.find(m_query) == counter.end()) counter[m_query] = 1;
529 else ++counter[m_query]; 489 else ++counter[m_query];
530 std::cerr << "Counter for this query: " << counter[m_query] << std::endl; 490 std::cerr << "Counter for this query: " << counter[m_query] << std::endl;
535 495
536 { 496 {
537 Profiler p("SimpleSPARQLQuery: Prepare LIBRDF query"); 497 Profiler p("SimpleSPARQLQuery: Prepare LIBRDF query");
538 query = librdf_new_query 498 query = librdf_new_query
539 (m_redland->getWorld(), "sparql", NULL, 499 (m_redland->getWorld(), "sparql", NULL,
540 (const unsigned char *)m_query.toUtf8().data(), uri); 500 (const unsigned char *)m_query.toUtf8().data(), NULL);
541 } 501 }
542 502
543 if (!query) { 503 if (!query) {
544 m_errorString = "Failed to construct query"; 504 m_errorString = "Failed to construct query";
545 return list; 505 return list;
648 #ifdef DEBUG_SIMPLE_SPARQL_QUERY 608 #ifdef DEBUG_SIMPLE_SPARQL_QUERY
649 cerr << "All results retrieved (" << resultCount << " of them)" << endl; 609 cerr << "All results retrieved (" << resultCount << " of them)" << endl;
650 #endif 610 #endif
651 611
652 return list; 612 return list;
653 #endif 613 }
614
615 bool
616 SimpleSPARQLQuery::Impl::addSourceToModel(QString sourceUri)
617 {
618 QString err;
619
620 m_mutex.lock();
621
622 if (!m_redland) {
623 m_redland = new WredlandWorldWrapper();
624 if (!m_redland->isOK()) {
625 cerr << "ERROR: SimpleSPARQLQuery::addSourceToModel: Failed to initialise Redland datastore" << endl;
626 delete m_redland;
627 m_redland = 0;
628 m_mutex.unlock();
629 return false;
630 }
631 }
632
633 m_mutex.unlock();
634
635 librdf_uri *uri = m_redland->getUri(sourceUri, err);
636
637 if (!uri) {
638 std::cerr << "SimpleSPARQLQuery::addSourceToModel: Failed to add source URI \"" << sourceUri.toStdString() << ": " << err.toStdString() << std::endl;
639 return false;
640 }
641 return true;
654 } 642 }
655 643
656 SimpleSPARQLQuery::Value 644 SimpleSPARQLQuery::Value
657 SimpleSPARQLQuery::singleResultQuery(QString fromUri, 645 SimpleSPARQLQuery::singleResultQuery(QueryType type,
658 QString query, QString binding) 646 QString query, QString binding)
659 { 647 {
660 SimpleSPARQLQuery q(fromUri, query); 648 SimpleSPARQLQuery q(type, query);
661 ResultList results = q.execute(); 649 ResultList results = q.execute();
662 if (!q.isOK()) { 650 if (!q.isOK()) {
663 cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: " 651 cerr << "SimpleSPARQLQuery::singleResultQuery: ERROR: "
664 << q.getErrorString().toStdString() << endl; 652 << q.getErrorString().toStdString() << endl;
665 return Value(); 653 return Value();