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"
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"
37 : isInitialized_(false) {
52 boost::property_tree::ptree config;
54 if (configFile.find_first_of(
'{') == 0) {
55 std::istringstream json_stream(configFile.data());
56 boost::property_tree::read_json(json_stream, config);
58 boost::property_tree::read_json(
URI::resolve(configFile), config);
77 return std::shared_ptr<KnowledgeBase>(
new KnowledgeBase(config));
81 return std::shared_ptr<KnowledgeBase>(
new KnowledgeBase(config));
101 auto definedBackend = pair.second;
102 definedBackend->value()->setVocabulary(
vocabulary_);
108 std::vector<std::shared_ptr<NamedBackend>> nonPersistent;
110 auto backend = it.second->value();
112 if (queryable ==
backendManager_->queryable().end() || !queryable->second->isPersistent()) {
113 nonPersistent.push_back(it.second);
120 using BackendOriginVersion = std::pair<std::shared_ptr<QueryableStorage>,
VersionedOriginPtr>;
121 std::map<std::string_view, std::vector<BackendOriginVersion>> origins;
123 auto persistentBackend = it.second;
124 for (
auto &origin: persistentBackend->getOrigins()) {
125 origins[origin->value()].emplace_back(it.second, origin);
130 for (
auto &origin_pair: origins) {
131 auto &v = origin_pair.second;
132 if (v.size() < 2)
continue;
134 std::string_view maxVersion;
135 for (
auto &version: v) {
136 if (!maxVersion.empty() && version.second->version() > maxVersion) {
137 maxVersion = version.second->version();
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());
155 for (
auto &origin_pair: origins) {
158 std::vector<std::shared_ptr<NamedBackend>> included;
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()) {
168 if (included.empty())
continue;
171 auto &persistedBackend = origin_pair.second.begin()->first;
172 auto transaction =
edb_->createTransaction(
177 persistedBackend->batchOrigin(origin_pair.first, [&](
const TripleContainerPtr &triples) {
178 transaction->commit(triples);
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(),
193 persistedBackend.second->batch([&](
const TripleContainerPtr &triples) { transaction->commit(triples); });
197 void KnowledgeBase::initVocabulary() {
198 auto v_s = std::make_shared<Variable>(
"?s");
199 auto v_o = std::make_shared<Variable>(
"?o");
202 auto backend = it.second;
205 for (
auto &origin: backend->getOrigins()) {
237 std::vector<semweb::PropertyPtr> reifiedProperties;
238 backend->count([
this, &reifiedProperties](std::string_view resource, uint64_t count) {
240 auto reifiedProperty =
vocabulary_->getDefinedReification(resource);
241 if (reifiedProperty) reifiedProperties.push_back(reifiedProperty);
244 for (
auto &p: reifiedProperties) {
253 if (propertyAtom.get() ==
rdf::type.get()) {
273 vocabulary_->increaseFrequency(propertyAtom->stringForm());
299 for (
const auto &pair: prefixesList.value()) {
302 if (!alias.empty() && !uri.empty()) {
305 KB_WARN(
"Invalid entry in semantic-web::prefixes, 'alias' and 'uri' must be defined.");
314 for (
const auto &pair: backendList.value()) {
318 KB_ERROR(
"configuration has no 'backends' key.");
325 for (
const auto &pair: reasonerList.value()) {
327 auto definedReasoner = reasonerManager_->loadPlugin(pair.second);
329 auto reasonerBackend = std::dynamic_pointer_cast<Storage>(definedReasoner->value());
330 if (reasonerBackend) {
331 backendManager_->addPlugin(definedReasoner->name(), definedReasoner->language(), reasonerBackend);
336 KB_ERROR(
"configuration has no 'reasoner' key.");
341 for (
auto &ontoPath: {
"owl/rdf-schema.xml",
"owl/owl.rdf"}) {
346 static void do_startReasoner(
const std::shared_ptr<DataDrivenReasoner> &reasoner) {
356 std::vector<std::string_view> failedToStartReasoner;
359 { do_startReasoner(pair.second); },
360 { failedToStartReasoner.push_back(pair.first); });
363 for (
auto &reasonerName: failedToStartReasoner) {
376 if (queryable.empty()) {
377 KB_WARN(
"No queryable backends available.");
380 return queryable.begin()->second;
389 auto pipeline = std::make_shared<QueryPipeline>(shared_from_this(), conjunctiveQuery);
393 auto out = std::make_shared<AnswerBuffer_WithReference>(pipeline);
395 pipeline->stopBuffering();
400 auto pipeline = std::make_shared<QueryPipeline>(shared_from_this(), phi, ctx);
401 auto out = std::make_shared<AnswerBuffer_WithReference>(pipeline);
403 pipeline->stopBuffering();
417 auto transaction =
edb_->createTransaction(
422 if (transaction->commit(triple)) {
424 std::vector<TriplePtr> triples;
425 triples.emplace_back(tripleCopy);
426 auto container = std::make_shared<ProxyTripleContainer>(triples);
436 auto transaction =
edb_->createTransaction(
441 if (transaction->commit(triples)) {
443 for (
auto &triple: *triples) {
455 auto transaction =
edb_->createTransaction(
460 if (transaction->commit(triple)) {
462 std::vector<TriplePtr> triples;
463 triples.emplace_back(tripleCopy);
464 auto container = std::make_shared<ProxyTripleContainer>(triples);
474 auto transaction =
edb_->createTransaction(
479 if (transaction->commit(triples)) {
489 return insertAll(std::make_shared<ProxyTripleContainer>(&triples));
493 return removeAll(std::make_shared<ProxyTripleContainer>(&triples));
497 return edb_->removeAllWithOrigin(origin);
501 if (!triple.
graph())
return {};
504 if (definedBackend_withID)
return definedBackend_withID;
507 if (definedReasoner) {
508 auto reasonerBackend =
reasonerManager_->getReasonerStorage(definedReasoner);
509 if (reasonerBackend) {
511 auto &definedBackend_ofReasoner = it.second;
512 if (definedBackend_ofReasoner->value() == reasonerBackend) {
513 return definedBackend_ofReasoner;
524 if (!dataSourcesList)
return;
526 for (
const auto &pair: dataSourcesList.value()) {
527 auto &subtree = pair.second;
530 KB_ERROR(
"Failed to create data source \"{}\".", pair.first);
535 if (transformationConfig) {
537 KB_ERROR(
"Transformations can only be applied on ontology data sources.");
540 auto ontology = std::static_pointer_cast<OntologySource>(dataSource);
543 auto transformed = std::make_shared<TransformedOntology>(
URI(ontology->uri()), ontology->format());
545 transformed->storage()->
insertAll(triples);
552 KB_ERROR(
"Failed to load data source from \"{}\".", dataSource->uri());
558 switch (source->dataSourceType()) {
568 const std::shared_ptr<NamedBackend> &definedBackend, std::string_view origin)
const {
570 auto runtimeVersion = definedBackend->value()->getVersionOfOrigin(origin);
571 if (runtimeVersion)
return runtimeVersion;
573 auto persistentBackend =
backendManager_->persistent().find(definedBackend->name());
575 return persistentBackend->second->getVersionOfOrigin(origin);
580 std::vector<std::shared_ptr<NamedBackend>>
582 std::vector<std::shared_ptr<NamedBackend>> backendsToLoad;
586 auto definedBackend = it.second;
588 if (currentVersion.has_value()) {
589 if (currentVersion.value() != newVersion) {
590 backendsToLoad.emplace_back(it.second);
591 definedBackend->value()->removeAllWithOrigin(origin);
594 backendsToLoad.emplace_back(it.second);
597 return backendsToLoad;
601 std::string_view newVersion) {
604 it.second->value()->setVersionOfOrigin(origin, newVersion);
607 auto persistentBackend = it.second;
608 persistentBackend->setVersionOfOrigin(origin, newVersion);
612 if (source->parentOrigin().has_value()) {
613 vocabulary_->importHierarchy()->addDirectImport(source->parentOrigin().value(), origin);
626 auto backendsToLoad =
prepareLoad(source->origin(), newVersion);
627 if (backendsToLoad.empty()) {
629 KB_DEBUG(
"Ontology at \"{}\" already loaded.", uri);
633 auto result = source->load([
this, &backendsToLoad](
const TripleContainerPtr &triples) {
634 auto transaction =
edb_->createTransaction(
639 transaction->commit(triples);
642 KB_WARN(
"Failed to load ontology \"{}\".", uri);
645 finishLoad(source, source->origin(), newVersion);
647 for (
auto &imported: source->imports()) {
648 auto importedSource = std::make_shared<OntologyFile>(
vocabulary_,
URI(imported), source->format());
650 KB_WARN(
"Failed to load imported ontology \"{}\".", imported);
659 bool hasHandler =
false;
660 bool allSucceeded =
true;
663 auto backend = kg_pair.second->value();
664 if (backend->hasDataHandler(source)) {
665 if (!backend->loadDataSource(source)) {
666 allSucceeded =
false;
667 KB_WARN(
"backend '{}' failed to load data source '{}'", kg_pair.first, source->uri());
674 KB_WARN(
"no data handler for data source format '{}'", source->format());
677 return hasHandler && allSucceeded;
681 vocabulary_->importHierarchy()->setDefaultGraph(origin);
684 static std::shared_ptr<KnowledgeBase> makeKB1() {
688 static std::shared_ptr<KnowledgeBase> makeKB2(std::string_view settingsFile) {
692 static std::shared_ptr<KnowledgeBase> makeKB3(
const boost::property_tree::ptree &settingsTree) {
708 using ListAction = bool (
KnowledgeBase::*)(
const std::vector<TriplePtr> &);
713 class_<KnowledgeBase, std::shared_ptr<KnowledgeBase>, boost::noncopyable>
714 (
"KnowledgeBase", no_init)
716 .def(
"__init__", make_constructor(&makeKB1))
717 .def(
"__init__", make_constructor(&makeKB2))
718 .def(
"__init__", make_constructor(&makeKB3))
#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)
#define KB_LOGGED_TRY_CATCH(name, type, goal)
static std::string getVersionFromURI(const std::string &uriString)
static std::shared_ptr< DataSource > create(const VocabularyPtr &vocabulary, const boost::property_tree::ptree &config)
static std::shared_ptr< IRIAtom > Tabled(std::string_view stringForm)
static constexpr std::string_view ORIGIN_USER
static constexpr std::string_view ORIGIN_SYSTEM
bool loadNonOntologySource(const DataSourcePtr &source) const
void synchronizeObservers()
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
void addToVocabulary(const TriplePtr &triple)
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
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)
void synchronizeBackends()
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
virtual std::string_view predicate() const =0
static std::string resolve(const std::string_view &uriString)
const IRIAtomPtr inverseOf
void createType< Vocabulary >()
void createType< KnowledgeBase >()
void createType< GraphQuery >()
const IRIAtomPtr subPropertyOf
const IRIAtomPtr subClassOf
TripleTemplate< std::string > TripleCopy
std::shared_ptr< TripleContainer > TripleContainerPtr
std::shared_ptr< VersionedOrigin > VersionedOriginPtr
std::shared_ptr< Observer > ObserverPtr
std::shared_ptr< const Bindings > BindingsPtr
std::shared_ptr< Formula > FormulaPtr
std::shared_ptr< ConjunctiveQuery > ConjunctiveQueryPtr
std::shared_ptr< TokenBuffer > TokenBufferPtr
std::function< void(const BindingsPtr &)> BindingsHandler
std::shared_ptr< const QueryContext > QueryContextPtr
std::shared_ptr< GraphQuery > GraphQueryPtr
std::shared_ptr< QueryableStorage > QueryableBackendPtr
std::shared_ptr< DataSource > DataSourcePtr
std::shared_ptr< FirstOrderLiteral > FirstOrderLiteralPtr