knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
MongoTriplePattern.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 "knowrob/storage/mongo/MongoTriplePattern.h"
7 #include "knowrob/storage/mongo/MongoTerm.h"
8 #include "knowrob/storage/mongo/Pipeline.h"
9 
10 using namespace knowrob;
11 using namespace knowrob::mongo;
12 
13 #define MONGO_OPERATOR_LTE "$lte"
14 #define MONGO_OPERATOR_GTE "$gte"
15 #define MONGO_OPERATOR_LT "$lt"
16 #define MONGO_OPERATOR_GT "$gt"
17 #define MONGO_OPERATOR_NEQ "$ne"
18 
20  const TriplePattern &tripleExpression,
21  bool b_isTaxonomicProperty,
22  const std::shared_ptr<ImportHierarchy> &importHierarchy)
23  : document_(create(tripleExpression, b_isTaxonomicProperty, importHierarchy)) {
24 }
25 
27  const TriplePattern &tripleExpression,
28  bool b_isTaxonomicProperty,
29  const std::shared_ptr<ImportHierarchy> &importHierarchy) {
30  auto selectorDoc = bson_new();
31  append(selectorDoc, tripleExpression, b_isTaxonomicProperty, importHierarchy);
32  return selectorDoc;
33 }
34 
35 void MongoTriplePattern::append(bson_t *selectorDoc,
36  const TriplePattern &tripleExpression,
37  bool b_isTaxonomicProperty,
38  const std::shared_ptr<ImportHierarchy> &importHierarchy) {
39  // "s"" field
40  MongoTerm::append(selectorDoc,
41  "s", tripleExpression.subjectTerm());
42  // "p" field
43  MongoTerm::append(selectorDoc,
44  (b_isTaxonomicProperty ? "p" : "p*"),
45  tripleExpression.propertyTerm());
46  // "o" field
47  const char *objectOperator = getOperatorString(tripleExpression.objectOperator());
48  MongoTerm::append(selectorDoc,
49  (b_isTaxonomicProperty ? "o*" : "o"),
50  tripleExpression.objectTerm(),
51  objectOperator);
52  // "g" field
53  appendGraphSelector(selectorDoc, tripleExpression, importHierarchy);
54  // epistemic fields
55  appendEpistemicSelector(selectorDoc, tripleExpression);
56  // temporal fields
57  appendTimeSelector(selectorDoc, tripleExpression);
58 }
59 
60 void MongoTriplePattern::appendGraphSelector(bson_t *selectorDoc,
61  const TriplePattern &tripleExpression,
62  const std::shared_ptr<ImportHierarchy> &importHierarchy) {
63  auto &gt = tripleExpression.graphTerm();
64  if (!gt) return;
65 
66  if (gt->termType() == TermType::ATOMIC) {
67  auto graphString = gt.grounded();
68  if (graphString->stringForm() == ImportHierarchy::ORIGIN_ANY || graphString->stringForm() == "*")
69  return;
70 
71  std::vector<TermPtr> childrenNames;
72  for (auto &child: importHierarchy->getImports(graphString->stringForm())) {
73  childrenNames.push_back(Atom::Tabled(child->name()));
74  }
75  if (childrenNames.empty()) {
76  MongoTerm::append(selectorDoc, "graph", graphString);
77  } else {
78  childrenNames.push_back(graphString);
79  MongoTerm::append(selectorDoc, "graph", childrenNames, "$in");
80  }
81  }
82  /*
83  else if (gt->termType() == TermType::FUNCTION) {
84  auto fn = (Function*) gt.get();
85  if (*fn->functor() == *ListTerm::listFunctor()) {
86  aggregation::appendArrayQuery(selectorDoc, "graph", fn->arguments(), "$in");
87  } else {
88  KB_WARN("graph term {} has unexpected function type", *gt);
89  }
90  }
91  */
92  else {
93  KB_WARN("graph term {} has unexpected type", *gt);
94  }
95 }
96 
97 void MongoTriplePattern::appendEpistemicSelector(bson_t *selectorDoc, const TriplePattern &tripleExpression) {
98  auto &ct = tripleExpression.confidenceTerm();
99  auto &at = tripleExpression.perspectiveTerm();
100  auto &u = tripleExpression.isUncertainTerm();
101 
102  if (!((u.has_grounding() && u.grounded()->asBoolean()) || u.has_variable())) {
103  // note: null value of "uncertain" field is seen as value "false"
105  selectorDoc,
106  "uncertain",
108  nullptr,
109  true);
110  }
111 
112  if (at) {
113  if (at->termType() == TermType::ATOMIC) {
115  selectorDoc,
116  "agent",
117  *at,
118  nullptr,
119  false);
120  } else {
121  KB_WARN("agent term {} has unexpected type", *at);
122  }
123  } else {
124  // make sure agent field is undefined: { agent: { $exists: false } }
125  // note: null value of agent field is seen as "self", i.e. the agent running the knowledge base
126  bson_t agentDoc;
127  BSON_APPEND_DOCUMENT_BEGIN(selectorDoc, "agent", &agentDoc);
128  BSON_APPEND_BOOL(&agentDoc, "$exists", false);
129  bson_append_document_end(selectorDoc, &agentDoc);
130  }
131 
132  if (ct) {
133  if (ct->termType() == TermType::ATOMIC) {
134  // note: null value of confidence is seen as larger than the requested threshold
136  selectorDoc,
137  "confidence",
138  *ct,
140  true);
141  } else {
142  KB_WARN("confidence term {} has unexpected type", *ct);
143  }
144  }
145 }
146 
147 void MongoTriplePattern::appendTimeSelector(bson_t *selectorDoc, const TriplePattern &tripleExpression) {
148  static const bool allowNullValues = true;
149  static auto b_occasional = std::make_shared<Integer>(static_cast<int32_t>(true));
150  static auto b_always = std::make_shared<Integer>(static_cast<int32_t>(false));
151  auto bt = &tripleExpression.beginTerm();
152  auto et = &tripleExpression.endTerm();
153  auto &o = tripleExpression.isOccasionalTerm();
154 
155  if (!((o.has_grounding() && o.grounded()->asBoolean()) || o.has_variable())) {
156  // note: null value of "occasional" field is seen as value "false"
158  selectorDoc,
159  "occasional",
161  nullptr,
162  true);
163  } else {
164  auto swap = bt;
165  bt = et;
166  et = swap;
167  }
168 
169  if (bt->has_grounding()) {
171  selectorDoc,
172  "scope.time.since",
173  bt->get(),
175  allowNullValues);
176  }
177  if (et->has_grounding()) {
179  selectorDoc,
180  "scope.time.until",
181  et->get(),
183  allowNullValues);
184  }
185 }
186 
188  switch (operatorType) {
189  case FilterType::EQ:
190  return nullptr;
191  case FilterType::NEQ:
192  return MONGO_OPERATOR_NEQ;
193  case FilterType::LEQ:
194  return MONGO_OPERATOR_LTE;
195  case FilterType::GEQ:
196  return MONGO_OPERATOR_GTE;
197  case FilterType::LT:
198  return MONGO_OPERATOR_LT;
199  case FilterType::GT:
200  return MONGO_OPERATOR_GT;
201  }
202  return nullptr;
203 }
204 
205 static inline void appendSetVariable(bson_t *doc, std::string_view varName, std::string_view newValue) {
206  const auto varKey = MongoTerm::variableKey(varName);
207  const auto varValue = std::string("$") + varKey;
208  bson_t condDoc, condArray, notOperator, notArray;
209  // Only conditionally apply new value in case it has not been grounded before.
210  // varKey: {$cond: [ { $not: [ varValue ] }, newValue, varValue ]}
211  BSON_APPEND_DOCUMENT_BEGIN(doc, varKey.c_str(), &condDoc);
212  BSON_APPEND_ARRAY_BEGIN(&condDoc, "$cond", &condArray);
213  {
214  BSON_APPEND_DOCUMENT_BEGIN(&condArray, "0", &notOperator);
215  BSON_APPEND_ARRAY_BEGIN(&notOperator, "$not", &notArray);
216  BSON_APPEND_UTF8(&notArray, "0", varValue.c_str());
217  bson_append_array_end(&notOperator, &notArray);
218  bson_append_document_end(&condArray, &notOperator);
219 
220  BSON_APPEND_UTF8(&condArray, "1", newValue.data());
221  BSON_APPEND_UTF8(&condArray, "2", varValue.c_str());
222  }
223  bson_append_array_end(&condDoc, &condArray);
224  bson_append_document_end(doc, &condDoc);
225 }
226 
227 static inline void appendMatchVariable(bson_t *doc,
228  std::string_view fieldValue,
229  std::string_view varName,
230  const TripleLookupData &lookupData) {
231  const auto varKey = MongoTerm::variableKey(varName);
232  const auto varLetValue = std::string("$$") + varKey;
233  const auto matchOperator = (fieldValue.back() == '*' ? "$in" : "$eq");
234  bson_t exprDoc, orArr, notDoc, notArr, matchDoc, matchArr;
235 
236  BSON_APPEND_DOCUMENT_BEGIN(doc, "$expr", &exprDoc);
237 
238  if (lookupData.knownGroundedVariables.count(varName) > 0) {
239  // variable is known to have a grounding in the v_VARS field
240  // {$expr: { matchOperator: [varLetValue, fieldValue] } }
241  BSON_APPEND_ARRAY_BEGIN(&exprDoc, matchOperator, &matchArr);
242  BSON_APPEND_UTF8(&matchArr, "0", varLetValue.c_str());
243  BSON_APPEND_UTF8(&matchArr, "1", fieldValue.data());
244  bson_append_array_end(&exprDoc, &matchArr);
245  } else {
246  // {$expr: {$or: [ { $not: [ varLetValue ] }, { matchOperator: [varLetValue, fieldValue] } ]}}
247  BSON_APPEND_ARRAY_BEGIN(&exprDoc, "$or", &orArr);
248 
249  // { $not: [ varLetValue ] }
250  BSON_APPEND_DOCUMENT_BEGIN(&orArr, "0", &notDoc);
251  BSON_APPEND_ARRAY_BEGIN(&notDoc, "$not", &notArr);
252  BSON_APPEND_UTF8(&notArr, "0", varLetValue.c_str());
253  bson_append_array_end(&notDoc, &notArr);
254  bson_append_document_end(&orArr, &notDoc);
255 
256  // { matchOperator: [varLetValue, fieldValue] }
257  BSON_APPEND_DOCUMENT_BEGIN(&orArr, "1", &matchDoc);
258  BSON_APPEND_ARRAY_BEGIN(&matchDoc, matchOperator, &matchArr);
259  BSON_APPEND_UTF8(&matchArr, "0", varLetValue.c_str());
260  BSON_APPEND_UTF8(&matchArr, "1", fieldValue.data());
261  bson_append_array_end(&matchDoc, &matchArr);
262  bson_append_document_end(&orArr, &matchDoc);
263 
264  bson_append_array_end(&exprDoc, &orArr);
265  }
266  bson_append_document_end(doc, &exprDoc);
267 }
268 
270  const TriplePattern &expr,
271  const std::set<std::string_view> &knownGroundedVariables) {
272  std::list<std::pair<const char *, Variable *>> varList;
273 
274  // the object can be specified as a triple (Value, Operator, ActualValue) such that
275  // a value constraint is given plus a variable where the actual value of the triple should be stored.
276  TermPtr objectVar = expr.objectTerm();
277  if (objectVar && !objectVar->isVariable() && expr.objectVariable()) {
278  objectVar = expr.objectVariable();
279  }
280 
281  for (auto &it: {
282  std::make_pair("$next.s", expr.subjectTerm()),
283  std::make_pair("$next.p", expr.propertyTerm()),
284  std::make_pair("$next.o", objectVar),
285  std::make_pair("$next.graph", expr.graphTerm().get()),
286  std::make_pair("$next.confidence", expr.confidenceTerm().get()),
287  std::make_pair("$next.agent", expr.perspectiveTerm().get()),
288  std::make_pair("$next.scope.time.since", expr.beginTerm().get()),
289  std::make_pair("$next.scope.time.until", expr.endTerm().get()),
290  std::make_pair("$next.uncertain", expr.isUncertainTerm().get()),
291  std::make_pair("$next.occasional", expr.isOccasionalTerm().get())
292  }) {
293  if (!it.second || it.second->termType() != TermType::VARIABLE) continue;
294  auto var = (Variable *) it.second.get();
295  // skip variables that were instantiated in previous steps
296  if (knownGroundedVariables.count(var->name()) > 0) continue;
297  varList.emplace_back(it.first, var);
298  }
299 
300  if (!varList.empty()) {
301  auto setVariables = pipeline.appendStageBegin("$set");
302  for (auto &it: varList) {
303  appendSetVariable(setVariables, it.second->name(), it.first);
304  }
305  pipeline.appendStageEnd(setVariables);
306  }
307 }
308 
309 static void nonTransitiveLookup(
310  Pipeline &pipeline,
311  const TripleStore &tripleStore,
312  const TripleLookupData &lookupData,
313  const semweb::PropertyPtr &definedProperty) {
314  bool b_isTaxonomicProperty = (definedProperty &&
315  tripleStore.vocabulary->isTaxonomicProperty(definedProperty->iri()));
316  char arrIndexStr[16];
317  const char *arrIndexKey;
318  uint32_t arrIndex;
319 
320  bool b_skipInputGroundings = false;
321  if (lookupData.expr->numVariables() == 0) {
322  // the triple expression has no variables
323  b_skipInputGroundings = true;
324  } else if (!lookupData.mayHasMoreGroundings) {
325  // all possible previous instantiations are known and stored in lookupData.knownGroundedVariables.
326  b_skipInputGroundings = true;
327  for (auto &exprTerm: {
328  lookupData.expr->subjectTerm(),
329  lookupData.expr->propertyTerm(),
330  lookupData.expr->objectTerm()
331  }) {
332  if (exprTerm->termType() != TermType::VARIABLE) continue;
333  auto var = (Variable *) exprTerm.get();
334  // skip if this variable cannot have a runtime grounding
335  if (lookupData.knownGroundedVariables.count(var->name()) > 0) {
336  // the expression contains a variable that is known to have received a grounding before
337  b_skipInputGroundings = false;
338  break;
339  }
340  }
341  }
342 
343  // filter out documents that do not match the triple pattern. this is done using $match or $lookup operators.
344  // first lookup matching documents and store them in the 'next' field
345  bson_t lookupArray, letDoc;
346  auto lookupStage = pipeline.appendStageBegin("$lookup");
347  BSON_APPEND_UTF8(lookupStage, "from", tripleStore.tripleCollection->name().data());
348  BSON_APPEND_UTF8(lookupStage, "as", "next");
349  if (!b_skipInputGroundings) {
350  // pass "v_VARS" field to lookup pipeline
351  BSON_APPEND_DOCUMENT_BEGIN(lookupStage, "let", &letDoc);
352  if (pipeline.isNested()) {
353  // pass from outer "let" document
354  BSON_APPEND_UTF8(&letDoc, "v_VARS", "$$v_VARS");
355  } else {
356  BSON_APPEND_UTF8(&letDoc, "v_VARS", "$v_VARS");
357  }
358  bson_append_document_end(lookupStage, &letDoc);
359  }
360  BSON_APPEND_ARRAY_BEGIN(lookupStage, "pipeline", &lookupArray);
361  {
362  Pipeline lookupPipeline(&lookupArray);
363 
364  auto matchStage = lookupPipeline.appendStageBegin("$match");
365  if (b_skipInputGroundings) {
366  MongoTriplePattern::append(matchStage, *lookupData.expr, b_isTaxonomicProperty,
367  tripleStore.vocabulary->importHierarchy());
368  } else {
369  // need to match with potential groundings of variables from previous steps these are stored in the "v_VARS" field.
370  bson_t andArray, tripleDoc, variablesDoc;
371  BSON_APPEND_ARRAY_BEGIN(matchStage, "$and", &andArray);
372  {
373  BSON_APPEND_DOCUMENT_BEGIN(&andArray, "0", &tripleDoc);
374  MongoTriplePattern::append(&tripleDoc, *lookupData.expr, b_isTaxonomicProperty,
375  tripleStore.vocabulary->importHierarchy());
376  bson_append_document_end(&andArray, &tripleDoc);
377 
378  // match triple values with previously grounded variables
379  arrIndex = 1;
380  for (auto &it: {
381  std::make_pair("$s", lookupData.expr->subjectTerm()),
382  std::make_pair(b_isTaxonomicProperty ? "$p" : "$p*", lookupData.expr->propertyTerm()),
383  std::make_pair(b_isTaxonomicProperty ? "$o*" : "$o", lookupData.expr->objectTerm())
384  }) {
385  if (it.second->termType() != TermType::VARIABLE) continue;
386  auto var = (Variable *) it.second.get();
387  // skip if this variable cannot have a runtime grounding
388  if (!lookupData.mayHasMoreGroundings &&
389  lookupData.knownGroundedVariables.count(var->name()) == 0)
390  continue;
391 
392  bson_uint32_to_string(arrIndex++,
393  &arrIndexKey, arrIndexStr, sizeof arrIndexStr);
394  BSON_APPEND_DOCUMENT_BEGIN(&andArray, arrIndexKey, &variablesDoc);
395  appendMatchVariable(&variablesDoc, it.first, var->name(), lookupData);
396  bson_append_document_end(&andArray, &variablesDoc);
397  }
398  }
399  bson_append_array_end(matchStage, &andArray);
400  }
401  lookupPipeline.appendStageEnd(matchStage);
402  // { $limit: maxNumOfTriples }
403  if (lookupData.maxNumOfTriples > 0) lookupPipeline.limit(lookupData.maxNumOfTriples);
404  }
405  bson_append_array_end(lookupStage, &lookupArray);
406  pipeline.appendStageEnd(lookupStage);
407 
408  // at this point the 'next' field holds an array of matching documents, if any.
409  if (lookupData.expr->isNegated()) {
410  // following closed-world assumption succeed if no solutions are found
411  pipeline.matchEmptyArray("next");
412  } else {
413  // Unwind, and set preserveEmpty=true if lookupData.expr->isOptional().
414  pipeline.unwind("$next", lookupData.expr->isOptional());
415  // project new variable groundings
416  MongoTriplePattern::setTripleVariables(pipeline, *lookupData.expr, lookupData.knownGroundedVariables);
417  }
418 
419  // finally, remove next field: { $unset: "next" }
420  pipeline.unset("next");
421 }
422 
423 static void transitiveLookup(
424  Pipeline &pipeline,
425  const TripleStore &tripleStore,
426  const TripleLookupData &lookupData,
427  const semweb::PropertyPtr &definedProperty) {
428  bool b_isTaxonomicProperty = (definedProperty &&
429  tripleStore.vocabulary->isTaxonomicProperty(definedProperty->iri()));
430  // start with object in case it is known to be grounded before at runtime
431  bool b_objectIsKnownGrounded = lookupData.expr->objectTerm()->isVariable() &&
432  lookupData.knownGroundedVariables.count(
433  std::static_pointer_cast<Variable>(lookupData.expr->objectTerm())->name()) >
434  0;
435  bool b_startWithSubject = lookupData.expr->subjectTerm()->isGround() || !b_objectIsKnownGrounded;
436 
437  auto startTerm = (b_startWithSubject ?
438  lookupData.expr->subjectTerm() : lookupData.expr->objectTerm());
439  auto endTerm = (b_startWithSubject ?
440  lookupData.expr->objectTerm() : lookupData.expr->subjectTerm());
441 
442  // recursive lookup
443  bson_t restrictSearchDoc;
444  auto lookupStage = pipeline.appendStageBegin("$graphLookup");
445  BSON_APPEND_UTF8(lookupStage, "from", tripleStore.tripleCollection->name().data());
446  if (startTerm->termType() == TermType::ATOMIC) {
447  auto startString = (Atomic *) startTerm.get();
448  BSON_APPEND_UTF8(lookupStage, "startWith", startString->stringForm().data());
449  } else if (startTerm->termType() == TermType::VARIABLE) {
450  auto startVariable = (Variable *) startTerm.get();
451  auto startValue = std::string("$") + MongoTerm::variableKey(startVariable->name());
452  BSON_APPEND_UTF8(lookupStage, "startWith", startValue.c_str());
453  } else {
454  KB_WARN("Ignoring term {} with invalid type for graph lookup.", *startTerm);
455  }
456  BSON_APPEND_UTF8(lookupStage, "connectToField", b_startWithSubject ? "s" : "o");
457  BSON_APPEND_UTF8(lookupStage, "connectFromField", b_startWithSubject ? "o" : "s");
458  BSON_APPEND_UTF8(lookupStage, "as", "t_paths");
459  BSON_APPEND_UTF8(lookupStage, "depthField", "depth");
460  /* { restrictSearchWithMatch: { p*: Query_p, ... }" */
461  BSON_APPEND_DOCUMENT_BEGIN(lookupStage, "restrictSearchWithMatch", &restrictSearchDoc);
462  {
463  MongoTerm::append(&restrictSearchDoc,
464  (b_isTaxonomicProperty ? "p" : "p*"),
465  lookupData.expr->propertyTerm());
466  MongoTriplePattern::appendGraphSelector(&restrictSearchDoc, *lookupData.expr,
467  tripleStore.vocabulary->importHierarchy());
468  MongoTriplePattern::appendEpistemicSelector(&restrictSearchDoc, *lookupData.expr);
469  MongoTriplePattern::appendTimeSelector(&restrictSearchDoc, *lookupData.expr);
470  }
471  bson_append_document_end(lookupStage, &restrictSearchDoc);
472  pipeline.appendStageEnd(lookupStage);
473 
474  // $graphLookup does not ensure order, so we need to order by recursion depth in a separate step
475  // t_sorted = { $sortArray: { input: "$t_paths", sort: { depth: 1 } } }
476  bson_t setSortedDoc, sortArrayDoc, sortByDoc;
477  auto setSortedStage = pipeline.appendStageBegin("$set");
478  BSON_APPEND_DOCUMENT_BEGIN(setSortedStage, "t_sorted", &setSortedDoc);
479  BSON_APPEND_DOCUMENT_BEGIN(&setSortedDoc, "$sortArray", &sortArrayDoc);
480  BSON_APPEND_UTF8(&sortArrayDoc, "input", "$t_paths");
481  BSON_APPEND_DOCUMENT_BEGIN(&sortArrayDoc, "$sortArray", &sortByDoc);
482  BSON_APPEND_INT32(&sortByDoc, "depth", 1);
483  bson_append_document_end(&sortArrayDoc, &sortByDoc);
484  bson_append_document_end(&setSortedDoc, &sortArrayDoc);
485  bson_append_document_end(setSortedStage, &setSortedDoc);
486  pipeline.appendStageEnd(setSortedStage);
487 
488  // { $set: { next: "$t_sorted" } }
489  auto setNext = pipeline.appendStageBegin("$set");
490  BSON_APPEND_UTF8(setNext, "next", "$t_sorted");
491  pipeline.appendStageEnd(setNext);
492 
493  // { $set: { start: { $arrayElemAt: ["$next", 0] } } }
494  bson_t setStartOperation, setStartArr;
495  auto setStart = pipeline.appendStageBegin("$set");
496  BSON_APPEND_DOCUMENT_BEGIN(setStart, "start", &setStartOperation);
497  BSON_APPEND_ARRAY_BEGIN(&setStartOperation, "$arrayElemAt", &setStartArr);
498  BSON_APPEND_UTF8(&setStartArr, "0", "$next");
499  BSON_APPEND_INT32(&setStartArr, "1", 0);
500  bson_append_array_end(&setStartOperation, &setStartArr);
501  bson_append_document_end(setStart, &setStartOperation);
502  pipeline.appendStageEnd(setStart);
503 
504  // { $unset: "t_paths" }, { $unset: "t_sorted" }
505  pipeline.unset("t_paths");
506  pipeline.unset("t_sorted");
507 
508  // iterate over results: { $unwind: "$next" }
509  pipeline.unwind("$next");
510 
511  // graph lookup uses "s" or "o" as start for recursive lookup but ignores the other.
512  // thus a matching must be performed for the results.
513  auto matchEnd = pipeline.appendStageBegin("$match");
514  if (endTerm->termType() == TermType::VARIABLE) {
515  bson_t exprDoc, orArr, ungroundedMatch, groundedMatch, notArray;
516  BSON_APPEND_DOCUMENT_BEGIN(matchEnd, "$expr", &exprDoc);
517  BSON_APPEND_ARRAY_BEGIN(&exprDoc, "$or", &orArr);
518 
519  BSON_APPEND_DOCUMENT_BEGIN(&orArr, "0", &ungroundedMatch);
520  BSON_APPEND_ARRAY_BEGIN(&ungroundedMatch, "$not", &notArray);
521  auto varKey = MongoTerm::variableKey(std::static_pointer_cast<Variable>(endTerm)->name());
522  BSON_APPEND_UTF8(&notArray, "0", (std::string("$") + varKey).c_str());
523  bson_append_array_end(&ungroundedMatch, &notArray);
524  bson_append_document_end(&orArr, &ungroundedMatch);
525 
526  BSON_APPEND_DOCUMENT_BEGIN(&orArr, "1", &groundedMatch);
527  MongoTerm::append(&groundedMatch, (b_startWithSubject ? "next.o" : "next.s"), endTerm);
528  bson_append_document_end(&orArr, &groundedMatch);
529 
530  bson_append_array_end(&exprDoc, &orArr);
531  bson_append_document_end(matchEnd, &exprDoc);
532  } else {
533  MongoTerm::append(matchEnd, (b_startWithSubject ? "next.o" : "next.s"), endTerm);
534  }
535  pipeline.appendStageEnd(matchEnd);
536 
537  // project new variable groundings
538  MongoTriplePattern::setTripleVariables(pipeline, *lookupData.expr, lookupData.knownGroundedVariables);
539  // remove next field again: { $unset: "next" }
540  pipeline.unset("next");
541 }
542 
543 void mongo::lookupTriple(Pipeline &pipeline, const TripleStore &tripleStore, const TripleLookupData &lookupData) {
544  semweb::PropertyPtr definedProperty;
545  if (lookupData.expr->propertyTerm() && lookupData.expr->propertyTerm()->termType() == TermType::ATOMIC) {
546  auto propertyTerm = std::static_pointer_cast<Atomic>(lookupData.expr->propertyTerm());
547  definedProperty = tripleStore.vocabulary->getDefinedProperty(propertyTerm->stringForm());
548  }
549 
550  bool b_isTransitiveProperty = (definedProperty && definedProperty->hasFlag(
552  if (b_isTransitiveProperty)
553  transitiveLookup(pipeline, tripleStore, lookupData, definedProperty);
554  else
555  nonTransitiveLookup(pipeline, tripleStore, lookupData, definedProperty);
556 }
#define MONGO_OPERATOR_GTE
#define MONGO_OPERATOR_LT
#define MONGO_OPERATOR_NEQ
#define MONGO_OPERATOR_LTE
#define MONGO_OPERATOR_GT
#define KB_WARN
Definition: Logger.h:27
static std::shared_ptr< knowrob::Atom > Tabled(std::string_view stringForm)
Definition: Atom.cpp:40
static constexpr std::string_view ORIGIN_ANY
static std::shared_ptr< Numeric > falseAtom()
Definition: Numeric.cpp:20
auto objectOperator() const
auto & propertyTerm() const
Definition: TriplePattern.h:92
auto & subjectTerm() const
Definition: TriplePattern.h:81
auto & objectVariable() const
auto & isOccasionalTerm() const
auto & isUncertainTerm() const
auto & beginTerm() const
auto & objectTerm() const
Definition: TriplePattern.h:97
uint32_t numVariables() const override
auto & endTerm() const
auto & graphTerm() const
auto & perspectiveTerm() const
auto & confidenceTerm() const
static void append(bson_t *doc, const char *key, const TermPtr &term, const char *queryOperator=nullptr, bool matchNullValue=false, bool includeVariables=false)
Definition: MongoTerm.cpp:13
static std::string variableKey(const std::string_view &varName)
Definition: MongoTerm.cpp:127
static bson_t * create(const TriplePattern &tripleExpression, bool b_isTaxonomicProperty, const std::shared_ptr< ImportHierarchy > &importHierarchy)
MongoTriplePattern(const TriplePattern &tripleExpression, bool b_isTaxonomicProperty, const std::shared_ptr< ImportHierarchy > &importHierarchy)
static const char * getOperatorString(knowrob::FilterType operatorType)
static void appendEpistemicSelector(bson_t *selectorDoc, const TriplePattern &tripleExpression)
static void appendTimeSelector(bson_t *selectorDoc, const TriplePattern &tripleExpression)
static void append(bson_t *selectorDoc, const TriplePattern &tripleExpression, bool b_isTaxonomicProperty, const std::shared_ptr< ImportHierarchy > &importHierarchy)
static void setTripleVariables(Pipeline &pipeline, const TriplePattern &expr, const std::set< std::string_view > &knownGroundedVariables)
static void appendGraphSelector(bson_t *selectorDoc, const TriplePattern &tripleExpression, const std::shared_ptr< ImportHierarchy > &importHierarchy)
void appendStageEnd(bson_t *stage)
Definition: Pipeline.cpp:46
bson_t * appendStageBegin()
Definition: Pipeline.cpp:27
auto isNested() const
Definition: Pipeline.h:36
void matchEmptyArray(std::string_view arrayKey)
Definition: Pipeline.cpp:352
void unwind(std::string_view field, bool preserveNullAndEmptyArrays=false)
Definition: Pipeline.cpp:255
void unset(std::string_view field)
Definition: Pipeline.cpp:267
void lookupTriple(Pipeline &pipeline, const TripleStore &tripleStore, const TripleLookupData &lookupData)
VariableRule & var()
Definition: terms.cpp:91
TermRule & string()
Definition: terms.cpp:63
@ TRANSITIVE_PROPERTY
Definition: Property.h:24
std::shared_ptr< Property > PropertyPtr
Definition: Property.h:175
std::shared_ptr< Term > TermPtr
Definition: Term.h:117
std::set< std::string_view > knownGroundedVariables
std::shared_ptr< knowrob::mongo::Collection > tripleCollection
Definition: TripleStore.h:27
std::shared_ptr< knowrob::Vocabulary > vocabulary
Definition: TripleStore.h:29