knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
KnowledgeBase.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of KnowRob, please consult
3  * https://github.com/knowrob/knowrob for license details.
4  */
5 
6 #include <thread>
7 #include <boost/property_tree/json_parser.hpp>
8 #include <knowrob/Logger.h>
9 #include <knowrob/KnowledgeBase.h>
10 #include <knowrob/URI.h>
11 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
12 #include "knowrob/queries/QueryPipeline.h"
13 #include "knowrob/semweb/PrefixRegistry.h"
14 #include "knowrob/semweb/rdf.h"
15 #include "knowrob/semweb/owl.h"
16 #include "knowrob/semweb/rdfs.h"
17 #include "knowrob/semweb/OntologyLanguage.h"
18 #include "knowrob/reasoner/ReasonerManager.h"
19 #include "knowrob/semweb/OntologyFile.h"
20 #include "knowrob/semweb/GraphTransformation.h"
21 #include "knowrob/semweb/TransformedOntology.h"
22 #include "knowrob/integration/python/utils.h"
23 #include "knowrob/integration/python/with.h"
24 
25 #define KB_SETTING_REASONER "reasoner"
26 #define KB_SETTING_DATA_BACKENDS "data-backends"
27 #define KB_SETTING_DATA_SOURCES "data-sources"
28 #define KB_SETTING_DATA_TRANSFORMATION "transformation"
29 #define KB_SETTING_SEMWEB "semantic-web"
30 #define KB_SETTING_PREFIXES "prefixes"
31 #define KB_SETTING_PREFIX_ALIAS "alias"
32 #define KB_SETTING_PREFIX_URI "uri"
33 
34 using namespace knowrob;
35 
37  : isInitialized_(false) {
38  vocabulary_ = std::make_shared<Vocabulary>();
39  // use "system" as default origin until initialization completed
40  vocabulary_->importHierarchy()->setDefaultGraph(ImportHierarchy::ORIGIN_SYSTEM);
41  backendManager_ = std::make_shared<StorageManager>(vocabulary_);
42  reasonerManager_ = std::make_shared<ReasonerManager>(this, backendManager_);
43  edb_ = std::make_shared<StorageInterface>(backendManager_);
44 }
45 
46 KnowledgeBase::KnowledgeBase(const boost::property_tree::ptree &config) : KnowledgeBase() {
47  configure(config);
48  init();
49 }
50 
51 KnowledgeBase::KnowledgeBase(std::string_view configFile) : KnowledgeBase() {
52  boost::property_tree::ptree config;
53  // Test if string is a JSON string or a file path
54  if (configFile.find_first_of('{') == 0) {
55  std::istringstream json_stream(configFile.data());
56  boost::property_tree::read_json(json_stream, config);
57  } else {
58  boost::property_tree::read_json(URI::resolve(configFile), config);
59  }
60  configure(config);
61  init();
62 }
63 
65  stopReasoner();
66  if(observerManager_) {
67  observerManager_->stop();
68  observerManager_ = nullptr;
69  }
70  edb_ = nullptr;
71  backendManager_ = nullptr;
72  reasonerManager_ = nullptr;
73  vocabulary_ = nullptr;
74 }
75 
76 std::shared_ptr<KnowledgeBase> KnowledgeBase::create(const boost::property_tree::ptree &config) {
77  return std::shared_ptr<KnowledgeBase>(new KnowledgeBase(config));
78 }
79 
80 std::shared_ptr<KnowledgeBase> KnowledgeBase::create(std::string_view config) {
81  return std::shared_ptr<KnowledgeBase>(new KnowledgeBase(config));
82 }
83 
84 std::shared_ptr<KnowledgeBase> KnowledgeBase::create() {
85  return std::shared_ptr<KnowledgeBase>(new KnowledgeBase());
86 }
87 
89  isInitialized_ = true;
90  vocabulary_->importHierarchy()->setDefaultGraph(ImportHierarchy::ORIGIN_USER);
91  initBackends();
94 
95  observerManager_ = std::make_shared<ObserverManager>(getBackendForQuery());
96  startReasoner();
97 }
98 
100  for (auto &pair: backendManager_->plugins()) {
101  auto definedBackend = pair.second;
102  definedBackend->value()->setVocabulary(vocabulary_);
103  }
104 }
105 
107  // find all non-persistent backends, which we assume to be empty at this point
108  std::vector<std::shared_ptr<NamedBackend>> nonPersistent;
109  for (auto &it: backendManager_->plugins()) {
110  auto backend = it.second->value();
111  auto queryable = backendManager_->queryable().find(it.first);
112  if (queryable == backendManager_->queryable().end() || !queryable->second->isPersistent()) {
113  nonPersistent.push_back(it.second);
114  }
115  }
116 
117  // synchronize persistent backends with each other
118  if (backendManager_->persistent().size() > 1) {
119  // find versions of persisted origins
120  using BackendOriginVersion = std::pair<std::shared_ptr<QueryableStorage>, VersionedOriginPtr>;
121  std::map<std::string_view, std::vector<BackendOriginVersion>> origins;
122  for (auto &it: backendManager_->persistent()) {
123  auto persistentBackend = it.second;
124  for (auto &origin: persistentBackend->getOrigins()) {
125  origins[origin->value()].emplace_back(it.second, origin);
126  }
127  }
128 
129  // drop all persisted origins with an outdated version
130  for (auto &origin_pair: origins) {
131  auto &v = origin_pair.second;
132  if (v.size() < 2) continue;
133  // find the maximum version
134  std::string_view maxVersion;
135  for (auto &version: v) {
136  if (!maxVersion.empty() && version.second->version() > maxVersion) {
137  maxVersion = version.second->version();
138  }
139  }
140  // drop origin for backends with outdated version, also remove such backends from "origins" array
141  v.erase(std::remove_if(v.begin(), v.end(),
142  [&maxVersion](const BackendOriginVersion &bov) {
143  if (bov.second->version() != maxVersion) {
144  bov.first->removeAllWithOrigin(bov.second->value());
145  return true;
146  } else {
147  return false;
148  }
149  }), v.end());
150  }
151 
152  // At this point, origins contains only the backends with the latest version.
153  // So data can be copied from any of them into all other persistent backends that do
154  // not have the data yet.
155  for (auto &origin_pair: origins) {
156  // First find all persistent backends that do not appear in origin_pair.
157  // These are the ones without the data.
158  std::vector<std::shared_ptr<NamedBackend>> included;
159  for (auto &it: backendManager_->persistent()) {
160  auto &persistentBackend = it.second;
161  if (std::find_if(origin_pair.second.begin(), origin_pair.second.end(),
162  [&persistentBackend](const BackendOriginVersion &bov) {
163  return bov.first == persistentBackend;
164  }) == origin_pair.second.end()) {
165  included.push_back(backendManager_->getPluginWithID(it.first));
166  }
167  }
168  if (included.empty()) continue;
169 
170  // Now copy the data from one of the backends in origin_pair to all backends in included.
171  auto &persistedBackend = origin_pair.second.begin()->first;
172  auto transaction = edb_->createTransaction(
173  persistedBackend,
176  included);
177  persistedBackend->batchOrigin(origin_pair.first, [&](const TripleContainerPtr &triples) {
178  transaction->commit(triples);
179  });
180  }
181  }
182 
183  // insert from first persistent backend into all non-persistent backends.
184  // persistent backends are synchronized before, so we can just take the first one.
185  if (!backendManager_->persistent().empty() && !nonPersistent.empty()) {
186  KB_DEBUG("Synchronizing persistent triples into {} non-persistent backends.", nonPersistent.size());
187  auto &persistedBackend = *backendManager_->persistent().begin();
188  auto transaction = edb_->createTransaction(
189  getBackendForQuery(),
192  nonPersistent);
193  persistedBackend.second->batch([&](const TripleContainerPtr &triples) { transaction->commit(triples); });
194  }
195 }
196 
197 void KnowledgeBase::initVocabulary() {
198  auto v_s = std::make_shared<Variable>("?s");
199  auto v_o = std::make_shared<Variable>("?o");
200 
201  for (auto &it: backendManager_->persistent()) {
202  auto backend = it.second;
203 
204  // initialize the import hierarchy
205  for (auto &origin: backend->getOrigins()) {
206  vocabulary_->importHierarchy()->addDirectImport(vocabulary_->importHierarchy()->ORIGIN_SYSTEM,
207  origin->value());
208  }
209 
210  // iterate over all rdf:type assertions and add them to the vocabulary
211  backend->match(TriplePattern(v_s, rdf::type, v_o),
212  [this](const TriplePtr &triple) {
213  vocabulary_->addResourceType(triple->subject(), triple->valueAsString());
214  vocabulary_->increaseFrequency(rdf::type->stringForm());
215  });
216  // iterate over all rdfs::subClassOf assertions and add them to the vocabulary
217  backend->match(TriplePattern(v_s, rdfs::subClassOf, v_o),
218  [this](const TriplePtr &triple) {
219  vocabulary_->addSubClassOf(triple->subject(), triple->valueAsString(), triple->graph());
220  vocabulary_->increaseFrequency(rdfs::subClassOf->stringForm());
221  });
222  // iterate over all rdfs::subPropertyOf assertions and add them to the vocabulary
223  backend->match(TriplePattern(v_s, rdfs::subPropertyOf, v_o),
224  [this](const TriplePtr &triple) {
225  vocabulary_->addSubPropertyOf(triple->subject(), triple->valueAsString(), triple->graph());
226  vocabulary_->increaseFrequency(rdfs::subPropertyOf->stringForm());
227  });
228  // iterate over all owl::inverseOf assertions and add them to the vocabulary
229  backend->match(TriplePattern(v_s, owl::inverseOf, v_o),
230  [this](const TriplePtr &triple) {
231  vocabulary_->setInverseOf(triple->subject(), triple->valueAsString());
232  vocabulary_->increaseFrequency(owl::inverseOf->stringForm());
233  });
234 
235  // query number of assertions of each property/class.
236  // this is useful information for optimizing the query planner.
237  std::vector<semweb::PropertyPtr> reifiedProperties;
238  backend->count([this, &reifiedProperties](std::string_view resource, uint64_t count) {
239  // special handling for reified relations: they are concepts, but do also increase the relation counter
240  auto reifiedProperty = vocabulary_->getDefinedReification(resource);
241  if (reifiedProperty) reifiedProperties.push_back(reifiedProperty);
242  vocabulary_->setFrequency(resource, count);
243  });
244  for (auto &p: reifiedProperties) {
245  vocabulary_->increaseFrequency(p->iri());
246  }
247  }
248 }
249 
250 void KnowledgeBase::configure(const boost::property_tree::ptree &config) {
251  configurePrefixes(config);
252  // initialize data backends from configuration
253  configureBackends(config);
254  // share vocabulary and import hierarchy with backends
255  initBackends();
256  // load common ontologies
257  loadCommon();
258  // load the "global" data sources.
259  // these are data sources that are loaded into all backends, however
260  // the backends may decide to ignore some of the data sources.
261  configureDataSources(config);
262  // load reasoners from configuration
263  configureReasoner(config);
264 }
265 
266 void KnowledgeBase::configurePrefixes(const boost::property_tree::ptree &config) {
267  auto semwebTree = config.get_child_optional(KB_SETTING_SEMWEB);
268  if (semwebTree) {
269  // load RDF URI aliases
270  auto prefixesList = semwebTree.value().get_child_optional(KB_SETTING_PREFIXES);
271  for (const auto &pair: prefixesList.value()) {
272  auto alias = pair.second.get(KB_SETTING_PREFIX_ALIAS, "");
273  auto uri = pair.second.get(KB_SETTING_PREFIX_URI, "");
274  if (!alias.empty() && !uri.empty()) {
275  PrefixRegistry::registerPrefix(alias, uri);
276  } else {
277  KB_WARN("Invalid entry in semantic-web::prefixes, 'alias' and 'uri' must be defined.");
278  }
279  }
280  }
281 }
282 
283 void KnowledgeBase::configureBackends(const boost::property_tree::ptree &config) {
284  auto backendList = config.get_child_optional(KB_SETTING_DATA_BACKENDS);
285  if (backendList) {
286  for (const auto &pair: backendList.value()) {
287  KB_LOGGED_TRY_CATCH(pair.first, "load", { backendManager_->loadPlugin(pair.second); });
288  }
289  } else {
290  KB_ERROR("configuration has no 'backends' key.");
291  }
292 }
293 
294 void KnowledgeBase::configureReasoner(const boost::property_tree::ptree &config) {
295  auto reasonerList = config.get_child_optional(KB_SETTING_REASONER);
296  if (reasonerList) {
297  for (const auto &pair: reasonerList.value()) {
298  KB_LOGGED_TRY_CATCH(pair.first, "load", {
299  auto definedReasoner = reasonerManager_->loadPlugin(pair.second);
300  // if reasoner implements DataBackend class, add it to the backend manager
301  auto reasonerBackend = std::dynamic_pointer_cast<Storage>(definedReasoner->value());
302  if (reasonerBackend) {
303  backendManager_->addPlugin(definedReasoner->name(), definedReasoner->language(), reasonerBackend);
304  }
305  });
306  }
307  } else {
308  KB_ERROR("configuration has no 'reasoner' key.");
309  }
310 }
311 
313  for (auto &ontoPath: {"owl/rdf-schema.xml", "owl/owl.rdf"}) {
314  loadDataSource(std::make_shared<OntologyFile>(vocabulary_, URI(ontoPath), "rdf-xml"));
315  }
316 }
317 
318 static void do_startReasoner(const std::shared_ptr<DataDrivenReasoner> &reasoner) {
319  if (reasoner->reasonerLanguage() == PluginLanguage::PYTHON) {
320  py::gil_lock lock;
321  reasoner->start();
322  } else {
323  reasoner->start();
324  }
325 }
326 
328  std::vector<std::string_view> failedToStartReasoner;
329  for (auto &pair: reasonerManager_->dataDriven()) {
330  KB_LOGGED_TRY_EXCEPT(pair.first.data(), "start",
331  { do_startReasoner(pair.second); },
332  { failedToStartReasoner.push_back(pair.first); });
333  }
334  // remove reasoner that failed to start
335  for (auto &reasonerName: failedToStartReasoner) {
336  reasonerManager_->removePlugin(reasonerName);
337  }
338 }
339 
341  for (auto &pair: reasonerManager_->dataDriven()) {
342  KB_LOGGED_TRY_CATCH(pair.first.data(), "stop", { pair.second->stop(); });
343  }
344 }
345 
347  auto &queryable = backendManager_->queryable();
348  if (queryable.empty()) {
349  KB_WARN("No queryable backends available.");
350  return nullptr;
351  } else {
352  return queryable.begin()->second;
353  }
354 }
355 
357  return submitQuery(std::make_shared<ConjunctiveQuery>(ConjunctiveQuery({literal}, ctx)));
358 }
359 
361  auto pipeline = std::make_shared<QueryPipeline>(shared_from_this(), conjunctiveQuery);
362  // Wrap output into AnswerBuffer_WithReference object.
363  // Note that the AnswerBuffer_WithReference object is used such that the caller can
364  // destroy the whole pipeline by de-referencing the returned AnswerBufferPtr.
365  auto out = std::make_shared<AnswerBuffer_WithReference>(pipeline);
366  *pipeline >> out;
367  pipeline->stopBuffering();
368  return out;
369 }
370 
372  auto pipeline = std::make_shared<QueryPipeline>(shared_from_this(), phi, ctx);
373  auto out = std::make_shared<AnswerBuffer_WithReference>(pipeline);
374  *pipeline >> out;
375  pipeline->stopBuffering();
376  return out;
377 }
378 
380  return observerManager_->observe(query, callback);
381 }
382 
384  observerManager_->synchronize();
385 }
386 
387 bool KnowledgeBase::insertOne(const Triple &triple) {
388  auto sourceBackend = findSourceBackend(triple);
389  auto transaction = edb_->createTransaction(
393  {sourceBackend});
394  if (transaction->commit(triple)) {
395  auto tripleCopy = new TripleCopy(triple);
396  std::vector<TriplePtr> triples;
397  triples.emplace_back(tripleCopy);
398  auto container = std::make_shared<ProxyTripleContainer>(triples);
399  observerManager_->insert(container);
400  return true;
401  } else {
402  return false;
403  }
404 }
405 
407  auto sourceBackend = findSourceBackend(**triples->begin());
408  auto transaction = edb_->createTransaction(
412  {sourceBackend});
413  if (transaction->commit(triples)) {
414  observerManager_->insert(triples);
415  return true;
416  } else {
417  return false;
418  }
419 }
420 
421 bool KnowledgeBase::removeOne(const Triple &triple) {
422  auto sourceBackend = findSourceBackend(triple);
423  auto transaction = edb_->createTransaction(
427  {sourceBackend});
428  if (transaction->commit(triple)) {
429  auto tripleCopy = new TripleCopy(triple);
430  std::vector<TriplePtr> triples;
431  triples.emplace_back(tripleCopy);
432  auto container = std::make_shared<ProxyTripleContainer>(triples);
433  observerManager_->remove(container);
434  return true;
435  } else {
436  return false;
437  }
438 }
439 
441  auto sourceBackend = findSourceBackend(**triples->begin());
442  auto transaction = edb_->createTransaction(
446  {sourceBackend});
447  if (transaction->commit(triples)) {
448  observerManager_->remove(triples);
449  return true;
450  } else {
451  return false;
452  }
453 }
454 
455 bool KnowledgeBase::insertAll(const std::vector<TriplePtr> &triples) {
456  // Note: insertAll blocks until the triples are inserted, so it is safe to use the triples vector as a pointer.
457  return insertAll(std::make_shared<ProxyTripleContainer>(&triples));
458 }
459 
460 bool KnowledgeBase::removeAll(const std::vector<TriplePtr> &triples) {
461  return removeAll(std::make_shared<ProxyTripleContainer>(&triples));
462 }
463 
464 bool KnowledgeBase::removeAllWithOrigin(std::string_view origin) {
465  return edb_->removeAllWithOrigin(origin);
466 }
467 
468 std::shared_ptr<NamedBackend> KnowledgeBase::findSourceBackend(const Triple &triple) {
469  if (!triple.graph()) return {};
470 
471  auto definedBackend_withID = backendManager_->getPluginWithID(triple.graph().value());
472  if (definedBackend_withID) return definedBackend_withID;
473 
474  auto definedReasoner = reasonerManager_->getPluginWithID(triple.graph().value());
475  if (definedReasoner) {
476  auto reasonerBackend = reasonerManager_->getReasonerStorage(definedReasoner);
477  if (reasonerBackend) {
478  for (auto &it: backendManager_->plugins()) {
479  auto &definedBackend_ofReasoner = it.second;
480  if (definedBackend_ofReasoner->value() == reasonerBackend) {
481  return definedBackend_ofReasoner;
482  }
483  }
484  }
485  }
486 
487  return {};
488 }
489 
490 void KnowledgeBase::configureDataSources(const boost::property_tree::ptree &config) {
491  auto dataSourcesList = config.get_child_optional(KB_SETTING_DATA_SOURCES);
492  if (!dataSourcesList) return;
493 
494  for (const auto &pair: dataSourcesList.value()) {
495  auto &subtree = pair.second;
496  auto dataSource = DataSource::create(vocabulary_, subtree);
497  if (!dataSource) {
498  KB_ERROR("Failed to create data source \"{}\".", pair.first);
499  continue;
500  }
501  bool has_error;
502  auto transformationConfig = config.get_child_optional(KB_SETTING_DATA_TRANSFORMATION);
503  if (transformationConfig) {
504  if (dataSource->dataSourceType() != DataSourceType::ONTOLOGY) {
505  KB_ERROR("Transformations can only be applied on ontology data sources.");
506  continue;
507  }
508  auto ontology = std::static_pointer_cast<OntologySource>(dataSource);
509  // apply a transformation to the data source if "transformation" key is present
510  auto transformation = GraphTransformation::create(transformationConfig.value());
511  auto transformed = std::make_shared<TransformedOntology>(URI(ontology->uri()), ontology->format());
512  transformation->apply(*ontology, [&transformed](const TripleContainerPtr &triples) {
513  transformed->storage()->insertAll(triples);
514  });
515  has_error = !loadDataSource(transformed);
516  } else {
517  has_error = !loadDataSource(dataSource);
518  }
519  if (has_error) {
520  KB_ERROR("Failed to load data source from \"{}\".", dataSource->uri());
521  }
522  }
523 }
524 
526  switch (source->dataSourceType()) {
528  return loadOntologySource(std::static_pointer_cast<OntologySource>(source));
530  return loadNonOntologySource(source);
531  }
532  return false;
533 }
534 
535 std::optional<std::string> KnowledgeBase::getVersionOfOrigin(
536  const std::shared_ptr<NamedBackend> &definedBackend, std::string_view origin) const {
537  // check if the origin was loaded before in this session
538  auto runtimeVersion = definedBackend->value()->getVersionOfOrigin(origin);
539  if (runtimeVersion) return runtimeVersion;
540  // otherwise check if the backend is persistent and if so, ask the persistent backend
541  auto persistentBackend = backendManager_->persistent().find(definedBackend->name());
542  if (persistentBackend != backendManager_->persistent().end()) {
543  return persistentBackend->second->getVersionOfOrigin(origin);
544  }
545  return {};
546 }
547 
548 std::vector<std::shared_ptr<NamedBackend>>
549 KnowledgeBase::prepareLoad(std::string_view origin, std::string_view newVersion) const {
550  std::vector<std::shared_ptr<NamedBackend>> backendsToLoad;
551  for (auto &it: backendManager_->plugins()) {
552  // check if the ontology is already loaded by the backend,
553  // and if so whether it has the right version.
554  auto definedBackend = it.second;
555  auto currentVersion = getVersionOfOrigin(definedBackend, origin);
556  if (currentVersion.has_value()) {
557  if (currentVersion.value() != newVersion) {
558  backendsToLoad.emplace_back(it.second);
559  definedBackend->value()->removeAllWithOrigin(origin);
560  }
561  } else {
562  backendsToLoad.emplace_back(it.second);
563  }
564  }
565  return backendsToLoad;
566 }
567 
568 void KnowledgeBase::finishLoad(const std::shared_ptr<OntologySource> &source, std::string_view origin,
569  std::string_view newVersion) {
570  // update the version triple
571  for (auto &it: backendManager_->plugins()) {
572  it.second->value()->setVersionOfOrigin(origin, newVersion);
573  }
574  for (auto &it: backendManager_->persistent()) {
575  auto persistentBackend = it.second;
576  persistentBackend->setVersionOfOrigin(origin, newVersion);
577  }
578 
579  // add direct import
580  if (source->parentOrigin().has_value()) {
581  vocabulary_->importHierarchy()->addDirectImport(source->parentOrigin().value(), origin);
582  } else {
583  vocabulary_->importHierarchy()->addDirectImport(vocabulary_->importHierarchy()->defaultGraph(), origin);
584  }
585 }
586 
587 bool KnowledgeBase::loadOntologySource(const std::shared_ptr<OntologySource> &source) { // NOLINT(misc-no-recursion)
588  auto uri = URI::resolve(source->uri());
589  // Some ontologies may encode version in the URI which we try to extract
590  // below. Otherwise, we just use the current day as version causing a re-load every day.
591  auto newVersion = DataSource::getVersionFromURI(uri);
592 
593  // get all backends that do not have the data loaded yet
594  auto backendsToLoad = prepareLoad(source->origin(), newVersion);
595  if (backendsToLoad.empty()) {
596  // data is already loaded
597  KB_DEBUG("Ontology at \"{}\" already loaded.", uri);
598  return true;
599  }
600 
601  auto result = source->load([this, &backendsToLoad](const TripleContainerPtr &triples) {
602  auto transaction = edb_->createTransaction(
606  backendsToLoad);
607  transaction->commit(triples);
608  });
609  if (!result) {
610  KB_WARN("Failed to load ontology \"{}\".", uri);
611  return false;
612  }
613  finishLoad(source, source->origin(), newVersion);
614 
615  for (auto &imported: source->imports()) {
616  auto importedSource = std::make_shared<OntologyFile>(vocabulary_, URI(imported), source->format());
617  if (!loadOntologySource(importedSource)) {
618  KB_WARN("Failed to load imported ontology \"{}\".", imported);
619  return false;
620  }
621  }
622 
623  return true;
624 }
625 
627  bool hasHandler = false;
628  bool allSucceeded = true;
629 
630  for (auto &kg_pair: backendManager_->plugins()) {
631  auto backend = kg_pair.second->value();
632  if (backend->hasDataHandler(source)) {
633  if (!backend->loadDataSource(source)) {
634  allSucceeded = false;
635  KB_WARN("backend '{}' failed to load data source '{}'", kg_pair.first, source->uri());
636  }
637  hasHandler = true;
638  }
639  }
640 
641  if (!hasHandler) {
642  KB_WARN("no data handler for data source format '{}'", source->format());
643  }
644 
645  return hasHandler && allSucceeded;
646 }
647 
648 void KnowledgeBase::setDefaultGraph(std::string_view origin) {
649  vocabulary_->importHierarchy()->setDefaultGraph(origin);
650 }
651 
652 static std::shared_ptr<KnowledgeBase> makeKB1() {
653  return KnowledgeBase::create();
654 }
655 
656 static std::shared_ptr<KnowledgeBase> makeKB2(std::string_view settingsFile) {
657  return KnowledgeBase::create(settingsFile);
658 }
659 
660 static std::shared_ptr<KnowledgeBase> makeKB3(const boost::property_tree::ptree &settingsTree) {
661  return KnowledgeBase::create(settingsTree);
662 }
663 
664 namespace knowrob::py {
665  template<>
667  using namespace boost::python;
668 
669  // these typedefs are necessary to resolve functions with duplicate names which is
670  // fine in C++ but not in Python, so they need special handling here.
671  // The typedefs are used to explicitly select the mapped method.
672  using QueryPredicate = TokenBufferPtr (KnowledgeBase::*)(const FirstOrderLiteralPtr &, const QueryContextPtr &);
673  using QueryFormula = TokenBufferPtr (KnowledgeBase::*)(const FormulaPtr &, const QueryContextPtr &);
674  using QueryGraph = TokenBufferPtr (KnowledgeBase::*)(const ConjunctiveQueryPtr &);
675  using ContainerAction = bool (KnowledgeBase::*)(const TripleContainerPtr &);
676  using ListAction = bool (KnowledgeBase::*)(const std::vector<TriplePtr> &);
677 
680 
681  class_<KnowledgeBase, std::shared_ptr<KnowledgeBase>, boost::noncopyable>
682  ("KnowledgeBase", no_init)
683  // hide the "create" functions in Python
684  .def("__init__", make_constructor(&makeKB1))
685  .def("__init__", make_constructor(&makeKB2))
686  .def("__init__", make_constructor(&makeKB3))
687  .def("setDefaultGraph", &KnowledgeBase::setDefaultGraph)
688  .def("vocabulary", &KnowledgeBase::vocabulary, return_value_policy<copy_const_reference>())
689  .def("loadCommon", with<no_gil>(&KnowledgeBase::loadCommon))
690  .def("loadDataSource", with<no_gil>(&KnowledgeBase::loadDataSource))
691  .def("submitQuery", with<no_gil>(static_cast<QueryFormula>(&KnowledgeBase::submitQuery)))
692  .def("submitQuery", with<no_gil>(static_cast<QueryPredicate>(&KnowledgeBase::submitQuery)))
693  .def("submitQuery", with<no_gil>(static_cast<QueryGraph>(&KnowledgeBase::submitQuery)))
694  .def("observe", +[](KnowledgeBase &kb, const GraphQueryPtr &query, object &fn) {
695  no_gil unlock;
696  return kb.observe(query, [fn](const BindingsPtr &bindings) {
697  // make sure to lock the GIL before calling the Python function
698  gil_lock lock;
699  fn(bindings);
700  });
701  })
702  .def("insertOne", with<no_gil>(&KnowledgeBase::insertOne))
703  .def("insertAll", with<no_gil>(static_cast<ContainerAction>(&KnowledgeBase::insertAll)))
704  .def("insertAll", with<no_gil>(static_cast<ListAction>(&KnowledgeBase::insertAll)))
705  .def("removeOne", with<no_gil>(&KnowledgeBase::removeOne))
706  .def("removeAll", with<no_gil>(static_cast<ContainerAction>(&KnowledgeBase::removeAll)))
707  .def("removeAll", with<no_gil>(static_cast<ListAction>(&KnowledgeBase::removeAll)))
708  .def("removeAllWithOrigin", with<no_gil>(&KnowledgeBase::removeAllWithOrigin));
709  }
710 }
#define KB_SETTING_DATA_SOURCES
#define KB_SETTING_REASONER
#define KB_SETTING_SEMWEB
#define KB_SETTING_PREFIX_URI
#define KB_SETTING_DATA_TRANSFORMATION
#define KB_SETTING_PREFIX_ALIAS
#define KB_SETTING_PREFIXES
#define KB_SETTING_DATA_BACKENDS
#define KB_LOGGED_TRY_EXCEPT(name, type, goal, except)
Definition: Logger.h:157
#define KB_DEBUG
Definition: Logger.h:25
#define KB_ERROR
Definition: Logger.h:28
#define KB_LOGGED_TRY_CATCH(name, type, goal)
Definition: Logger.h:142
#define KB_WARN
Definition: Logger.h:27
static std::string getVersionFromURI(const std::string &uriString)
Definition: DataSource.cpp:48
static std::shared_ptr< DataSource > create(const VocabularyPtr &vocabulary, const boost::property_tree::ptree &config)
Definition: DataSource.cpp:105
static std::shared_ptr< GraphTransformation > create(const boost::property_tree::ptree &config)
static constexpr std::string_view ORIGIN_USER
static constexpr std::string_view ORIGIN_SYSTEM
bool loadNonOntologySource(const DataSourcePtr &source) const
bool removeOne(const Triple &triple)
bool insertAll(const TripleContainerPtr &triples)
std::optional< std::string > getVersionOfOrigin(const std::shared_ptr< NamedBackend > &definedBackend, std::string_view origin) const
std::vector< std::shared_ptr< NamedBackend > > prepareLoad(std::string_view origin, std::string_view newVersion) const
void finishLoad(const std::shared_ptr< OntologySource > &source, std::string_view origin, std::string_view newVersion)
bool removeAllWithOrigin(std::string_view origin)
void configureBackends(const boost::property_tree::ptree &config)
bool insertOne(const Triple &triple)
std::shared_ptr< NamedBackend > findSourceBackend(const Triple &triple)
std::shared_ptr< StorageManager > backendManager_
QueryableBackendPtr getBackendForQuery() const
void setDefaultGraph(std::string_view origin)
std::shared_ptr< ReasonerManager > reasonerManager_
static void configurePrefixes(const boost::property_tree::ptree &config)
void configureReasoner(const boost::property_tree::ptree &config)
bool loadOntologySource(const std::shared_ptr< OntologySource > &source)
auto & vocabulary() const
Definition: KnowledgeBase.h:67
void configure(const boost::property_tree::ptree &config)
bool loadDataSource(const DataSourcePtr &source)
static std::shared_ptr< KnowledgeBase > create()
std::shared_ptr< StorageInterface > edb_
std::shared_ptr< Vocabulary > vocabulary_
bool removeAll(const TripleContainerPtr &triples)
ObserverPtr observe(const GraphQueryPtr &query, const BindingsHandler &callback)
std::shared_ptr< ObserverManager > observerManager_
TokenBufferPtr submitQuery(const ConjunctiveQueryPtr &conjunctiveQuery)
void configureDataSources(const boost::property_tree::ptree &config)
static void registerPrefix(std::string_view prefix, std::string_view uri)
virtual std::string_view valueAsString() const =0
virtual std::optional< std::string_view > graph() const =0
virtual std::string_view subject() const =0
static std::string resolve(const std::string_view &uriString)
Definition: URI.cpp:79
const IRIAtomPtr inverseOf
Definition: owl.h:17
void createType< Vocabulary >()
Definition: Vocabulary.cpp:271
void createType< KnowledgeBase >()
void createType< GraphQuery >()
Definition: GraphQuery.cpp:96
const IRIAtomPtr type
Definition: rdf.h:15
const IRIAtomPtr subPropertyOf
Definition: rdfs.h:16
const IRIAtomPtr subClassOf
Definition: rdfs.h:15
TripleTemplate< std::string > TripleCopy
Definition: Triple.h:577
std::shared_ptr< TripleContainer > TripleContainerPtr
std::shared_ptr< VersionedOrigin > VersionedOriginPtr
std::shared_ptr< Observer > ObserverPtr
Definition: Observer.h:42
std::shared_ptr< const Bindings > BindingsPtr
Definition: Bindings.h:151
std::shared_ptr< Formula > FormulaPtr
Definition: Formula.h:99
std::shared_ptr< ConjunctiveQuery > ConjunctiveQueryPtr
std::shared_ptr< TokenBuffer > TokenBufferPtr
Definition: TokenBuffer.h:43
std::function< void(const BindingsPtr &)> BindingsHandler
Definition: Bindings.h:152
std::shared_ptr< const QueryContext > QueryContextPtr
Definition: QueryContext.h:41
std::shared_ptr< GraphQuery > GraphQueryPtr
Definition: GraphQuery.h:65
std::shared_ptr< QueryableStorage > QueryableBackendPtr
std::shared_ptr< DataSource > DataSourcePtr
Definition: DataSource.h:107
std::shared_ptr< FirstOrderLiteral > FirstOrderLiteralPtr