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) {
271 for (
const auto &pair: prefixesList.value()) {
274 if (!alias.empty() && !uri.empty()) {
277 KB_WARN(
"Invalid entry in semantic-web::prefixes, 'alias' and 'uri' must be defined.");
286 for (
const auto &pair: backendList.value()) {
290 KB_ERROR(
"configuration has no 'backends' key.");
297 for (
const auto &pair: reasonerList.value()) {
299 auto definedReasoner = reasonerManager_->loadPlugin(pair.second);
301 auto reasonerBackend = std::dynamic_pointer_cast<Storage>(definedReasoner->value());
302 if (reasonerBackend) {
303 backendManager_->addPlugin(definedReasoner->name(), definedReasoner->language(), reasonerBackend);
308 KB_ERROR(
"configuration has no 'reasoner' key.");
313 for (
auto &ontoPath: {
"owl/rdf-schema.xml",
"owl/owl.rdf"}) {
318 static void do_startReasoner(
const std::shared_ptr<DataDrivenReasoner> &reasoner) {
328 std::vector<std::string_view> failedToStartReasoner;
331 { do_startReasoner(pair.second); },
332 { failedToStartReasoner.push_back(pair.first); });
335 for (
auto &reasonerName: failedToStartReasoner) {
348 if (queryable.empty()) {
349 KB_WARN(
"No queryable backends available.");
352 return queryable.begin()->second;
361 auto pipeline = std::make_shared<QueryPipeline>(shared_from_this(), conjunctiveQuery);
365 auto out = std::make_shared<AnswerBuffer_WithReference>(pipeline);
367 pipeline->stopBuffering();
372 auto pipeline = std::make_shared<QueryPipeline>(shared_from_this(), phi, ctx);
373 auto out = std::make_shared<AnswerBuffer_WithReference>(pipeline);
375 pipeline->stopBuffering();
389 auto transaction =
edb_->createTransaction(
394 if (transaction->commit(triple)) {
396 std::vector<TriplePtr> triples;
397 triples.emplace_back(tripleCopy);
398 auto container = std::make_shared<ProxyTripleContainer>(triples);
408 auto transaction =
edb_->createTransaction(
413 if (transaction->commit(triples)) {
423 auto transaction =
edb_->createTransaction(
428 if (transaction->commit(triple)) {
430 std::vector<TriplePtr> triples;
431 triples.emplace_back(tripleCopy);
432 auto container = std::make_shared<ProxyTripleContainer>(triples);
442 auto transaction =
edb_->createTransaction(
447 if (transaction->commit(triples)) {
457 return insertAll(std::make_shared<ProxyTripleContainer>(&triples));
461 return removeAll(std::make_shared<ProxyTripleContainer>(&triples));
465 return edb_->removeAllWithOrigin(origin);
469 if (!triple.
graph())
return {};
472 if (definedBackend_withID)
return definedBackend_withID;
475 if (definedReasoner) {
476 auto reasonerBackend =
reasonerManager_->getReasonerStorage(definedReasoner);
477 if (reasonerBackend) {
479 auto &definedBackend_ofReasoner = it.second;
480 if (definedBackend_ofReasoner->value() == reasonerBackend) {
481 return definedBackend_ofReasoner;
492 if (!dataSourcesList)
return;
494 for (
const auto &pair: dataSourcesList.value()) {
495 auto &subtree = pair.second;
498 KB_ERROR(
"Failed to create data source \"{}\".", pair.first);
503 if (transformationConfig) {
505 KB_ERROR(
"Transformations can only be applied on ontology data sources.");
508 auto ontology = std::static_pointer_cast<OntologySource>(dataSource);
511 auto transformed = std::make_shared<TransformedOntology>(
URI(ontology->uri()), ontology->format());
513 transformed->storage()->
insertAll(triples);
520 KB_ERROR(
"Failed to load data source from \"{}\".", dataSource->uri());
526 switch (source->dataSourceType()) {
536 const std::shared_ptr<NamedBackend> &definedBackend, std::string_view origin)
const {
538 auto runtimeVersion = definedBackend->value()->getVersionOfOrigin(origin);
539 if (runtimeVersion)
return runtimeVersion;
541 auto persistentBackend =
backendManager_->persistent().find(definedBackend->name());
543 return persistentBackend->second->getVersionOfOrigin(origin);
548 std::vector<std::shared_ptr<NamedBackend>>
550 std::vector<std::shared_ptr<NamedBackend>> backendsToLoad;
554 auto definedBackend = it.second;
556 if (currentVersion.has_value()) {
557 if (currentVersion.value() != newVersion) {
558 backendsToLoad.emplace_back(it.second);
559 definedBackend->value()->removeAllWithOrigin(origin);
562 backendsToLoad.emplace_back(it.second);
565 return backendsToLoad;
569 std::string_view newVersion) {
572 it.second->value()->setVersionOfOrigin(origin, newVersion);
575 auto persistentBackend = it.second;
576 persistentBackend->setVersionOfOrigin(origin, newVersion);
580 if (source->parentOrigin().has_value()) {
581 vocabulary_->importHierarchy()->addDirectImport(source->parentOrigin().value(), origin);
594 auto backendsToLoad =
prepareLoad(source->origin(), newVersion);
595 if (backendsToLoad.empty()) {
597 KB_DEBUG(
"Ontology at \"{}\" already loaded.", uri);
601 auto result = source->load([
this, &backendsToLoad](
const TripleContainerPtr &triples) {
602 auto transaction =
edb_->createTransaction(
607 transaction->commit(triples);
610 KB_WARN(
"Failed to load ontology \"{}\".", uri);
613 finishLoad(source, source->origin(), newVersion);
615 for (
auto &imported: source->imports()) {
616 auto importedSource = std::make_shared<OntologyFile>(
vocabulary_,
URI(imported), source->format());
618 KB_WARN(
"Failed to load imported ontology \"{}\".", imported);
627 bool hasHandler =
false;
628 bool allSucceeded =
true;
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());
642 KB_WARN(
"no data handler for data source format '{}'", source->format());
645 return hasHandler && allSucceeded;
649 vocabulary_->importHierarchy()->setDefaultGraph(origin);
652 static std::shared_ptr<KnowledgeBase> makeKB1() {
656 static std::shared_ptr<KnowledgeBase> makeKB2(std::string_view settingsFile) {
660 static std::shared_ptr<KnowledgeBase> makeKB3(
const boost::property_tree::ptree &settingsTree) {
676 using ListAction = bool (
KnowledgeBase::*)(
const std::vector<TriplePtr> &);
681 class_<KnowledgeBase, std::shared_ptr<KnowledgeBase>, boost::noncopyable>
682 (
"KnowledgeBase", no_init)
684 .def(
"__init__", make_constructor(&makeKB1))
685 .def(
"__init__", make_constructor(&makeKB2))
686 .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 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
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
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