@comunica/actor-optimize-query-operation-filter-pushdown 4.4.0 → 4.4.2-alpha.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
File without changes
@@ -2,8 +2,8 @@ import type { IActionOptimizeQueryOperation, IActorOptimizeQueryOperationArgs, I
2
2
  import { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';
3
3
  import type { IActorTest, TestResult } from '@comunica/core';
4
4
  import type { FragmentSelectorShape, IActionContext, IQuerySourceWrapper } from '@comunica/types';
5
+ import { AlgebraFactory, Algebra } from '@comunica/utils-algebra';
5
6
  import type * as RDF from '@rdfjs/types';
6
- import { Factory, Algebra } from 'sparqlalgebrajs';
7
7
  /**
8
8
  * A comunica Filter Pushdown Optimize Query Operation Actor.
9
9
  */
@@ -27,14 +27,17 @@ export declare class ActorOptimizeQueryOperationFilterPushdown extends ActorOpti
27
27
  * @param sources The query sources in the operation
28
28
  * @param sourceShapes A mapping of sources to selector shapes.
29
29
  * @param extensionFunctions The extension functions comunica supports.
30
+ * @param extensionFunctionsAlwaysPushdown If extension functions must always be pushed down to sources that support
31
+ * expressions, even if those sources to not explicitly declare support for
32
+ * these extension functions.
30
33
  */
31
- shouldAttemptPushDown(operation: Algebra.Filter, sources: IQuerySourceWrapper[], sourceShapes: Map<IQuerySourceWrapper, FragmentSelectorShape>, extensionFunctions?: Record<string, any>): boolean;
34
+ shouldAttemptPushDown(operation: Algebra.Filter, sources: IQuerySourceWrapper[], sourceShapes: Map<IQuerySourceWrapper, FragmentSelectorShape>, extensionFunctions?: Record<string, any>, extensionFunctionsAlwaysPushdown?: boolean): boolean;
32
35
  /**
33
36
  * Collected all sources that are defined within the given operation of children recursively.
34
37
  * @param operation An operation.
35
38
  */
36
39
  getSources(operation: Algebra.Operation): IQuerySourceWrapper[];
37
- protected getOverlappingOperations(operation: Algebra.Operation, expressionVariables: RDF.Variable[]): {
40
+ protected getOverlappingOperations(operation: Algebra.Union | Algebra.Join, expressionVariables: RDF.Variable[]): {
38
41
  fullyOverlapping: Algebra.Operation[];
39
42
  partiallyOverlapping: Algebra.Operation[];
40
43
  notOverlapping: Algebra.Operation[];
@@ -52,7 +55,7 @@ export declare class ActorOptimizeQueryOperationFilterPushdown extends ActorOpti
52
55
  * @param context The action context.
53
56
  * @return A tuple indicating if the operation was modified and the modified operation.
54
57
  */
55
- filterPushdown(expression: Algebra.Expression, expressionVariables: RDF.Variable[], operation: Algebra.Operation, factory: Factory, context: IActionContext): [boolean, Algebra.Operation];
58
+ filterPushdown(expression: Algebra.Expression, expressionVariables: RDF.Variable[], operation: Algebra.Operation, factory: AlgebraFactory, context: IActionContext): [boolean, Algebra.Operation];
56
59
  /**
57
60
  * Check if the given expression is a simple equals operation with one variable and one non-literal
58
61
  * (or literal with canonical lexical form) term that can be pushed into a pattern.
@@ -71,7 +74,7 @@ export declare class ActorOptimizeQueryOperationFilterPushdown extends ActorOpti
71
74
  * @param term An RDF term.
72
75
  * @protected
73
76
  */
74
- protected isLiteralWithCanonicalLexicalForm(term: RDF.Term): boolean;
77
+ protected isLiteralWithCanonicalLexicalForm(term: RDF.Literal): boolean;
75
78
  /**
76
79
  * Check if there is an overlap between the two given lists of variables.
77
80
  * @param varsA A list of variables.
@@ -4,9 +4,9 @@ exports.ActorOptimizeQueryOperationFilterPushdown = void 0;
4
4
  const bus_optimize_query_operation_1 = require("@comunica/bus-optimize-query-operation");
5
5
  const context_entries_1 = require("@comunica/context-entries");
6
6
  const core_1 = require("@comunica/core");
7
+ const utils_algebra_1 = require("@comunica/utils-algebra");
7
8
  const utils_query_operation_1 = require("@comunica/utils-query-operation");
8
9
  const rdf_terms_1 = require("rdf-terms");
9
- const sparqlalgebrajs_1 = require("sparqlalgebrajs");
10
10
  /**
11
11
  * A comunica Filter Pushdown Optimize Query Operation Actor.
12
12
  */
@@ -19,29 +19,22 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
19
19
  }
20
20
  async run(action) {
21
21
  const dataFactory = action.context.getSafe(context_entries_1.KeysInitQuery.dataFactory);
22
- const algebraFactory = new sparqlalgebrajs_1.Factory(dataFactory);
22
+ const algebraFactory = new utils_algebra_1.AlgebraFactory(dataFactory);
23
23
  let operation = action.operation;
24
- // eslint-disable-next-line ts/no-this-alias
25
- const self = this;
26
24
  // Split conjunctive filters into nested filters
27
25
  if (this.splitConjunctive) {
28
- operation = sparqlalgebrajs_1.Util.mapOperation(operation, {
29
- filter(op, factory) {
30
- // Split conjunctive filters into separate filters
31
- if (op.expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.OPERATOR && op.expression.operator === '&&') {
32
- self.logDebug(action.context, `Split conjunctive filter into ${op.expression.args.length} nested filters`);
33
- return {
34
- recurse: true,
35
- result: op.expression.args
36
- .reduce((operation, expression) => factory.createFilter(operation, expression), op.input),
37
- };
38
- }
39
- return {
40
- recurse: true,
41
- result: op,
42
- };
43
- },
44
- }, algebraFactory);
26
+ operation = utils_algebra_1.algebraUtils.mapOperation(operation, {
27
+ [utils_algebra_1.Algebra.Types.FILTER]: { transform: (filterOp) => {
28
+ // Split conjunctive filters into separate filters
29
+ if ((0, utils_algebra_1.isKnownSubType)(filterOp.expression, utils_algebra_1.Algebra.ExpressionTypes.OPERATOR) &&
30
+ filterOp.expression.operator === '&&') {
31
+ this.logDebug(action.context, `Split conjunctive filter into ${filterOp.expression.args.length} nested filters`);
32
+ return filterOp.expression.args
33
+ .reduce((operation, expression) => algebraFactory.createFilter(operation, expression), filterOp.input);
34
+ }
35
+ return filterOp;
36
+ } },
37
+ });
45
38
  }
46
39
  // Collect selector shapes of all operations
47
40
  const sources = this.getSources(operation);
@@ -54,52 +47,41 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
54
47
  let iterations = 0;
55
48
  while (repeat && iterations < this.maxIterations) {
56
49
  repeat = false;
57
- operation = sparqlalgebrajs_1.Util.mapOperation(operation, {
58
- filter(op, factory) {
59
- // Check if the filter must be pushed down
60
- const extensionFunctions = action.context.get(context_entries_1.KeysInitQuery.extensionFunctions);
61
- if (!self.shouldAttemptPushDown(op, sources, sourceShapes, extensionFunctions)) {
62
- return {
63
- recurse: true,
64
- result: op,
65
- };
66
- }
67
- // For all filter expressions in the operation,
68
- // we attempt to push them down as deep as possible into the algebra.
69
- const variables = (0, utils_query_operation_1.getExpressionVariables)(op.expression);
70
- const [isModified, result] = self
71
- .filterPushdown(op.expression, variables, op.input, factory, action.context);
72
- if (isModified) {
73
- repeat = true;
74
- }
75
- return {
76
- recurse: true,
77
- result,
78
- };
79
- },
50
+ operation = utils_algebra_1.algebraUtils.mapOperation(operation, {
51
+ [utils_algebra_1.Algebra.Types.FILTER]: { transform: (filterOp) => {
52
+ // Check if the filter must be pushed down
53
+ const extensionFunctions = action.context.get(context_entries_1.KeysInitQuery.extensionFunctions);
54
+ const extensionFunctionsAlwaysPushdown = action.context.get(context_entries_1.KeysInitQuery.extensionFunctionsAlwaysPushdown);
55
+ if (!this.shouldAttemptPushDown(filterOp, sources, sourceShapes, extensionFunctions, extensionFunctionsAlwaysPushdown)) {
56
+ return filterOp;
57
+ }
58
+ // For all filter expressions in the operation,
59
+ // we attempt to push them down as deep as possible into the algebra.
60
+ const variables = (0, utils_query_operation_1.getExpressionVariables)(filterOp.expression);
61
+ const [isModified, result] = this
62
+ .filterPushdown(filterOp.expression, variables, filterOp.input, algebraFactory, action.context);
63
+ if (isModified) {
64
+ repeat = true;
65
+ }
66
+ return result;
67
+ } },
80
68
  });
81
69
  iterations++;
82
70
  }
83
71
  if (iterations > 1) {
84
- self.logDebug(action.context, `Pushed down filters in ${iterations} iterations`);
72
+ this.logDebug(action.context, `Pushed down filters in ${iterations} iterations`);
85
73
  }
86
74
  // Merge nested filters into conjunctive filters
87
75
  if (this.mergeConjunctive) {
88
- operation = sparqlalgebrajs_1.Util.mapOperation(operation, {
89
- filter(op, factory) {
90
- if (op.input.type === sparqlalgebrajs_1.Algebra.types.FILTER) {
91
- const { nestedExpressions, input } = self.getNestedFilterExpressions(op);
92
- self.logDebug(action.context, `Merge ${nestedExpressions.length} nested filters into conjunctive filter`);
93
- return {
94
- recurse: true,
95
- result: factory.createFilter(input, nestedExpressions.slice(1).reduce((previous, current) => factory.createOperatorExpression('&&', [previous, current]), nestedExpressions[0])),
96
- };
97
- }
98
- return {
99
- recurse: true,
100
- result: op,
101
- };
102
- },
76
+ operation = utils_algebra_1.algebraUtils.mapOperation(operation, {
77
+ [utils_algebra_1.Algebra.Types.FILTER]: { transform: (op) => {
78
+ if (op.input.type === utils_algebra_1.Algebra.Types.FILTER) {
79
+ const { nestedExpressions, input } = this.getNestedFilterExpressions(op);
80
+ this.logDebug(action.context, `Merge ${nestedExpressions.length} nested filters into conjunctive filter`);
81
+ return algebraFactory.createFilter(input, nestedExpressions.slice(1).reduce((previous, current) => algebraFactory.createOperatorExpression('&&', [previous, current]), nestedExpressions[0]));
82
+ }
83
+ return op;
84
+ } },
103
85
  });
104
86
  }
105
87
  return { operation, context: action.context };
@@ -114,31 +96,39 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
114
96
  * @param sources The query sources in the operation
115
97
  * @param sourceShapes A mapping of sources to selector shapes.
116
98
  * @param extensionFunctions The extension functions comunica supports.
99
+ * @param extensionFunctionsAlwaysPushdown If extension functions must always be pushed down to sources that support
100
+ * expressions, even if those sources to not explicitly declare support for
101
+ * these extension functions.
117
102
  */
118
- shouldAttemptPushDown(operation, sources, sourceShapes, extensionFunctions) {
103
+ shouldAttemptPushDown(operation, sources, sourceShapes, extensionFunctions, extensionFunctionsAlwaysPushdown) {
119
104
  // Always push down if aggressive mode is enabled
120
105
  if (this.aggressivePushdown) {
121
106
  return true;
122
107
  }
123
108
  // Push down if the filter is extremely selective
124
109
  const expression = operation.expression;
125
- if (expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.OPERATOR &&
126
- expression.operator === '=' &&
127
- ((expression.args[0].expressionType === 'term' && expression.args[0].term.termType !== 'Variable' &&
128
- expression.args[1].expressionType === 'term' && expression.args[1].term.termType === 'Variable') ||
129
- (expression.args[0].expressionType === 'term' && expression.args[0].term.termType === 'Variable' &&
130
- expression.args[1].expressionType === 'term' && expression.args[1].term.termType !== 'Variable'))) {
110
+ if ((0, utils_algebra_1.isKnownSubType)(expression, utils_algebra_1.Algebra.ExpressionTypes.OPERATOR) && expression.operator === '=' &&
111
+ (((0, utils_algebra_1.isKnownSubType)(expression.args[0], utils_algebra_1.Algebra.ExpressionTypes.TERM) &&
112
+ expression.args[0].term.termType !== 'Variable' &&
113
+ (0, utils_algebra_1.isKnownSubType)(expression.args[1], utils_algebra_1.Algebra.ExpressionTypes.TERM) &&
114
+ expression.args[1].term.termType === 'Variable') ||
115
+ ((0, utils_algebra_1.isKnownSubType)(expression.args[0], utils_algebra_1.Algebra.ExpressionTypes.TERM) &&
116
+ expression.args[0].term.termType === 'Variable' &&
117
+ (0, utils_algebra_1.isKnownSubType)(expression.args[1], utils_algebra_1.Algebra.ExpressionTypes.TERM) &&
118
+ expression.args[1].term.termType !== 'Variable'))) {
131
119
  return true;
132
120
  }
133
121
  // Don't push down extension functions comunica support, but no source does
134
- if (extensionFunctions && expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.NAMED &&
122
+ if (extensionFunctions && (0, utils_algebra_1.isKnownSubType)(expression, utils_algebra_1.Algebra.ExpressionTypes.NAMED) &&
135
123
  expression.name.value in extensionFunctions &&
136
124
  // Checks if there's not a single source that supports the extension function
137
125
  !sources.some(source => (0, utils_query_operation_1.doesShapeAcceptOperation)(sourceShapes.get(source), expression))) {
138
126
  return false;
139
127
  }
140
128
  // Push down if federated and at least one accepts the filter
141
- if (sources.some(source => (0, utils_query_operation_1.doesShapeAcceptOperation)(sourceShapes.get(source), operation))) {
129
+ if (sources.some(source => (0, utils_query_operation_1.doesShapeAcceptOperation)(sourceShapes.get(source), operation, {
130
+ wildcardAcceptAllExtensionFunctions: extensionFunctionsAlwaysPushdown,
131
+ }))) {
142
132
  return true;
143
133
  }
144
134
  // Don't push down in all other cases
@@ -157,11 +147,11 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
157
147
  }
158
148
  return false;
159
149
  };
160
- sparqlalgebrajs_1.Util.recurseOperation(operation, {
161
- [sparqlalgebrajs_1.Algebra.types.PATTERN]: sourceAdder,
162
- [sparqlalgebrajs_1.Algebra.types.LINK]: sourceAdder,
163
- [sparqlalgebrajs_1.Algebra.types.NPS]: sourceAdder,
164
- [sparqlalgebrajs_1.Algebra.types.SERVICE]: sourceAdder,
150
+ utils_algebra_1.algebraUtils.visitOperation(operation, {
151
+ [utils_algebra_1.Algebra.Types.PATTERN]: { visitor: sourceAdder },
152
+ [utils_algebra_1.Algebra.Types.SERVICE]: { visitor: sourceAdder },
153
+ [utils_algebra_1.Algebra.Types.LINK]: { visitor: sourceAdder },
154
+ [utils_algebra_1.Algebra.Types.NPS]: { visitor: sourceAdder },
165
155
  });
166
156
  return [...sources];
167
157
  }
@@ -170,7 +160,7 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
170
160
  const partiallyOverlapping = [];
171
161
  const notOverlapping = [];
172
162
  for (const input of operation.input) {
173
- const inputVariables = sparqlalgebrajs_1.Util.inScopeVariables(input);
163
+ const inputVariables = utils_algebra_1.algebraUtils.inScopeVariables(input);
174
164
  if (this.variablesSubSetOf(expressionVariables, inputVariables)) {
175
165
  fullyOverlapping.push(input);
176
166
  }
@@ -206,183 +196,154 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
206
196
  return [true, factory.createUnion([])];
207
197
  }
208
198
  // Don't push down (NOT) EXISTS
209
- if (expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.EXISTENCE) {
199
+ if ((0, utils_algebra_1.isKnownOperation)(expression, utils_algebra_1.Algebra.Types.EXPRESSION, utils_algebra_1.Algebra.ExpressionTypes.EXISTENCE)) {
210
200
  return [false, factory.createFilter(operation, expression)];
211
201
  }
212
- switch (operation.type) {
213
- case sparqlalgebrajs_1.Algebra.types.EXTEND:
214
- // Pass if the variable is not part of the expression
215
- if (!this.variablesIntersect([operation.variable], expressionVariables)) {
216
- return [true, factory.createExtend(this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1], operation.variable, operation.expression)];
217
- }
202
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.EXTEND)) {
203
+ // Pass if the variable is not part of the expression
204
+ if (!this.variablesIntersect([operation.variable], expressionVariables)) {
205
+ return [true, factory.createExtend(this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1], operation.variable, operation.expression)];
206
+ }
207
+ return [false, factory.createFilter(operation, expression)];
208
+ }
209
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.FILTER)) {
210
+ // Always pass
211
+ const [isModified, result] = this
212
+ .filterPushdown(expression, expressionVariables, operation.input, factory, context);
213
+ return [isModified, factory.createFilter(result, operation.expression)];
214
+ }
215
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.JOIN)) {
216
+ // Don't push down for empty join
217
+ if (operation.input.length === 0) {
218
218
  return [false, factory.createFilter(operation, expression)];
219
- case sparqlalgebrajs_1.Algebra.types.FILTER: {
220
- // Always pass
221
- const [isModified, result] = this
222
- .filterPushdown(expression, expressionVariables, operation.input, factory, context);
223
- return [isModified, factory.createFilter(result, operation.expression)];
224
219
  }
225
- case sparqlalgebrajs_1.Algebra.types.JOIN: {
226
- // Don't push down for empty join
227
- if (operation.input.length === 0) {
228
- return [false, factory.createFilter(operation, expression)];
229
- }
230
- // Determine overlapping operations
231
- const { fullyOverlapping, partiallyOverlapping, notOverlapping, } = this.getOverlappingOperations(operation, expressionVariables);
232
- const joins = [];
233
- let isModified = false;
234
- if (fullyOverlapping.length > 0) {
235
- isModified = true;
236
- joins.push(factory.createJoin(fullyOverlapping
237
- .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));
238
- }
239
- if (partiallyOverlapping.length > 0) {
240
- joins.push(factory.createFilter(factory.createJoin(partiallyOverlapping, false), expression));
241
- }
242
- if (notOverlapping.length > 0) {
243
- joins.push(...notOverlapping);
244
- }
245
- if (joins.length > 1) {
246
- isModified = true;
247
- }
248
- if (isModified) {
249
- this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
250
- }
251
- return [isModified, joins.length === 1 ? joins[0] : factory.createJoin(joins)];
220
+ // Determine overlapping operations
221
+ const { fullyOverlapping, partiallyOverlapping, notOverlapping, } = this.getOverlappingOperations(operation, expressionVariables);
222
+ const joins = [];
223
+ let isModified = false;
224
+ if (fullyOverlapping.length > 0) {
225
+ isModified = true;
226
+ joins.push(factory.createJoin(fullyOverlapping
227
+ .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));
252
228
  }
253
- case sparqlalgebrajs_1.Algebra.types.NOP:
254
- return [true, operation];
255
- case sparqlalgebrajs_1.Algebra.types.PROJECT:
256
- // Push down if variables overlap
257
- if (this.variablesIntersect(operation.variables, expressionVariables)) {
258
- return [true, factory.createProject(this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1], operation.variables)];
259
- }
260
- // Void expression otherwise
261
- return [true, operation];
262
- case sparqlalgebrajs_1.Algebra.types.UNION: {
263
- // Determine overlapping operations
264
- const { fullyOverlapping, partiallyOverlapping, notOverlapping, } = this.getOverlappingOperations(operation, expressionVariables);
265
- const unions = [];
266
- let isModified = false;
267
- if (fullyOverlapping.length > 0) {
268
- isModified = true;
269
- unions.push(factory.createUnion(fullyOverlapping
270
- .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));
271
- }
272
- if (partiallyOverlapping.length > 0) {
273
- unions.push(factory.createFilter(factory.createUnion(partiallyOverlapping, false), expression));
274
- }
275
- if (notOverlapping.length > 0) {
276
- unions.push(...notOverlapping);
277
- }
278
- if (unions.length > 1) {
279
- isModified = true;
280
- }
281
- if (isModified) {
282
- this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
283
- }
284
- return [isModified, unions.length === 1 ? unions[0] : factory.createUnion(unions)];
229
+ if (partiallyOverlapping.length > 0) {
230
+ joins.push(factory.createFilter(factory.createJoin(partiallyOverlapping, false), expression));
285
231
  }
286
- case sparqlalgebrajs_1.Algebra.types.VALUES:
287
- // Only keep filter if it overlaps with the variables
288
- if (this.variablesIntersect(operation.variables, expressionVariables)) {
289
- return [false, factory.createFilter(operation, expression)];
290
- }
291
- return [true, operation];
292
- case sparqlalgebrajs_1.Algebra.types.LEFT_JOIN: {
293
- if (this.pushIntoLeftJoins) {
294
- const rightVariables = sparqlalgebrajs_1.Util.inScopeVariables(operation.input[1]);
295
- if (!this.variablesIntersect(expressionVariables, rightVariables)) {
296
- // If filter *only* applies to left entry of optional, push it down into that.
297
- this.logDebug(context, `Push down filter into left join`);
298
- return [true, factory.createLeftJoin(this.filterPushdown(expression, expressionVariables, operation.input[0], factory, context)[1], operation.input[1], operation.expression)];
299
- }
300
- }
301
- // Don't push down in all other cases
232
+ if (notOverlapping.length > 0) {
233
+ joins.push(...notOverlapping);
234
+ }
235
+ if (joins.length > 1) {
236
+ isModified = true;
237
+ }
238
+ if (isModified) {
239
+ this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
240
+ }
241
+ return [isModified, joins.length === 1 ? joins[0] : factory.createJoin(joins)];
242
+ }
243
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.NOP)) {
244
+ return [true, operation];
245
+ }
246
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.PROJECT)) {
247
+ // Push down if variables overlap
248
+ if (this.variablesIntersect(operation.variables, expressionVariables)) {
249
+ return [true, factory.createProject(this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1], operation.variables)];
250
+ }
251
+ // Void expression otherwise
252
+ return [true, operation];
253
+ }
254
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.UNION)) {
255
+ // Determine overlapping operations
256
+ const { fullyOverlapping, partiallyOverlapping, notOverlapping, } = this.getOverlappingOperations(operation, expressionVariables);
257
+ const unions = [];
258
+ let isModified = false;
259
+ if (fullyOverlapping.length > 0) {
260
+ isModified = true;
261
+ unions.push(factory.createUnion(fullyOverlapping
262
+ .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));
263
+ }
264
+ if (partiallyOverlapping.length > 0) {
265
+ unions.push(factory.createFilter(factory.createUnion(partiallyOverlapping, false), expression));
266
+ }
267
+ if (notOverlapping.length > 0) {
268
+ unions.push(...notOverlapping);
269
+ }
270
+ if (unions.length > 1) {
271
+ isModified = true;
272
+ }
273
+ if (isModified) {
274
+ this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
275
+ }
276
+ return [isModified, unions.length === 1 ? unions[0] : factory.createUnion(unions)];
277
+ }
278
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.VALUES)) {
279
+ // Only keep filter if it overlaps with the variables
280
+ if (this.variablesIntersect(operation.variables, expressionVariables)) {
302
281
  return [false, factory.createFilter(operation, expression)];
303
282
  }
304
- case sparqlalgebrajs_1.Algebra.types.PATTERN: {
305
- if (this.pushEqualityIntoPatterns) {
306
- // Try to push simple FILTER(?s = <iri>) expressions into the pattern
307
- const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);
308
- if (pushableResult) {
309
- let isModified = false;
310
- const originalMetadata = operation.metadata;
311
- operation = (0, rdf_terms_1.mapTermsNested)(operation, (value) => {
312
- if (value.equals(pushableResult.variable)) {
313
- isModified = true;
314
- return pushableResult.term;
315
- }
316
- return value;
317
- });
318
- operation.type = sparqlalgebrajs_1.Algebra.types.PATTERN;
319
- operation.metadata = originalMetadata;
320
- if (isModified) {
321
- this.logDebug(context, `Push down filter into pattern for ?${pushableResult.variable.value}`);
322
- return [true, factory.createJoin([
323
- operation,
324
- factory.createValues([pushableResult.variable], [{ [`?${pushableResult.variable.value}`]: pushableResult.term }]),
325
- ])];
326
- }
327
- }
283
+ return [true, operation];
284
+ }
285
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.LEFT_JOIN)) {
286
+ if (this.pushIntoLeftJoins) {
287
+ const rightVariables = utils_algebra_1.algebraUtils.inScopeVariables(operation.input[1]);
288
+ if (!this.variablesIntersect(expressionVariables, rightVariables)) {
289
+ // If filter *only* applies to left entry of optional, push it down into that.
290
+ this.logDebug(context, `Push down filter into left join`);
291
+ return [true, factory.createLeftJoin(this.filterPushdown(expression, expressionVariables, operation.input[0], factory, context)[1], operation.input[1], operation.expression)];
328
292
  }
329
- // Don't push down in all other cases
330
- return [false, factory.createFilter(operation, expression)];
331
293
  }
332
- case sparqlalgebrajs_1.Algebra.types.PATH: {
333
- if (this.pushEqualityIntoPatterns) {
334
- // Try to push simple FILTER(?s = <iri>) expressions into the path
335
- const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);
336
- if (pushableResult &&
337
- (operation.subject.equals(pushableResult.variable) || operation.object.equals(pushableResult.variable))) {
338
- this.logDebug(context, `Push down filter into path for ?${pushableResult.variable.value}`);
339
- const originalMetadata = operation.metadata;
340
- operation = factory.createPath(operation.subject.equals(pushableResult.variable) ? pushableResult.term : operation.subject, operation.predicate, operation.object.equals(pushableResult.variable) ? pushableResult.term : operation.object);
341
- operation.metadata = originalMetadata;
294
+ // Don't push down in all other cases
295
+ return [false, factory.createFilter(operation, expression)];
296
+ }
297
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.PATTERN)) {
298
+ if (this.pushEqualityIntoPatterns) {
299
+ // Try to push simple FILTER(?s = <iri>) expressions into the pattern
300
+ const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);
301
+ if (pushableResult) {
302
+ let isModified = false;
303
+ const originalMetadata = operation.metadata;
304
+ operation = (0, rdf_terms_1.mapTermsNested)(operation, (value) => {
305
+ if (value.equals(pushableResult.variable)) {
306
+ isModified = true;
307
+ return pushableResult.term;
308
+ }
309
+ return value;
310
+ });
311
+ operation.type = utils_algebra_1.Algebra.Types.PATTERN;
312
+ operation.metadata = originalMetadata;
313
+ if (isModified) {
314
+ this.logDebug(context, `Push down filter into pattern for ?${pushableResult.variable.value}`);
342
315
  return [true, factory.createJoin([
343
316
  operation,
344
- factory.createValues([pushableResult.variable], [{ [`?${pushableResult.variable.value}`]: pushableResult.term }]),
317
+ factory.createValues([pushableResult.variable], [{ [pushableResult.variable.value]: pushableResult.term }]),
345
318
  ])];
346
319
  }
347
320
  }
348
- // Don't push down in all other cases
349
- return [false, factory.createFilter(operation, expression)];
350
321
  }
351
- case sparqlalgebrajs_1.Algebra.types.MINUS:
352
- case sparqlalgebrajs_1.Algebra.types.ALT:
353
- case sparqlalgebrajs_1.Algebra.types.ASK:
354
- case sparqlalgebrajs_1.Algebra.types.BGP:
355
- case sparqlalgebrajs_1.Algebra.types.CONSTRUCT:
356
- case sparqlalgebrajs_1.Algebra.types.DESCRIBE:
357
- case sparqlalgebrajs_1.Algebra.types.DISTINCT:
358
- case sparqlalgebrajs_1.Algebra.types.EXPRESSION:
359
- case sparqlalgebrajs_1.Algebra.types.FROM:
360
- case sparqlalgebrajs_1.Algebra.types.GRAPH:
361
- case sparqlalgebrajs_1.Algebra.types.GROUP:
362
- case sparqlalgebrajs_1.Algebra.types.INV:
363
- case sparqlalgebrajs_1.Algebra.types.LINK:
364
- case sparqlalgebrajs_1.Algebra.types.NPS:
365
- case sparqlalgebrajs_1.Algebra.types.ONE_OR_MORE_PATH:
366
- case sparqlalgebrajs_1.Algebra.types.ORDER_BY:
367
- case sparqlalgebrajs_1.Algebra.types.REDUCED:
368
- case sparqlalgebrajs_1.Algebra.types.SEQ:
369
- case sparqlalgebrajs_1.Algebra.types.SERVICE:
370
- case sparqlalgebrajs_1.Algebra.types.SLICE:
371
- case sparqlalgebrajs_1.Algebra.types.ZERO_OR_MORE_PATH:
372
- case sparqlalgebrajs_1.Algebra.types.ZERO_OR_ONE_PATH:
373
- case sparqlalgebrajs_1.Algebra.types.COMPOSITE_UPDATE:
374
- case sparqlalgebrajs_1.Algebra.types.DELETE_INSERT:
375
- case sparqlalgebrajs_1.Algebra.types.LOAD:
376
- case sparqlalgebrajs_1.Algebra.types.CLEAR:
377
- case sparqlalgebrajs_1.Algebra.types.CREATE:
378
- case sparqlalgebrajs_1.Algebra.types.DROP:
379
- case sparqlalgebrajs_1.Algebra.types.ADD:
380
- case sparqlalgebrajs_1.Algebra.types.MOVE:
381
- case sparqlalgebrajs_1.Algebra.types.COPY:
382
- // Operations that do not support pushing down
383
- // Left-join and minus might be possible to support in the future.
384
- return [false, factory.createFilter(operation, expression)];
322
+ // Don't push down in all other cases
323
+ return [false, factory.createFilter(operation, expression)];
385
324
  }
325
+ if ((0, utils_algebra_1.isKnownOperation)(operation, utils_algebra_1.Algebra.Types.PATH)) {
326
+ if (this.pushEqualityIntoPatterns) {
327
+ // Try to push simple FILTER(?s = <iri>) expressions into the path
328
+ const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);
329
+ if (pushableResult &&
330
+ (operation.subject.equals(pushableResult.variable) || operation.object.equals(pushableResult.variable))) {
331
+ this.logDebug(context, `Push down filter into path for ?${pushableResult.variable.value}`);
332
+ const originalMetadata = operation.metadata;
333
+ operation = factory.createPath(operation.subject.equals(pushableResult.variable) ? pushableResult.term : operation.subject, operation.predicate, operation.object.equals(pushableResult.variable) ? pushableResult.term : operation.object);
334
+ operation.metadata = originalMetadata;
335
+ return [true, factory.createJoin([
336
+ operation,
337
+ factory.createValues([pushableResult.variable], [{ [pushableResult.variable.value]: pushableResult.term }]),
338
+ ])];
339
+ }
340
+ }
341
+ // Don't push down in all other cases
342
+ return [false, factory.createFilter(operation, expression)];
343
+ }
344
+ // Operations that do not support pushing down
345
+ // Left-join and minus might be possible to support in the future.
346
+ return [false, factory.createFilter(operation, expression)];
386
347
  }
387
348
  /**
388
349
  * Check if the given expression is a simple equals operation with one variable and one non-literal
@@ -391,23 +352,24 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
391
352
  * @return The variable and term to fill into the pattern, or undefined.
392
353
  */
393
354
  getEqualityExpressionPushableIntoPattern(expression) {
394
- if (expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.OPERATOR && expression.operator === '=') {
395
- if (expression.args[0].expressionType === 'term' && expression.args[0].term.termType !== 'Variable' &&
396
- (expression.args[0].term.termType !== 'Literal' ||
397
- this.isLiteralWithCanonicalLexicalForm(expression.args[0].term)) &&
398
- expression.args[1].expressionType === 'term' && expression.args[1].term.termType === 'Variable') {
355
+ if ((0, utils_algebra_1.isKnownSubType)(expression, utils_algebra_1.Algebra.ExpressionTypes.OPERATOR) && expression.operator === '=') {
356
+ const arg0 = expression.args[0];
357
+ const arg1 = expression.args[1];
358
+ if ((0, utils_algebra_1.isKnownSubType)(arg0, utils_algebra_1.Algebra.ExpressionTypes.TERM) && arg0.term.termType !== 'Variable' &&
359
+ (arg0.term.termType !== 'Literal' || this.isLiteralWithCanonicalLexicalForm(arg0.term)) &&
360
+ (0, utils_algebra_1.isKnownSubType)(arg1, utils_algebra_1.Algebra.ExpressionTypes.TERM) &&
361
+ arg1.term.termType === 'Variable') {
399
362
  return {
400
- variable: expression.args[1].term,
401
- term: expression.args[0].term,
363
+ variable: arg1.term,
364
+ term: arg0.term,
402
365
  };
403
366
  }
404
- if (expression.args[0].expressionType === 'term' && expression.args[0].term.termType === 'Variable' &&
405
- expression.args[1].expressionType === 'term' && expression.args[1].term.termType !== 'Variable' &&
406
- (expression.args[1].term.termType !== 'Literal' ||
407
- this.isLiteralWithCanonicalLexicalForm(expression.args[1].term))) {
367
+ if ((0, utils_algebra_1.isKnownSubType)(arg0, utils_algebra_1.Algebra.ExpressionTypes.TERM) && arg0.term.termType === 'Variable' &&
368
+ (0, utils_algebra_1.isKnownSubType)(arg1, utils_algebra_1.Algebra.ExpressionTypes.TERM) && arg1.term.termType !== 'Variable' &&
369
+ (arg1.term.termType !== 'Literal' || this.isLiteralWithCanonicalLexicalForm(arg1.term))) {
408
370
  return {
409
- variable: expression.args[0].term,
410
- term: expression.args[1].term,
371
+ variable: arg0.term,
372
+ term: arg1.term,
411
373
  };
412
374
  }
413
375
  }
@@ -421,21 +383,19 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
421
383
  * @protected
422
384
  */
423
385
  isLiteralWithCanonicalLexicalForm(term) {
424
- if (term.termType === 'Literal') {
425
- switch (term.datatype.value) {
426
- case 'http://www.w3.org/2001/XMLSchema#string':
427
- case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString':
428
- case 'http://www.w3.org/2001/XMLSchema#normalizedString':
429
- case 'http://www.w3.org/2001/XMLSchema#anyURI':
430
- case 'http://www.w3.org/2001/XMLSchema#base64Binary':
431
- case 'http://www.w3.org/2001/XMLSchema#language':
432
- case 'http://www.w3.org/2001/XMLSchema#Name':
433
- case 'http://www.w3.org/2001/XMLSchema#NCName':
434
- case 'http://www.w3.org/2001/XMLSchema#NMTOKEN':
435
- case 'http://www.w3.org/2001/XMLSchema#token':
436
- case 'http://www.w3.org/2001/XMLSchema#hexBinary':
437
- return true;
438
- }
386
+ switch (term.datatype.value) {
387
+ case 'http://www.w3.org/2001/XMLSchema#string':
388
+ case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString':
389
+ case 'http://www.w3.org/2001/XMLSchema#normalizedString':
390
+ case 'http://www.w3.org/2001/XMLSchema#anyURI':
391
+ case 'http://www.w3.org/2001/XMLSchema#base64Binary':
392
+ case 'http://www.w3.org/2001/XMLSchema#language':
393
+ case 'http://www.w3.org/2001/XMLSchema#Name':
394
+ case 'http://www.w3.org/2001/XMLSchema#NCName':
395
+ case 'http://www.w3.org/2001/XMLSchema#NMTOKEN':
396
+ case 'http://www.w3.org/2001/XMLSchema#token':
397
+ case 'http://www.w3.org/2001/XMLSchema#hexBinary':
398
+ return true;
439
399
  }
440
400
  return false;
441
401
  }
@@ -462,7 +422,8 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
462
422
  * @param expression An expression.
463
423
  */
464
424
  isExpressionFalse(expression) {
465
- return (expression.term && expression.term.termType === 'Literal' && expression.term.value === 'false');
425
+ const casted = expression;
426
+ return (casted.term && casted.term.termType === 'Literal' && casted.term.value === 'false');
466
427
  }
467
428
  /**
468
429
  * Get all directly nested filter expressions.
@@ -470,7 +431,7 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
470
431
  * @param op A filter expression.
471
432
  */
472
433
  getNestedFilterExpressions(op) {
473
- if (op.input.type === sparqlalgebrajs_1.Algebra.types.FILTER) {
434
+ if ((0, utils_algebra_1.isKnownOperation)(op.input, utils_algebra_1.Algebra.Types.FILTER)) {
474
435
  const childData = this.getNestedFilterExpressions(op.input);
475
436
  return { nestedExpressions: [op.expression, ...childData.nestedExpressions], input: childData.input };
476
437
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ActorOptimizeQueryOperationFilterPushdown.js","sourceRoot":"","sources":["ActorOptimizeQueryOperationFilterPushdown.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n IActionOptimizeQueryOperation,\n IActorOptimizeQueryOperationArgs,\n IActorOptimizeQueryOperationOutput,\n} from '@comunica/bus-optimize-query-operation';\nimport { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';\nimport { KeysInitQuery } from '@comunica/context-entries';\nimport type { IActorTest, TestResult } from '@comunica/core';\nimport { passTestVoid } from '@comunica/core';\nimport type {\n ComunicaDataFactory,\n FragmentSelectorShape,\n IActionContext,\n IQuerySourceWrapper,\n} from '@comunica/types';\nimport {\n doesShapeAcceptOperation,\n getExpressionVariables,\n getOperationSource,\n} from '@comunica/utils-query-operation';\nimport type * as RDF from '@rdfjs/types';\nimport { mapTermsNested } from 'rdf-terms';\nimport { Factory, Algebra, Util } from 'sparqlalgebrajs';\n\n/**\n * A comunica Filter Pushdown Optimize Query Operation Actor.\n */\nexport class ActorOptimizeQueryOperationFilterPushdown extends ActorOptimizeQueryOperation {\n private readonly aggressivePushdown: boolean;\n private readonly maxIterations: number;\n private readonly splitConjunctive: boolean;\n private readonly mergeConjunctive: boolean;\n private readonly pushIntoLeftJoins: boolean;\n private readonly pushEqualityIntoPatterns: boolean;\n\n public constructor(args: IActorOptimizeQueryOperationFilterPushdownArgs) {\n super(args);\n }\n\n public async test(_action: IActionOptimizeQueryOperation): Promise<TestResult<IActorTest>> {\n return passTestVoid();\n }\n\n public async run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput> {\n const dataFactory: ComunicaDataFactory = action.context.getSafe(KeysInitQuery.dataFactory);\n const algebraFactory = new Factory(dataFactory);\n let operation: Algebra.Operation = action.operation;\n\n // eslint-disable-next-line ts/no-this-alias\n const self = this;\n\n // Split conjunctive filters into nested filters\n if (this.splitConjunctive) {\n operation = Util.mapOperation(operation, {\n filter(op: Algebra.Filter, factory: Factory) {\n // Split conjunctive filters into separate filters\n if (op.expression.expressionType === Algebra.expressionTypes.OPERATOR && op.expression.operator === '&&') {\n self.logDebug(action.context, `Split conjunctive filter into ${op.expression.args.length} nested filters`);\n return {\n recurse: true,\n result: op.expression.args\n .reduce((operation, expression) => factory.createFilter(operation, expression), op.input),\n };\n }\n return {\n recurse: true,\n result: op,\n };\n },\n }, algebraFactory);\n }\n\n // Collect selector shapes of all operations\n const sources = this.getSources(operation);\n // eslint-disable-next-line ts/no-unnecessary-type-assertion\n const sourceShapes = new Map(<[IQuerySourceWrapper, FragmentSelectorShape][]> await Promise.all(sources\n .map(async source => [ source, await source.source.getSelectorShape(action.context) ])));\n\n // Push down all filters\n // We loop until no more filters can be pushed down.\n let repeat = true;\n let iterations = 0;\n while (repeat && iterations < this.maxIterations) {\n repeat = false;\n operation = Util.mapOperation(operation, {\n filter(op: Algebra.Filter, factory: Factory) {\n // Check if the filter must be pushed down\n const extensionFunctions = action.context.get(KeysInitQuery.extensionFunctions);\n if (!self.shouldAttemptPushDown(op, sources, sourceShapes, extensionFunctions)) {\n return {\n recurse: true,\n result: op,\n };\n }\n\n // For all filter expressions in the operation,\n // we attempt to push them down as deep as possible into the algebra.\n const variables = getExpressionVariables(op.expression);\n const [ isModified, result ] = self\n .filterPushdown(op.expression, variables, op.input, factory, action.context);\n if (isModified) {\n repeat = true;\n }\n return {\n recurse: true,\n result,\n };\n },\n });\n iterations++;\n }\n\n if (iterations > 1) {\n self.logDebug(action.context, `Pushed down filters in ${iterations} iterations`);\n }\n\n // Merge nested filters into conjunctive filters\n if (this.mergeConjunctive) {\n operation = Util.mapOperation(operation, {\n filter(op: Algebra.Filter, factory: Factory) {\n if (op.input.type === Algebra.types.FILTER) {\n const { nestedExpressions, input } = self.getNestedFilterExpressions(op);\n self.logDebug(action.context, `Merge ${nestedExpressions.length} nested filters into conjunctive filter`);\n return {\n recurse: true,\n result: factory.createFilter(\n input,\n nestedExpressions.slice(1).reduce((previous, current) =>\n factory.createOperatorExpression('&&', [ previous, current ]), nestedExpressions[0]),\n ),\n };\n }\n return {\n recurse: true,\n result: op,\n };\n },\n });\n }\n\n return { operation, context: action.context };\n }\n\n /**\n * Check if the given filter operation must be attempted to push down, based on the following criteria:\n * - Always push down if aggressive mode is enabled\n * - Push down if the filter is extremely selective\n * - Don't push down extension functions comunica support, but a source does not\n * - Push down if federated and at least one accepts the filter\n * @param operation The filter operation\n * @param sources The query sources in the operation\n * @param sourceShapes A mapping of sources to selector shapes.\n * @param extensionFunctions The extension functions comunica supports.\n */\n public shouldAttemptPushDown(\n operation: Algebra.Filter,\n sources: IQuerySourceWrapper[],\n sourceShapes: Map<IQuerySourceWrapper, FragmentSelectorShape>,\n extensionFunctions?: Record<string, any>,\n ): boolean {\n // Always push down if aggressive mode is enabled\n if (this.aggressivePushdown) {\n return true;\n }\n\n // Push down if the filter is extremely selective\n const expression = operation.expression;\n if (expression.expressionType === Algebra.expressionTypes.OPERATOR &&\n expression.operator === '=' &&\n ((expression.args[0].expressionType === 'term' && expression.args[0].term.termType !== 'Variable' &&\n expression.args[1].expressionType === 'term' && expression.args[1].term.termType === 'Variable') ||\n (expression.args[0].expressionType === 'term' && expression.args[0].term.termType === 'Variable' &&\n expression.args[1].expressionType === 'term' && expression.args[1].term.termType !== 'Variable'))) {\n return true;\n }\n\n // Don't push down extension functions comunica support, but no source does\n if (extensionFunctions && expression.expressionType === Algebra.expressionTypes.NAMED &&\n expression.name.value in extensionFunctions &&\n // Checks if there's not a single source that supports the extension function\n !sources.some(source =>\n doesShapeAcceptOperation(sourceShapes.get(source)!, expression))\n ) {\n return false;\n }\n\n // Push down if federated and at least one accepts the filter\n if (sources.some(source => doesShapeAcceptOperation(sourceShapes.get(source)!, operation))) {\n return true;\n }\n\n // Don't push down in all other cases\n return false;\n }\n\n /**\n * Collected all sources that are defined within the given operation of children recursively.\n * @param operation An operation.\n */\n public getSources(operation: Algebra.Operation): IQuerySourceWrapper[] {\n const sources = new Set<IQuerySourceWrapper>();\n const sourceAdder = (subOperation: Algebra.Operation): boolean => {\n const src = getOperationSource(subOperation);\n if (src) {\n sources.add(src);\n }\n return false;\n };\n Util.recurseOperation(operation, {\n [Algebra.types.PATTERN]: sourceAdder,\n [Algebra.types.LINK]: sourceAdder,\n [Algebra.types.NPS]: sourceAdder,\n [Algebra.types.SERVICE]: sourceAdder,\n });\n return [ ...sources ];\n }\n\n protected getOverlappingOperations(\n operation: Algebra.Operation,\n expressionVariables: RDF.Variable[],\n ): {\n fullyOverlapping: Algebra.Operation[];\n partiallyOverlapping: Algebra.Operation[];\n notOverlapping: Algebra.Operation[];\n } {\n const fullyOverlapping: Algebra.Operation[] = [];\n const partiallyOverlapping: Algebra.Operation[] = [];\n const notOverlapping: Algebra.Operation[] = [];\n for (const input of operation.input) {\n const inputVariables = Util.inScopeVariables(input);\n if (this.variablesSubSetOf(expressionVariables, inputVariables)) {\n fullyOverlapping.push(input);\n } else if (this.variablesIntersect(expressionVariables, inputVariables)) {\n partiallyOverlapping.push(input);\n } else {\n notOverlapping.push(input);\n }\n }\n\n return {\n fullyOverlapping,\n partiallyOverlapping,\n notOverlapping,\n };\n }\n\n /**\n * Recursively push down the given expression into the given operation if possible.\n * Different operators have different semantics for choosing whether or not to push down,\n * and how this pushdown is done.\n * For every passed operator, it is checked whether or not the filter will have any effect on the operation.\n * If not, the filter is voided.\n * @param expression An expression to push down.\n * @param expressionVariables The variables inside the given expression.\n * @param operation The operation to push down into.\n * @param factory An algebra factory.\n * @param context The action context.\n * @return A tuple indicating if the operation was modified and the modified operation.\n */\n public filterPushdown(\n expression: Algebra.Expression,\n expressionVariables: RDF.Variable[],\n operation: Algebra.Operation,\n factory: Factory,\n context: IActionContext,\n ): [ boolean, Algebra.Operation ] {\n // Void false expressions\n if (this.isExpressionFalse(expression)) {\n return [ true, factory.createUnion([]) ];\n }\n\n // Don't push down (NOT) EXISTS\n if (expression.expressionType === Algebra.expressionTypes.EXISTENCE) {\n return [ false, factory.createFilter(operation, expression) ];\n }\n\n switch (operation.type) {\n case Algebra.types.EXTEND:\n // Pass if the variable is not part of the expression\n if (!this.variablesIntersect([ operation.variable ], expressionVariables)) {\n return [ true, factory.createExtend(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1],\n operation.variable,\n operation.expression,\n ) ];\n }\n return [ false, factory.createFilter(operation, expression) ];\n case Algebra.types.FILTER: {\n // Always pass\n const [ isModified, result ] = this\n .filterPushdown(expression, expressionVariables, operation.input, factory, context);\n return [ isModified, factory.createFilter(result, operation.expression) ];\n }\n case Algebra.types.JOIN: {\n // Don't push down for empty join\n if (operation.input.length === 0) {\n return [ false, factory.createFilter(operation, expression) ];\n }\n\n // Determine overlapping operations\n const {\n fullyOverlapping,\n partiallyOverlapping,\n notOverlapping,\n } = this.getOverlappingOperations(operation, expressionVariables);\n\n const joins: Algebra.Operation[] = [];\n let isModified = false;\n if (fullyOverlapping.length > 0) {\n isModified = true;\n joins.push(factory.createJoin(fullyOverlapping\n .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));\n }\n if (partiallyOverlapping.length > 0) {\n joins.push(factory.createFilter(factory.createJoin(partiallyOverlapping, false), expression));\n }\n if (notOverlapping.length > 0) {\n joins.push(...notOverlapping);\n }\n\n if (joins.length > 1) {\n isModified = true;\n }\n\n if (isModified) {\n this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);\n }\n\n return [ isModified, joins.length === 1 ? joins[0] : factory.createJoin(joins) ];\n }\n case Algebra.types.NOP:\n return [ true, operation ];\n case Algebra.types.PROJECT:\n // Push down if variables overlap\n if (this.variablesIntersect(operation.variables, expressionVariables)) {\n return [ true, factory.createProject(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1],\n operation.variables,\n ) ];\n }\n // Void expression otherwise\n return [ true, operation ];\n case Algebra.types.UNION: {\n // Determine overlapping operations\n const {\n fullyOverlapping,\n partiallyOverlapping,\n notOverlapping,\n } = this.getOverlappingOperations(operation, expressionVariables);\n\n const unions: Algebra.Operation[] = [];\n let isModified = false;\n if (fullyOverlapping.length > 0) {\n isModified = true;\n unions.push(factory.createUnion(fullyOverlapping\n .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));\n }\n if (partiallyOverlapping.length > 0) {\n unions.push(factory.createFilter(factory.createUnion(partiallyOverlapping, false), expression));\n }\n if (notOverlapping.length > 0) {\n unions.push(...notOverlapping);\n }\n\n if (unions.length > 1) {\n isModified = true;\n }\n\n if (isModified) {\n this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);\n }\n\n return [ isModified, unions.length === 1 ? unions[0] : factory.createUnion(unions) ];\n }\n case Algebra.types.VALUES:\n // Only keep filter if it overlaps with the variables\n if (this.variablesIntersect(operation.variables, expressionVariables)) {\n return [ false, factory.createFilter(operation, expression) ];\n }\n return [ true, operation ];\n case Algebra.types.LEFT_JOIN: {\n if (this.pushIntoLeftJoins) {\n const rightVariables = Util.inScopeVariables(operation.input[1]);\n if (!this.variablesIntersect(expressionVariables, rightVariables)) {\n // If filter *only* applies to left entry of optional, push it down into that.\n this.logDebug(context, `Push down filter into left join`);\n return [ true, factory.createLeftJoin(\n this.filterPushdown(expression, expressionVariables, operation.input[0], factory, context)[1],\n operation.input[1],\n operation.expression,\n ) ];\n }\n }\n\n // Don't push down in all other cases\n return [ false, factory.createFilter(operation, expression) ];\n }\n case Algebra.types.PATTERN: {\n if (this.pushEqualityIntoPatterns) {\n // Try to push simple FILTER(?s = <iri>) expressions into the pattern\n const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);\n if (pushableResult) {\n let isModified = false;\n const originalMetadata = operation.metadata;\n operation = mapTermsNested(operation, (value) => {\n if (value.equals(pushableResult.variable)) {\n isModified = true;\n return pushableResult.term;\n }\n return value;\n });\n operation.type = Algebra.types.PATTERN;\n operation.metadata = originalMetadata;\n if (isModified) {\n this.logDebug(context, `Push down filter into pattern for ?${pushableResult.variable.value}`);\n return [ true, factory.createJoin([\n operation,\n factory.createValues(\n [ pushableResult.variable ],\n [{ [`?${pushableResult.variable.value}`]: <RDF.NamedNode | RDF.Literal> pushableResult.term }],\n ),\n ]) ];\n }\n }\n }\n\n // Don't push down in all other cases\n return [ false, factory.createFilter(operation, expression) ];\n }\n case Algebra.types.PATH: {\n if (this.pushEqualityIntoPatterns) {\n // Try to push simple FILTER(?s = <iri>) expressions into the path\n const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);\n if (pushableResult &&\n (operation.subject.equals(pushableResult.variable) || operation.object.equals(pushableResult.variable))) {\n this.logDebug(context, `Push down filter into path for ?${pushableResult.variable.value}`);\n const originalMetadata = operation.metadata;\n operation = factory.createPath(\n operation.subject.equals(pushableResult.variable) ? pushableResult.term : operation.subject,\n operation.predicate,\n operation.object.equals(pushableResult.variable) ? pushableResult.term : operation.object,\n );\n operation.metadata = originalMetadata;\n return [ true, factory.createJoin([\n operation,\n factory.createValues(\n [ pushableResult.variable ],\n [{ [`?${pushableResult.variable.value}`]: <RDF.NamedNode | RDF.Literal> pushableResult.term }],\n ),\n ]) ];\n }\n }\n\n // Don't push down in all other cases\n return [ false, factory.createFilter(operation, expression) ];\n }\n case Algebra.types.MINUS:\n case Algebra.types.ALT:\n case Algebra.types.ASK:\n case Algebra.types.BGP:\n case Algebra.types.CONSTRUCT:\n case Algebra.types.DESCRIBE:\n case Algebra.types.DISTINCT:\n case Algebra.types.EXPRESSION:\n case Algebra.types.FROM:\n case Algebra.types.GRAPH:\n case Algebra.types.GROUP:\n case Algebra.types.INV:\n case Algebra.types.LINK:\n case Algebra.types.NPS:\n case Algebra.types.ONE_OR_MORE_PATH:\n case Algebra.types.ORDER_BY:\n case Algebra.types.REDUCED:\n case Algebra.types.SEQ:\n case Algebra.types.SERVICE:\n case Algebra.types.SLICE:\n case Algebra.types.ZERO_OR_MORE_PATH:\n case Algebra.types.ZERO_OR_ONE_PATH:\n case Algebra.types.COMPOSITE_UPDATE:\n case Algebra.types.DELETE_INSERT:\n case Algebra.types.LOAD:\n case Algebra.types.CLEAR:\n case Algebra.types.CREATE:\n case Algebra.types.DROP:\n case Algebra.types.ADD:\n case Algebra.types.MOVE:\n case Algebra.types.COPY:\n // Operations that do not support pushing down\n // Left-join and minus might be possible to support in the future.\n return [ false, factory.createFilter(operation, expression) ];\n }\n }\n\n /**\n * Check if the given expression is a simple equals operation with one variable and one non-literal\n * (or literal with canonical lexical form) term that can be pushed into a pattern.\n * @param expression The current expression.\n * @return The variable and term to fill into the pattern, or undefined.\n */\n public getEqualityExpressionPushableIntoPattern(\n expression: Algebra.Expression,\n ): { variable: RDF.Variable; term: RDF.Term } | undefined {\n if (expression.expressionType === Algebra.expressionTypes.OPERATOR && expression.operator === '=') {\n if (expression.args[0].expressionType === 'term' && expression.args[0].term.termType !== 'Variable' &&\n (expression.args[0].term.termType !== 'Literal' ||\n this.isLiteralWithCanonicalLexicalForm(expression.args[0].term)) &&\n expression.args[1].expressionType === 'term' && expression.args[1].term.termType === 'Variable') {\n return {\n variable: expression.args[1].term,\n term: expression.args[0].term,\n };\n }\n if (expression.args[0].expressionType === 'term' && expression.args[0].term.termType === 'Variable' &&\n expression.args[1].expressionType === 'term' && expression.args[1].term.termType !== 'Variable' &&\n (expression.args[1].term.termType !== 'Literal' ||\n this.isLiteralWithCanonicalLexicalForm(expression.args[1].term))) {\n return {\n variable: expression.args[0].term,\n term: expression.args[1].term,\n };\n }\n }\n }\n\n /**\n * Check if the given term is a literal with datatype that where all values\n * can only have one possible lexical representation.\n * In other words, no variants of values exist that should be considered equal.\n * For example: \"01\"^xsd:number and \"1\"^xsd:number will return false.\n * @param term An RDF term.\n * @protected\n */\n protected isLiteralWithCanonicalLexicalForm(term: RDF.Term): boolean {\n if (term.termType === 'Literal') {\n switch (term.datatype.value) {\n case 'http://www.w3.org/2001/XMLSchema#string':\n case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString':\n case 'http://www.w3.org/2001/XMLSchema#normalizedString':\n case 'http://www.w3.org/2001/XMLSchema#anyURI':\n case 'http://www.w3.org/2001/XMLSchema#base64Binary':\n case 'http://www.w3.org/2001/XMLSchema#language':\n case 'http://www.w3.org/2001/XMLSchema#Name':\n case 'http://www.w3.org/2001/XMLSchema#NCName':\n case 'http://www.w3.org/2001/XMLSchema#NMTOKEN':\n case 'http://www.w3.org/2001/XMLSchema#token':\n case 'http://www.w3.org/2001/XMLSchema#hexBinary':\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if there is an overlap between the two given lists of variables.\n * @param varsA A list of variables.\n * @param varsB A list of variables.\n */\n public variablesIntersect(varsA: RDF.Variable[], varsB: RDF.Variable[]): boolean {\n return varsA.some(varA => varsB.some(varB => varA.equals(varB)));\n }\n\n /**\n * Check if all variables from the first list are included in the second list.\n * The second list may contain other variables as well.\n * @param varsNeedles A list of variables to search for.\n * @param varsHaystack A list of variables to search in.\n */\n public variablesSubSetOf(varsNeedles: RDF.Variable[], varsHaystack: RDF.Variable[]): boolean {\n return varsNeedles.length <= varsHaystack.length &&\n varsNeedles.every(varA => varsHaystack.some(varB => varA.equals(varB)));\n }\n\n /**\n * Check if an expression is simply 'false'.\n * @param expression An expression.\n */\n public isExpressionFalse(expression: Algebra.Expression): boolean {\n return (expression.term && expression.term.termType === 'Literal' && expression.term.value === 'false');\n }\n\n /**\n * Get all directly nested filter expressions.\n * As soon as a non-filter is found, it is returned as the input field.\n * @param op A filter expression.\n */\n public getNestedFilterExpressions(\n op: Algebra.Filter,\n ): { nestedExpressions: Algebra.Expression[]; input: Algebra.Operation } {\n if (op.input.type === Algebra.types.FILTER) {\n const childData = this.getNestedFilterExpressions(op.input);\n return { nestedExpressions: [ op.expression, ...childData.nestedExpressions ], input: childData.input };\n }\n return { nestedExpressions: [ op.expression ], input: op.input };\n }\n}\n\nexport interface IActorOptimizeQueryOperationFilterPushdownArgs extends IActorOptimizeQueryOperationArgs {\n /**\n * If filters should be pushed down as deep as possible.\n * If false, filters will only be pushed down if the source(s) accept them,\n * or if the filter is very selective.\n * @range {boolean}\n * @default {false}\n */\n aggressivePushdown: boolean;\n /**\n * The maximum number of full iterations across the query can be done for attempting to push down filters.\n * @default {10}\n */\n maxIterations: number;\n /**\n * If conjunctive filters should be split into nested filters before applying filter pushdown.\n * This can enable pushing down deeper.\n * @range {boolean}\n * @default {true}\n */\n splitConjunctive: boolean;\n /**\n * If nested filters should be merged into conjunctive filters after applying filter pushdown.\n * @range {boolean}\n * @default {true}\n */\n mergeConjunctive: boolean;\n /**\n * If filters should be pushed into left-joins.\n * @range {boolean}\n * @default {true}\n */\n pushIntoLeftJoins: boolean;\n /**\n * If simple equality filters should be pushed into patterns and paths.\n * This only applies to equality filters with terms that are not literals that have no canonical lexical form.\n * @range {boolean}\n * @default {true}\n */\n pushEqualityIntoPatterns: boolean;\n}\n"]}
1
+ {"version":3,"file":"ActorOptimizeQueryOperationFilterPushdown.js","sourceRoot":"","sources":["ActorOptimizeQueryOperationFilterPushdown.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n IActionOptimizeQueryOperation,\n IActorOptimizeQueryOperationArgs,\n IActorOptimizeQueryOperationOutput,\n} from '@comunica/bus-optimize-query-operation';\nimport { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';\nimport { KeysInitQuery } from '@comunica/context-entries';\nimport type { IActorTest, TestResult } from '@comunica/core';\nimport { passTestVoid } from '@comunica/core';\nimport type { ComunicaDataFactory, FragmentSelectorShape, IActionContext, IQuerySourceWrapper } from '@comunica/types';\nimport {\n AlgebraFactory,\n Algebra,\n algebraUtils,\n isKnownOperation,\n isKnownSubType,\n} from '@comunica/utils-algebra';\nimport { doesShapeAcceptOperation, getExpressionVariables, getOperationSource } from '@comunica/utils-query-operation';\nimport type * as RDF from '@rdfjs/types';\nimport { mapTermsNested } from 'rdf-terms';\n\n/**\n * A comunica Filter Pushdown Optimize Query Operation Actor.\n */\nexport class ActorOptimizeQueryOperationFilterPushdown extends ActorOptimizeQueryOperation {\n private readonly aggressivePushdown: boolean;\n private readonly maxIterations: number;\n private readonly splitConjunctive: boolean;\n private readonly mergeConjunctive: boolean;\n private readonly pushIntoLeftJoins: boolean;\n private readonly pushEqualityIntoPatterns: boolean;\n\n public constructor(args: IActorOptimizeQueryOperationFilterPushdownArgs) {\n super(args);\n }\n\n public async test(_action: IActionOptimizeQueryOperation): Promise<TestResult<IActorTest>> {\n return passTestVoid();\n }\n\n public async run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput> {\n const dataFactory: ComunicaDataFactory = action.context.getSafe(KeysInitQuery.dataFactory);\n const algebraFactory = new AlgebraFactory(dataFactory);\n let operation: Algebra.Operation = action.operation;\n\n // Split conjunctive filters into nested filters\n if (this.splitConjunctive) {\n operation = algebraUtils.mapOperation(operation, {\n [Algebra.Types.FILTER]: { transform: (filterOp) => {\n // Split conjunctive filters into separate filters\n if (isKnownSubType(filterOp.expression, Algebra.ExpressionTypes.OPERATOR) &&\n filterOp.expression.operator === '&&') {\n this.logDebug(action.context, `Split conjunctive filter into ${filterOp.expression.args.length} nested filters`);\n return filterOp.expression.args\n .reduce((operation, expression) => algebraFactory.createFilter(operation, expression), filterOp.input);\n }\n return filterOp;\n } },\n });\n }\n\n // Collect selector shapes of all operations\n const sources = this.getSources(operation);\n // eslint-disable-next-line ts/no-unnecessary-type-assertion\n const sourceShapes = new Map(<[IQuerySourceWrapper, FragmentSelectorShape][]> await Promise.all(sources\n .map(async source => [ source, await source.source.getSelectorShape(action.context) ])));\n\n // Push down all filters\n // We loop until no more filters can be pushed down.\n let repeat = true;\n let iterations = 0;\n while (repeat && iterations < this.maxIterations) {\n repeat = false;\n operation = algebraUtils.mapOperation(operation, {\n [Algebra.Types.FILTER]: { transform: (filterOp) => {\n // Check if the filter must be pushed down\n const extensionFunctions = action.context.get(KeysInitQuery.extensionFunctions);\n const extensionFunctionsAlwaysPushdown = action.context.get(KeysInitQuery.extensionFunctionsAlwaysPushdown);\n if (!this.shouldAttemptPushDown(\n filterOp,\n sources,\n sourceShapes,\n extensionFunctions,\n extensionFunctionsAlwaysPushdown,\n )) {\n return filterOp;\n }\n\n // For all filter expressions in the operation,\n // we attempt to push them down as deep as possible into the algebra.\n const variables = getExpressionVariables(filterOp.expression);\n const [ isModified, result ] = this\n .filterPushdown(filterOp.expression, variables, filterOp.input, algebraFactory, action.context);\n if (isModified) {\n repeat = true;\n }\n return result;\n } },\n });\n iterations++;\n }\n\n if (iterations > 1) {\n this.logDebug(action.context, `Pushed down filters in ${iterations} iterations`);\n }\n\n // Merge nested filters into conjunctive filters\n if (this.mergeConjunctive) {\n operation = algebraUtils.mapOperation(operation, {\n [Algebra.Types.FILTER]: { transform: (op) => {\n if (op.input.type === Algebra.Types.FILTER) {\n const { nestedExpressions, input } = this.getNestedFilterExpressions(op);\n this.logDebug(action.context, `Merge ${nestedExpressions.length} nested filters into conjunctive filter`);\n return algebraFactory.createFilter(\n input,\n nestedExpressions.slice(1).reduce((previous, current) =>\n algebraFactory.createOperatorExpression('&&', [ previous, current ]), nestedExpressions[0]),\n );\n }\n return op;\n } },\n });\n }\n\n return { operation, context: action.context };\n }\n\n /**\n * Check if the given filter operation must be attempted to push down, based on the following criteria:\n * - Always push down if aggressive mode is enabled\n * - Push down if the filter is extremely selective\n * - Don't push down extension functions comunica support, but a source does not\n * - Push down if federated and at least one accepts the filter\n * @param operation The filter operation\n * @param sources The query sources in the operation\n * @param sourceShapes A mapping of sources to selector shapes.\n * @param extensionFunctions The extension functions comunica supports.\n * @param extensionFunctionsAlwaysPushdown If extension functions must always be pushed down to sources that support\n * expressions, even if those sources to not explicitly declare support for\n * these extension functions.\n */\n public shouldAttemptPushDown(\n operation: Algebra.Filter,\n sources: IQuerySourceWrapper[],\n sourceShapes: Map<IQuerySourceWrapper, FragmentSelectorShape>,\n extensionFunctions?: Record<string, any>,\n extensionFunctionsAlwaysPushdown?: boolean,\n ): boolean {\n // Always push down if aggressive mode is enabled\n if (this.aggressivePushdown) {\n return true;\n }\n\n // Push down if the filter is extremely selective\n const expression = operation.expression;\n if (isKnownSubType(expression, Algebra.ExpressionTypes.OPERATOR) && expression.operator === '=' &&\n ((isKnownSubType(expression.args[0], Algebra.ExpressionTypes.TERM) &&\n expression.args[0].term.termType !== 'Variable' &&\n isKnownSubType(expression.args[1], Algebra.ExpressionTypes.TERM) &&\n expression.args[1].term.termType === 'Variable') ||\n (isKnownSubType(expression.args[0], Algebra.ExpressionTypes.TERM) &&\n expression.args[0].term.termType === 'Variable' &&\n isKnownSubType(expression.args[1], Algebra.ExpressionTypes.TERM) &&\n expression.args[1].term.termType !== 'Variable'))) {\n return true;\n }\n\n // Don't push down extension functions comunica support, but no source does\n if (extensionFunctions && isKnownSubType(expression, Algebra.ExpressionTypes.NAMED) &&\n expression.name.value in extensionFunctions &&\n // Checks if there's not a single source that supports the extension function\n !sources.some(source =>\n doesShapeAcceptOperation(sourceShapes.get(source)!, expression))\n ) {\n return false;\n }\n\n // Push down if federated and at least one accepts the filter\n if (sources.some(source => doesShapeAcceptOperation(sourceShapes.get(source)!, operation, {\n wildcardAcceptAllExtensionFunctions: extensionFunctionsAlwaysPushdown,\n }))) {\n return true;\n }\n\n // Don't push down in all other cases\n return false;\n }\n\n /**\n * Collected all sources that are defined within the given operation of children recursively.\n * @param operation An operation.\n */\n public getSources(operation: Algebra.Operation): IQuerySourceWrapper[] {\n const sources = new Set<IQuerySourceWrapper>();\n const sourceAdder = (subOperation: Algebra.Operation): boolean => {\n const src = getOperationSource(subOperation);\n if (src) {\n sources.add(src);\n }\n return false;\n };\n algebraUtils.visitOperation(operation, {\n [Algebra.Types.PATTERN]: { visitor: sourceAdder },\n [Algebra.Types.SERVICE]: { visitor: sourceAdder },\n [Algebra.Types.LINK]: { visitor: sourceAdder },\n [Algebra.Types.NPS]: { visitor: sourceAdder },\n });\n return [ ...sources ];\n }\n\n protected getOverlappingOperations(\n operation: Algebra.Union | Algebra.Join,\n expressionVariables: RDF.Variable[],\n ): {\n fullyOverlapping: Algebra.Operation[];\n partiallyOverlapping: Algebra.Operation[];\n notOverlapping: Algebra.Operation[];\n } {\n const fullyOverlapping: Algebra.Operation[] = [];\n const partiallyOverlapping: Algebra.Operation[] = [];\n const notOverlapping: Algebra.Operation[] = [];\n for (const input of operation.input) {\n const inputVariables = algebraUtils.inScopeVariables(input);\n if (this.variablesSubSetOf(expressionVariables, inputVariables)) {\n fullyOverlapping.push(input);\n } else if (this.variablesIntersect(expressionVariables, inputVariables)) {\n partiallyOverlapping.push(input);\n } else {\n notOverlapping.push(input);\n }\n }\n\n return {\n fullyOverlapping,\n partiallyOverlapping,\n notOverlapping,\n };\n }\n\n /**\n * Recursively push down the given expression into the given operation if possible.\n * Different operators have different semantics for choosing whether or not to push down,\n * and how this pushdown is done.\n * For every passed operator, it is checked whether or not the filter will have any effect on the operation.\n * If not, the filter is voided.\n * @param expression An expression to push down.\n * @param expressionVariables The variables inside the given expression.\n * @param operation The operation to push down into.\n * @param factory An algebra factory.\n * @param context The action context.\n * @return A tuple indicating if the operation was modified and the modified operation.\n */\n public filterPushdown(\n expression: Algebra.Expression,\n expressionVariables: RDF.Variable[],\n operation: Algebra.Operation,\n factory: AlgebraFactory,\n context: IActionContext,\n ): [ boolean, Algebra.Operation ] {\n // Void false expressions\n if (this.isExpressionFalse(expression)) {\n return [ true, factory.createUnion([]) ];\n }\n\n // Don't push down (NOT) EXISTS\n if (isKnownOperation(expression, Algebra.Types.EXPRESSION, Algebra.ExpressionTypes.EXISTENCE)) {\n return [ false, factory.createFilter(operation, expression) ];\n }\n\n if (isKnownOperation(operation, Algebra.Types.EXTEND)) {\n // Pass if the variable is not part of the expression\n if (!this.variablesIntersect([ operation.variable ], expressionVariables)) {\n return [ true, factory.createExtend(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1],\n operation.variable,\n operation.expression,\n ) ];\n }\n return [ false, factory.createFilter(operation, expression) ];\n }\n if (isKnownOperation(operation, Algebra.Types.FILTER)) {\n // Always pass\n const [ isModified, result ] = this\n .filterPushdown(expression, expressionVariables, operation.input, factory, context);\n return [ isModified, factory.createFilter(result, operation.expression) ];\n }\n if (isKnownOperation(operation, Algebra.Types.JOIN)) {\n // Don't push down for empty join\n if (operation.input.length === 0) {\n return [ false, factory.createFilter(operation, expression) ];\n }\n\n // Determine overlapping operations\n const {\n fullyOverlapping,\n partiallyOverlapping,\n notOverlapping,\n } = this.getOverlappingOperations(operation, expressionVariables);\n\n const joins: Algebra.Operation[] = [];\n let isModified = false;\n if (fullyOverlapping.length > 0) {\n isModified = true;\n joins.push(factory.createJoin(fullyOverlapping\n .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));\n }\n if (partiallyOverlapping.length > 0) {\n joins.push(factory.createFilter(factory.createJoin(partiallyOverlapping, false), expression));\n }\n if (notOverlapping.length > 0) {\n joins.push(...notOverlapping);\n }\n\n if (joins.length > 1) {\n isModified = true;\n }\n\n if (isModified) {\n this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);\n }\n\n return [ isModified, joins.length === 1 ? joins[0] : factory.createJoin(joins) ];\n }\n if (isKnownOperation(operation, Algebra.Types.NOP)) {\n return [ true, operation ];\n }\n if (isKnownOperation(operation, Algebra.Types.PROJECT)) {\n // Push down if variables overlap\n if (this.variablesIntersect(operation.variables, expressionVariables)) {\n return [ true, factory.createProject(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1],\n operation.variables,\n ) ];\n }\n // Void expression otherwise\n return [ true, operation ];\n }\n if (isKnownOperation(operation, Algebra.Types.UNION)) {\n // Determine overlapping operations\n const {\n fullyOverlapping,\n partiallyOverlapping,\n notOverlapping,\n } = this.getOverlappingOperations(operation, expressionVariables);\n\n const unions: Algebra.Operation[] = [];\n let isModified = false;\n if (fullyOverlapping.length > 0) {\n isModified = true;\n unions.push(factory.createUnion(fullyOverlapping\n .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));\n }\n if (partiallyOverlapping.length > 0) {\n unions.push(factory.createFilter(factory.createUnion(partiallyOverlapping, false), expression));\n }\n if (notOverlapping.length > 0) {\n unions.push(...notOverlapping);\n }\n\n if (unions.length > 1) {\n isModified = true;\n }\n\n if (isModified) {\n this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);\n }\n\n return [ isModified, unions.length === 1 ? unions[0] : factory.createUnion(unions) ];\n }\n if (isKnownOperation(operation, Algebra.Types.VALUES)) {\n // Only keep filter if it overlaps with the variables\n if (this.variablesIntersect(operation.variables, expressionVariables)) {\n return [ false, factory.createFilter(operation, expression) ];\n }\n return [ true, operation ];\n }\n if (isKnownOperation(operation, Algebra.Types.LEFT_JOIN)) {\n if (this.pushIntoLeftJoins) {\n const rightVariables = algebraUtils.inScopeVariables(operation.input[1]);\n if (!this.variablesIntersect(expressionVariables, rightVariables)) {\n // If filter *only* applies to left entry of optional, push it down into that.\n this.logDebug(context, `Push down filter into left join`);\n return [ true, factory.createLeftJoin(\n this.filterPushdown(expression, expressionVariables, operation.input[0], factory, context)[1],\n operation.input[1],\n operation.expression,\n ) ];\n }\n }\n\n // Don't push down in all other cases\n return [ false, factory.createFilter(operation, expression) ];\n }\n if (isKnownOperation(operation, Algebra.Types.PATTERN)) {\n if (this.pushEqualityIntoPatterns) {\n // Try to push simple FILTER(?s = <iri>) expressions into the pattern\n const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);\n if (pushableResult) {\n let isModified = false;\n const originalMetadata = operation.metadata;\n operation = mapTermsNested(operation, (value) => {\n if (value.equals(pushableResult.variable)) {\n isModified = true;\n return pushableResult.term;\n }\n return value;\n });\n operation.type = Algebra.Types.PATTERN;\n operation.metadata = originalMetadata;\n if (isModified) {\n this.logDebug(context, `Push down filter into pattern for ?${pushableResult.variable.value}`);\n return [ true, factory.createJoin([\n operation,\n factory.createValues(\n [ pushableResult.variable ],\n [{ [pushableResult.variable.value]: <RDF.NamedNode | RDF.Literal> pushableResult.term }],\n ),\n ]) ];\n }\n }\n }\n\n // Don't push down in all other cases\n return [ false, factory.createFilter(operation, expression) ];\n }\n if (isKnownOperation(operation, Algebra.Types.PATH)) {\n if (this.pushEqualityIntoPatterns) {\n // Try to push simple FILTER(?s = <iri>) expressions into the path\n const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);\n if (pushableResult &&\n (operation.subject.equals(pushableResult.variable) || operation.object.equals(pushableResult.variable))) {\n this.logDebug(context, `Push down filter into path for ?${pushableResult.variable.value}`);\n const originalMetadata = operation.metadata;\n operation = factory.createPath(\n operation.subject.equals(pushableResult.variable) ? pushableResult.term : operation.subject,\n operation.predicate,\n operation.object.equals(pushableResult.variable) ? pushableResult.term : operation.object,\n );\n operation.metadata = originalMetadata;\n return [ true, factory.createJoin([\n operation,\n factory.createValues(\n [ pushableResult.variable ],\n [{ [pushableResult.variable.value]: <RDF.NamedNode | RDF.Literal> pushableResult.term }],\n ),\n ]) ];\n }\n }\n\n // Don't push down in all other cases\n return [ false, factory.createFilter(operation, expression) ];\n }\n\n // Operations that do not support pushing down\n // Left-join and minus might be possible to support in the future.\n return [ false, factory.createFilter(operation, expression) ];\n }\n\n /**\n * Check if the given expression is a simple equals operation with one variable and one non-literal\n * (or literal with canonical lexical form) term that can be pushed into a pattern.\n * @param expression The current expression.\n * @return The variable and term to fill into the pattern, or undefined.\n */\n public getEqualityExpressionPushableIntoPattern(\n expression: Algebra.Expression,\n ): { variable: RDF.Variable; term: RDF.Term } | undefined {\n if (isKnownSubType(expression, Algebra.ExpressionTypes.OPERATOR) && expression.operator === '=') {\n const arg0 = expression.args[0];\n const arg1 = expression.args[1];\n if (isKnownSubType(arg0, Algebra.ExpressionTypes.TERM) && arg0.term.termType !== 'Variable' &&\n (arg0.term.termType !== 'Literal' || this.isLiteralWithCanonicalLexicalForm(arg0.term)) &&\n isKnownSubType(arg1, Algebra.ExpressionTypes.TERM) &&\n arg1.term.termType === 'Variable') {\n return {\n variable: arg1.term,\n term: arg0.term,\n };\n }\n if (isKnownSubType(arg0, Algebra.ExpressionTypes.TERM) && arg0.term.termType === 'Variable' &&\n isKnownSubType(arg1, Algebra.ExpressionTypes.TERM) && arg1.term.termType !== 'Variable' &&\n (arg1.term.termType !== 'Literal' || this.isLiteralWithCanonicalLexicalForm(arg1.term))) {\n return {\n variable: arg0.term,\n term: arg1.term,\n };\n }\n }\n }\n\n /**\n * Check if the given term is a literal with datatype that where all values\n * can only have one possible lexical representation.\n * In other words, no variants of values exist that should be considered equal.\n * For example: \"01\"^xsd:number and \"1\"^xsd:number will return false.\n * @param term An RDF term.\n * @protected\n */\n protected isLiteralWithCanonicalLexicalForm(term: RDF.Literal): boolean {\n switch (term.datatype.value) {\n case 'http://www.w3.org/2001/XMLSchema#string':\n case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString':\n case 'http://www.w3.org/2001/XMLSchema#normalizedString':\n case 'http://www.w3.org/2001/XMLSchema#anyURI':\n case 'http://www.w3.org/2001/XMLSchema#base64Binary':\n case 'http://www.w3.org/2001/XMLSchema#language':\n case 'http://www.w3.org/2001/XMLSchema#Name':\n case 'http://www.w3.org/2001/XMLSchema#NCName':\n case 'http://www.w3.org/2001/XMLSchema#NMTOKEN':\n case 'http://www.w3.org/2001/XMLSchema#token':\n case 'http://www.w3.org/2001/XMLSchema#hexBinary':\n return true;\n }\n return false;\n }\n\n /**\n * Check if there is an overlap between the two given lists of variables.\n * @param varsA A list of variables.\n * @param varsB A list of variables.\n */\n public variablesIntersect(varsA: RDF.Variable[], varsB: RDF.Variable[]): boolean {\n return varsA.some(varA => varsB.some(varB => varA.equals(varB)));\n }\n\n /**\n * Check if all variables from the first list are included in the second list.\n * The second list may contain other variables as well.\n * @param varsNeedles A list of variables to search for.\n * @param varsHaystack A list of variables to search in.\n */\n public variablesSubSetOf(varsNeedles: RDF.Variable[], varsHaystack: RDF.Variable[]): boolean {\n return varsNeedles.length <= varsHaystack.length &&\n varsNeedles.every(varA => varsHaystack.some(varB => varA.equals(varB)));\n }\n\n /**\n * Check if an expression is simply 'false'.\n * @param expression An expression.\n */\n public isExpressionFalse(expression: Algebra.Expression): boolean {\n const casted = <Extract<Algebra.KnownExpression, { term?: unknown }>> expression;\n return (casted.term && casted.term.termType === 'Literal' && casted.term.value === 'false');\n }\n\n /**\n * Get all directly nested filter expressions.\n * As soon as a non-filter is found, it is returned as the input field.\n * @param op A filter expression.\n */\n public getNestedFilterExpressions(\n op: Algebra.Filter,\n ): { nestedExpressions: Algebra.Expression[]; input: Algebra.Operation } {\n if (isKnownOperation(op.input, Algebra.Types.FILTER)) {\n const childData = this.getNestedFilterExpressions(op.input);\n return { nestedExpressions: [ op.expression, ...childData.nestedExpressions ], input: childData.input };\n }\n return { nestedExpressions: [ op.expression ], input: op.input };\n }\n}\n\nexport interface IActorOptimizeQueryOperationFilterPushdownArgs extends IActorOptimizeQueryOperationArgs {\n /**\n * If filters should be pushed down as deep as possible.\n * If false, filters will only be pushed down if the source(s) accept them,\n * or if the filter is very selective.\n * @range {boolean}\n * @default {false}\n */\n aggressivePushdown: boolean;\n /**\n * The maximum number of full iterations across the query can be done for attempting to push down filters.\n * @default {10}\n */\n maxIterations: number;\n /**\n * If conjunctive filters should be split into nested filters before applying filter pushdown.\n * This can enable pushing down deeper.\n * @range {boolean}\n * @default {true}\n */\n splitConjunctive: boolean;\n /**\n * If nested filters should be merged into conjunctive filters after applying filter pushdown.\n * @range {boolean}\n * @default {true}\n */\n mergeConjunctive: boolean;\n /**\n * If filters should be pushed into left-joins.\n * @range {boolean}\n * @default {true}\n */\n pushIntoLeftJoins: boolean;\n /**\n * If simple equality filters should be pushed into patterns and paths.\n * This only applies to equality filters with terms that are not literals that have no canonical lexical form.\n * @range {boolean}\n * @default {true}\n */\n pushEqualityIntoPatterns: boolean;\n}\n"]}
package/lib/index.d.ts CHANGED
File without changes
package/lib/index.js CHANGED
File without changes
package/lib/index.js.map CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comunica/actor-optimize-query-operation-filter-pushdown",
3
- "version": "4.4.0",
3
+ "version": "4.4.2-alpha.49.0",
4
4
  "description": "A filter-pushdown optimize-query-operation actor",
5
5
  "lsd:module": true,
6
6
  "license": "MIT",
@@ -41,14 +41,14 @@
41
41
  "build:components": "componentsjs-generator"
42
42
  },
43
43
  "dependencies": {
44
- "@comunica/bus-optimize-query-operation": "^4.4.0",
45
- "@comunica/context-entries": "^4.4.0",
46
- "@comunica/core": "^4.4.0",
47
- "@comunica/types": "^4.4.0",
48
- "@comunica/utils-query-operation": "^4.4.0",
44
+ "@comunica/bus-optimize-query-operation": "4.4.2-alpha.49.0",
45
+ "@comunica/context-entries": "4.4.2-alpha.49.0",
46
+ "@comunica/core": "4.4.2-alpha.49.0",
47
+ "@comunica/types": "4.4.2-alpha.49.0",
48
+ "@comunica/utils-algebra": "4.4.2-alpha.49.0",
49
+ "@comunica/utils-query-operation": "4.4.2-alpha.49.0",
49
50
  "@rdfjs/types": "*",
50
- "rdf-terms": "^1.11.0",
51
- "sparqlalgebrajs": "^4.3.8"
51
+ "rdf-terms": "^2.0.0"
52
52
  },
53
- "gitHead": "27acde56dfe0c1ff1162c1f46818ad752296ca88"
53
+ "gitHead": "ef6f96cfd8faf7c37955bb7e0fe9f6fc6a994bdf"
54
54
  }