@comunica/actor-optimize-query-operation-filter-pushdown 3.2.1 → 3.2.2

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.
package/README.md CHANGED
@@ -34,3 +34,12 @@ After installing, this package can be added to your engine's configuration as fo
34
34
  ]
35
35
  }
36
36
  ```
37
+
38
+ ### Config Parameters
39
+
40
+ * `aggressivePushdown`: If filters should be pushed down as deep as possible. If false, filters will only be pushed down if the source(s) accept them, or if the filter is very selective. _(defaults to `false`)_
41
+ * `maxIterations`: The maximum number of full iterations across the query can be done for attempting to push down filters. _(defaults to `10`)_
42
+ * `splitConjunctive`: If conjunctive filters should be split into nested filters before applying filter pushdown. This can enable pushing down deeper. _(defaults to `true`)_
43
+ * `mergeConjunctive`: If nested filters should be merged into conjunctive filters after applying filter pushdown. _(defaults to `true`)_
44
+ * `pushIntoLeftJoins`: If filters should be pushed into left-joins. _(defaults to `false`)_
45
+ * `pushEqualityIntoPatterns`: If simple equality filters should be pushed into patterns and paths. This only applies to equality filters with terms that are not literals that have no canonical lexical form. _(defaults to `true`)_
@@ -15,6 +15,42 @@
15
15
  ],
16
16
  "comment": "A comunica Filter Pushdown Optimize Query Operation Actor.",
17
17
  "parameters": [
18
+ {
19
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_aggressivePushdown",
20
+ "range": "xsd:boolean",
21
+ "default": "false",
22
+ "comment": "If filters should be pushed down as deep as possible. If false, filters will only be pushed down if the source(s) accept them, or if the filter is very selective."
23
+ },
24
+ {
25
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_maxIterations",
26
+ "range": "xsd:number",
27
+ "default": "10",
28
+ "comment": "The maximum number of full iterations across the query can be done for attempting to push down filters."
29
+ },
30
+ {
31
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_splitConjunctive",
32
+ "range": "xsd:boolean",
33
+ "default": "true",
34
+ "comment": "If conjunctive filters should be split into nested filters before applying filter pushdown. This can enable pushing down deeper."
35
+ },
36
+ {
37
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_mergeConjunctive",
38
+ "range": "xsd:boolean",
39
+ "default": "true",
40
+ "comment": "If nested filters should be merged into conjunctive filters after applying filter pushdown."
41
+ },
42
+ {
43
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushIntoLeftJoins",
44
+ "range": "xsd:boolean",
45
+ "default": "true",
46
+ "comment": "If filters should be pushed into left-joins."
47
+ },
48
+ {
49
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushEqualityIntoPatterns",
50
+ "range": "xsd:boolean",
51
+ "default": "true",
52
+ "comment": "If simple equality filters should be pushed into patterns and paths. This only applies to equality filters with terms that are not literals that have no canonical lexical form."
53
+ },
18
54
  {
19
55
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_name",
20
56
  "range": "xsd:string",
@@ -102,6 +138,30 @@
102
138
  }
103
139
  ],
104
140
  "memberFields": [
141
+ {
142
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_aggressivePushdown",
143
+ "memberFieldName": "aggressivePushdown"
144
+ },
145
+ {
146
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_maxIterations",
147
+ "memberFieldName": "maxIterations"
148
+ },
149
+ {
150
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_splitConjunctive",
151
+ "memberFieldName": "splitConjunctive"
152
+ },
153
+ {
154
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_mergeConjunctive",
155
+ "memberFieldName": "mergeConjunctive"
156
+ },
157
+ {
158
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_pushIntoLeftJoins",
159
+ "memberFieldName": "pushIntoLeftJoins"
160
+ },
161
+ {
162
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_pushEqualityIntoPatterns",
163
+ "memberFieldName": "pushEqualityIntoPatterns"
164
+ },
105
165
  {
106
166
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_constructor",
107
167
  "memberFieldName": "constructor"
@@ -114,6 +174,14 @@
114
174
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_run",
115
175
  "memberFieldName": "run"
116
176
  },
177
+ {
178
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_shouldAttemptPushDown",
179
+ "memberFieldName": "shouldAttemptPushDown"
180
+ },
181
+ {
182
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_getSources",
183
+ "memberFieldName": "getSources"
184
+ },
117
185
  {
118
186
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_getExpressionVariables",
119
187
  "memberFieldName": "getExpressionVariables"
@@ -126,6 +194,14 @@
126
194
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_filterPushdown",
127
195
  "memberFieldName": "filterPushdown"
128
196
  },
197
+ {
198
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_getEqualityExpressionPushableIntoPattern",
199
+ "memberFieldName": "getEqualityExpressionPushableIntoPattern"
200
+ },
201
+ {
202
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_isLiteralWithCanonicalLexicalForm",
203
+ "memberFieldName": "isLiteralWithCanonicalLexicalForm"
204
+ },
129
205
  {
130
206
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_variablesIntersect",
131
207
  "memberFieldName": "variablesIntersect"
@@ -137,12 +213,52 @@
137
213
  {
138
214
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_isExpressionFalse",
139
215
  "memberFieldName": "isExpressionFalse"
216
+ },
217
+ {
218
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown__member_getNestedFilterExpressions",
219
+ "memberFieldName": "getNestedFilterExpressions"
140
220
  }
141
221
  ],
142
222
  "constructorArguments": [
143
223
  {
144
224
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args__constructorArgument",
145
225
  "fields": [
226
+ {
227
+ "keyRaw": "aggressivePushdown",
228
+ "value": {
229
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_aggressivePushdown"
230
+ }
231
+ },
232
+ {
233
+ "keyRaw": "maxIterations",
234
+ "value": {
235
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_maxIterations"
236
+ }
237
+ },
238
+ {
239
+ "keyRaw": "splitConjunctive",
240
+ "value": {
241
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_splitConjunctive"
242
+ }
243
+ },
244
+ {
245
+ "keyRaw": "mergeConjunctive",
246
+ "value": {
247
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_mergeConjunctive"
248
+ }
249
+ },
250
+ {
251
+ "keyRaw": "pushIntoLeftJoins",
252
+ "value": {
253
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushIntoLeftJoins"
254
+ }
255
+ },
256
+ {
257
+ "keyRaw": "pushEqualityIntoPatterns",
258
+ "value": {
259
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushEqualityIntoPatterns"
260
+ }
261
+ },
146
262
  {
147
263
  "keyRaw": "name",
148
264
  "value": {
@@ -164,6 +280,39 @@
164
280
  ]
165
281
  }
166
282
  ]
283
+ },
284
+ {
285
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs",
286
+ "@type": "AbstractClass",
287
+ "requireElement": "IActorOptimizeQueryOperationFilterPushdownArgs",
288
+ "parameters": [],
289
+ "memberFields": [
290
+ {
291
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs__member_aggressivePushdown",
292
+ "memberFieldName": "aggressivePushdown"
293
+ },
294
+ {
295
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs__member_maxIterations",
296
+ "memberFieldName": "maxIterations"
297
+ },
298
+ {
299
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs__member_splitConjunctive",
300
+ "memberFieldName": "splitConjunctive"
301
+ },
302
+ {
303
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs__member_mergeConjunctive",
304
+ "memberFieldName": "mergeConjunctive"
305
+ },
306
+ {
307
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs__member_pushIntoLeftJoins",
308
+ "memberFieldName": "pushIntoLeftJoins"
309
+ },
310
+ {
311
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs__member_pushEqualityIntoPatterns",
312
+ "memberFieldName": "pushEqualityIntoPatterns"
313
+ }
314
+ ],
315
+ "constructorArguments": []
167
316
  }
168
317
  ]
169
318
  }
@@ -8,6 +8,24 @@
8
8
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown",
9
9
  "@prefix": true,
10
10
  "@context": {
11
+ "args_aggressivePushdown": {
12
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_aggressivePushdown"
13
+ },
14
+ "args_maxIterations": {
15
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_maxIterations"
16
+ },
17
+ "args_splitConjunctive": {
18
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_splitConjunctive"
19
+ },
20
+ "args_mergeConjunctive": {
21
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_mergeConjunctive"
22
+ },
23
+ "args_pushIntoLeftJoins": {
24
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushIntoLeftJoins"
25
+ },
26
+ "args_pushEqualityIntoPatterns": {
27
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushEqualityIntoPatterns"
28
+ },
11
29
  "args_name": {
12
30
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_name"
13
31
  },
@@ -18,6 +36,24 @@
18
36
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_beforeActors",
19
37
  "@container": "@list"
20
38
  },
39
+ "aggressivePushdown": {
40
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_aggressivePushdown"
41
+ },
42
+ "maxIterations": {
43
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_maxIterations"
44
+ },
45
+ "splitConjunctive": {
46
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_splitConjunctive"
47
+ },
48
+ "mergeConjunctive": {
49
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_mergeConjunctive"
50
+ },
51
+ "pushIntoLeftJoins": {
52
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushIntoLeftJoins"
53
+ },
54
+ "pushEqualityIntoPatterns": {
55
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_pushEqualityIntoPatterns"
56
+ },
21
57
  "name": {
22
58
  "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#ActorOptimizeQueryOperationFilterPushdown_args_name"
23
59
  },
@@ -29,6 +65,11 @@
29
65
  "@container": "@list"
30
66
  }
31
67
  }
68
+ },
69
+ "IActorOptimizeQueryOperationFilterPushdownArgs": {
70
+ "@id": "caoqofp:components/ActorOptimizeQueryOperationFilterPushdown.jsonld#IActorOptimizeQueryOperationFilterPushdownArgs",
71
+ "@prefix": true,
72
+ "@context": {}
32
73
  }
33
74
  }
34
75
  ]
@@ -1,7 +1,7 @@
1
- import type { IActionOptimizeQueryOperation, IActorOptimizeQueryOperationOutput, IActorOptimizeQueryOperationArgs } from '@comunica/bus-optimize-query-operation';
1
+ import type { IActionOptimizeQueryOperation, IActorOptimizeQueryOperationArgs, IActorOptimizeQueryOperationOutput } from '@comunica/bus-optimize-query-operation';
2
2
  import { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';
3
3
  import type { IActorTest } from '@comunica/core';
4
- import type { IActionContext } from '@comunica/types';
4
+ import type { FragmentSelectorShape, IActionContext, IQuerySourceWrapper } from '@comunica/types';
5
5
  import type * as RDF from '@rdfjs/types';
6
6
  import type { Factory } from 'sparqlalgebrajs';
7
7
  import { Algebra } from 'sparqlalgebrajs';
@@ -9,9 +9,30 @@ import { Algebra } from 'sparqlalgebrajs';
9
9
  * A comunica Filter Pushdown Optimize Query Operation Actor.
10
10
  */
11
11
  export declare class ActorOptimizeQueryOperationFilterPushdown extends ActorOptimizeQueryOperation {
12
- constructor(args: IActorOptimizeQueryOperationArgs);
12
+ private readonly aggressivePushdown;
13
+ private readonly maxIterations;
14
+ private readonly splitConjunctive;
15
+ private readonly mergeConjunctive;
16
+ private readonly pushIntoLeftJoins;
17
+ private readonly pushEqualityIntoPatterns;
18
+ constructor(args: IActorOptimizeQueryOperationFilterPushdownArgs);
13
19
  test(_action: IActionOptimizeQueryOperation): Promise<IActorTest>;
14
20
  run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput>;
21
+ /**
22
+ * Check if the given filter operation must be attempted to push down, based on the following criteria:
23
+ * - Always push down if aggressive mode is enabled
24
+ * - Push down if the filter is extremely selective
25
+ * - Push down if federated and at least one accepts the filter
26
+ * @param operation The filter operation
27
+ * @param sources The query sources in the operation
28
+ * @param sourceShapes A mapping of sources to selector shapes.
29
+ */
30
+ shouldAttemptPushDown(operation: Algebra.Filter, sources: IQuerySourceWrapper[], sourceShapes: Map<IQuerySourceWrapper, FragmentSelectorShape>): boolean;
31
+ /**
32
+ * Collected all sources that are defined within the given operation of children recursively.
33
+ * @param operation An operation.
34
+ */
35
+ getSources(operation: Algebra.Operation): IQuerySourceWrapper[];
15
36
  /**
16
37
  * Get all variables inside the given expression.
17
38
  * @param expression An expression.
@@ -34,9 +55,28 @@ export declare class ActorOptimizeQueryOperationFilterPushdown extends ActorOpti
34
55
  * @param operation The operation to push down into.
35
56
  * @param factory An algebra factory.
36
57
  * @param context The action context.
37
- * @return The modified operation.
58
+ * @return A tuple indicating if the operation was modified and the modified operation.
59
+ */
60
+ filterPushdown(expression: Algebra.Expression, expressionVariables: RDF.Variable[], operation: Algebra.Operation, factory: Factory, context: IActionContext): [boolean, Algebra.Operation];
61
+ /**
62
+ * Check if the given expression is a simple equals operation with one variable and one non-literal
63
+ * (or literal with canonical lexical form) term that can be pushed into a pattern.
64
+ * @param expression The current expression.
65
+ * @return The variable and term to fill into the pattern, or undefined.
38
66
  */
39
- filterPushdown(expression: Algebra.Expression, expressionVariables: RDF.Variable[], operation: Algebra.Operation, factory: Factory, context: IActionContext): Algebra.Operation;
67
+ getEqualityExpressionPushableIntoPattern(expression: Algebra.Expression): {
68
+ variable: RDF.Variable;
69
+ term: RDF.Term;
70
+ } | undefined;
71
+ /**
72
+ * Check if the given term is a literal with datatype that where all values
73
+ * can only have one possible lexical representation.
74
+ * In other words, no variants of values exist that should be considered equal.
75
+ * For example: "01"^xsd:number and "1"^xsd:number will return false.
76
+ * @param term An RDF term.
77
+ * @protected
78
+ */
79
+ protected isLiteralWithCanonicalLexicalForm(term: RDF.Term): boolean;
40
80
  /**
41
81
  * Check if there is an overlap between the two given lists of variables.
42
82
  * @param varsA A list of variables.
@@ -55,4 +95,54 @@ export declare class ActorOptimizeQueryOperationFilterPushdown extends ActorOpti
55
95
  * @param expression An expression.
56
96
  */
57
97
  isExpressionFalse(expression: Algebra.Expression): boolean;
98
+ /**
99
+ * Get all directly nested filter expressions.
100
+ * As soon as a non-filter is found, it is returned as the input field.
101
+ * @param op A filter expression.
102
+ */
103
+ getNestedFilterExpressions(op: Algebra.Filter): {
104
+ nestedExpressions: Algebra.Expression[];
105
+ input: Algebra.Operation;
106
+ };
107
+ }
108
+ export interface IActorOptimizeQueryOperationFilterPushdownArgs extends IActorOptimizeQueryOperationArgs {
109
+ /**
110
+ * If filters should be pushed down as deep as possible.
111
+ * If false, filters will only be pushed down if the source(s) accept them,
112
+ * or if the filter is very selective.
113
+ * @range {boolean}
114
+ * @default {false}
115
+ */
116
+ aggressivePushdown: boolean;
117
+ /**
118
+ * The maximum number of full iterations across the query can be done for attempting to push down filters.
119
+ * @default {10}
120
+ */
121
+ maxIterations: number;
122
+ /**
123
+ * If conjunctive filters should be split into nested filters before applying filter pushdown.
124
+ * This can enable pushing down deeper.
125
+ * @range {boolean}
126
+ * @default {true}
127
+ */
128
+ splitConjunctive: boolean;
129
+ /**
130
+ * If nested filters should be merged into conjunctive filters after applying filter pushdown.
131
+ * @range {boolean}
132
+ * @default {true}
133
+ */
134
+ mergeConjunctive: boolean;
135
+ /**
136
+ * If filters should be pushed into left-joins.
137
+ * @range {boolean}
138
+ * @default {true}
139
+ */
140
+ pushIntoLeftJoins: boolean;
141
+ /**
142
+ * If simple equality filters should be pushed into patterns and paths.
143
+ * This only applies to equality filters with terms that are not literals that have no canonical lexical form.
144
+ * @range {boolean}
145
+ * @default {true}
146
+ */
147
+ pushEqualityIntoPatterns: boolean;
58
148
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ActorOptimizeQueryOperationFilterPushdown = void 0;
4
4
  const bus_optimize_query_operation_1 = require("@comunica/bus-optimize-query-operation");
5
+ const bus_query_operation_1 = require("@comunica/bus-query-operation");
5
6
  const rdf_terms_1 = require("rdf-terms");
6
7
  const sparqlalgebrajs_1 = require("sparqlalgebrajs");
7
8
  /**
@@ -15,21 +16,141 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
15
16
  return true;
16
17
  }
17
18
  async run(action) {
19
+ let operation = action.operation;
18
20
  // eslint-disable-next-line ts/no-this-alias
19
21
  const self = this;
20
- const operation = sparqlalgebrajs_1.Util.mapOperation(action.operation, {
21
- filter(op, factory) {
22
- // For all filter expressions in the operation,
23
- // we attempt to push them down as deep as possible into the algebra.
24
- const variables = self.getExpressionVariables(op.expression);
25
- return {
26
- recurse: true,
27
- result: self.filterPushdown(op.expression, variables, op.input, factory, action.context),
28
- };
29
- },
30
- });
22
+ // Split conjunctive filters into nested filters
23
+ if (this.splitConjunctive) {
24
+ operation = sparqlalgebrajs_1.Util.mapOperation(operation, {
25
+ filter(op, factory) {
26
+ // Split conjunctive filters into separate filters
27
+ if (op.expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.OPERATOR && op.expression.operator === '&&') {
28
+ self.logDebug(action.context, `Split conjunctive filter into ${op.expression.args.length} nested filters`);
29
+ return {
30
+ recurse: true,
31
+ result: op.expression.args
32
+ .reduce((operation, expression) => factory.createFilter(operation, expression), op.input),
33
+ };
34
+ }
35
+ return {
36
+ recurse: true,
37
+ result: op,
38
+ };
39
+ },
40
+ });
41
+ }
42
+ // Collect selector shapes of all operations
43
+ const sources = this.getSources(operation);
44
+ // eslint-disable-next-line ts/no-unnecessary-type-assertion
45
+ const sourceShapes = new Map(await Promise.all(sources
46
+ .map(async (source) => [source, await source.source.getSelectorShape(action.context)])));
47
+ // Push down all filters
48
+ // We loop until no more filters can be pushed down.
49
+ let repeat = true;
50
+ let iterations = 0;
51
+ while (repeat && iterations < this.maxIterations) {
52
+ repeat = false;
53
+ operation = sparqlalgebrajs_1.Util.mapOperation(operation, {
54
+ filter(op, factory) {
55
+ // Check if the filter must be pushed down
56
+ if (!self.shouldAttemptPushDown(op, sources, sourceShapes)) {
57
+ return {
58
+ recurse: true,
59
+ result: op,
60
+ };
61
+ }
62
+ // For all filter expressions in the operation,
63
+ // we attempt to push them down as deep as possible into the algebra.
64
+ const variables = self.getExpressionVariables(op.expression);
65
+ const [isModified, result] = self
66
+ .filterPushdown(op.expression, variables, op.input, factory, action.context);
67
+ if (isModified) {
68
+ repeat = true;
69
+ }
70
+ return {
71
+ recurse: true,
72
+ result,
73
+ };
74
+ },
75
+ });
76
+ iterations++;
77
+ }
78
+ if (iterations > 1) {
79
+ self.logDebug(action.context, `Pushed down filters in ${iterations} iterations`);
80
+ }
81
+ // Merge nested filters into conjunctive filters
82
+ if (this.mergeConjunctive) {
83
+ operation = sparqlalgebrajs_1.Util.mapOperation(operation, {
84
+ filter(op, factory) {
85
+ if (op.input.type === sparqlalgebrajs_1.Algebra.types.FILTER) {
86
+ const { nestedExpressions, input } = self.getNestedFilterExpressions(op);
87
+ self.logDebug(action.context, `Merge ${nestedExpressions.length} nested filters into conjunctive filter`);
88
+ return {
89
+ recurse: true,
90
+ result: factory.createFilter(input, nestedExpressions.slice(1).reduce((previous, current) => factory.createOperatorExpression('&&', [previous, current]), nestedExpressions[0])),
91
+ };
92
+ }
93
+ return {
94
+ recurse: true,
95
+ result: op,
96
+ };
97
+ },
98
+ });
99
+ }
31
100
  return { operation, context: action.context };
32
101
  }
102
+ /**
103
+ * Check if the given filter operation must be attempted to push down, based on the following criteria:
104
+ * - Always push down if aggressive mode is enabled
105
+ * - Push down if the filter is extremely selective
106
+ * - Push down if federated and at least one accepts the filter
107
+ * @param operation The filter operation
108
+ * @param sources The query sources in the operation
109
+ * @param sourceShapes A mapping of sources to selector shapes.
110
+ */
111
+ shouldAttemptPushDown(operation, sources, sourceShapes) {
112
+ // Always push down if aggressive mode is enabled
113
+ if (this.aggressivePushdown) {
114
+ return true;
115
+ }
116
+ // Push down if the filter is extremely selective
117
+ const expression = operation.expression;
118
+ if (expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.OPERATOR &&
119
+ expression.operator === '=' &&
120
+ ((expression.args[0].expressionType === 'term' && expression.args[0].term.termType !== 'Variable' &&
121
+ expression.args[1].expressionType === 'term' && expression.args[1].term.termType === 'Variable') ||
122
+ (expression.args[0].expressionType === 'term' && expression.args[0].term.termType === 'Variable' &&
123
+ expression.args[1].expressionType === 'term' && expression.args[1].term.termType !== 'Variable'))) {
124
+ return true;
125
+ }
126
+ // Push down if federated and at least one accepts the filter
127
+ if (sources.some(source => bus_query_operation_1.ActorQueryOperation.doesShapeAcceptOperation(sourceShapes.get(source), operation))) {
128
+ return true;
129
+ }
130
+ // Don't push down in all other cases
131
+ return false;
132
+ }
133
+ /**
134
+ * Collected all sources that are defined within the given operation of children recursively.
135
+ * @param operation An operation.
136
+ */
137
+ getSources(operation) {
138
+ const sources = new Set();
139
+ const sourceAdder = (subOperation) => {
140
+ const src = bus_query_operation_1.ActorQueryOperation.getOperationSource(subOperation);
141
+ if (src) {
142
+ sources.add(src);
143
+ }
144
+ return false;
145
+ };
146
+ sparqlalgebrajs_1.Util.recurseOperation(operation, {
147
+ [sparqlalgebrajs_1.Algebra.types.PATTERN]: sourceAdder,
148
+ [sparqlalgebrajs_1.Algebra.types.LINK]: sourceAdder,
149
+ [sparqlalgebrajs_1.Algebra.types.NPS]: sourceAdder,
150
+ [sparqlalgebrajs_1.Algebra.types.SERVICE]: sourceAdder,
151
+ });
152
+ return [...sources];
153
+ }
33
154
  /**
34
155
  * Get all variables inside the given expression.
35
156
  * @param expression An expression.
@@ -86,34 +207,44 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
86
207
  * @param operation The operation to push down into.
87
208
  * @param factory An algebra factory.
88
209
  * @param context The action context.
89
- * @return The modified operation.
210
+ * @return A tuple indicating if the operation was modified and the modified operation.
90
211
  */
91
212
  filterPushdown(expression, expressionVariables, operation, factory, context) {
213
+ // Void false expressions
92
214
  if (this.isExpressionFalse(expression)) {
93
- return factory.createUnion([]);
215
+ return [true, factory.createUnion([])];
216
+ }
217
+ // Don't push down (NOT) EXISTS
218
+ if (expression.type === sparqlalgebrajs_1.Algebra.types.EXPRESSION &&
219
+ expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.EXISTENCE) {
220
+ return [false, factory.createFilter(operation, expression)];
94
221
  }
95
222
  switch (operation.type) {
96
223
  case sparqlalgebrajs_1.Algebra.types.EXTEND:
97
224
  // Pass if the variable is not part of the expression
98
225
  if (!this.variablesIntersect([operation.variable], expressionVariables)) {
99
- return factory.createExtend(this.filterPushdown(expression, expressionVariables, operation.input, factory, context), operation.variable, operation.expression);
226
+ return [true, factory.createExtend(this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1], operation.variable, operation.expression)];
100
227
  }
101
- return factory.createFilter(operation, expression);
102
- case sparqlalgebrajs_1.Algebra.types.FILTER:
228
+ return [false, factory.createFilter(operation, expression)];
229
+ case sparqlalgebrajs_1.Algebra.types.FILTER: {
103
230
  // Always pass
104
- return factory.createFilter(this.filterPushdown(expression, expressionVariables, operation.input, factory, context), operation.expression);
231
+ const [isModified, result] = this
232
+ .filterPushdown(expression, expressionVariables, operation.input, factory, context);
233
+ return [isModified, factory.createFilter(result, operation.expression)];
234
+ }
105
235
  case sparqlalgebrajs_1.Algebra.types.JOIN: {
106
236
  // Don't push down for empty join
107
237
  if (operation.input.length === 0) {
108
- return factory.createFilter(operation, expression);
238
+ return [false, factory.createFilter(operation, expression)];
109
239
  }
110
240
  // Determine overlapping operations
111
241
  const { fullyOverlapping, partiallyOverlapping, notOverlapping, } = this.getOverlappingOperations(operation, expressionVariables);
112
242
  const joins = [];
113
- this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
243
+ let isModified = false;
114
244
  if (fullyOverlapping.length > 0) {
245
+ isModified = true;
115
246
  joins.push(factory.createJoin(fullyOverlapping
116
- .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context))));
247
+ .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));
117
248
  }
118
249
  if (partiallyOverlapping.length > 0) {
119
250
  joins.push(factory.createFilter(factory.createJoin(partiallyOverlapping, false), expression));
@@ -121,25 +252,32 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
121
252
  if (notOverlapping.length > 0) {
122
253
  joins.push(...notOverlapping);
123
254
  }
124
- return joins.length === 1 ? joins[0] : factory.createJoin(joins);
255
+ if (joins.length > 1) {
256
+ isModified = true;
257
+ }
258
+ if (isModified) {
259
+ this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
260
+ }
261
+ return [isModified, joins.length === 1 ? joins[0] : factory.createJoin(joins)];
125
262
  }
126
263
  case sparqlalgebrajs_1.Algebra.types.NOP:
127
- return operation;
264
+ return [true, operation];
128
265
  case sparqlalgebrajs_1.Algebra.types.PROJECT:
129
266
  // Push down if variables overlap
130
267
  if (this.variablesIntersect(operation.variables, expressionVariables)) {
131
- return factory.createProject(this.filterPushdown(expression, expressionVariables, operation.input, factory, context), operation.variables);
268
+ return [true, factory.createProject(this.filterPushdown(expression, expressionVariables, operation.input, factory, context)[1], operation.variables)];
132
269
  }
133
270
  // Void expression otherwise
134
- return operation;
271
+ return [true, operation];
135
272
  case sparqlalgebrajs_1.Algebra.types.UNION: {
136
273
  // Determine overlapping operations
137
274
  const { fullyOverlapping, partiallyOverlapping, notOverlapping, } = this.getOverlappingOperations(operation, expressionVariables);
138
275
  const unions = [];
139
- this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
276
+ let isModified = false;
140
277
  if (fullyOverlapping.length > 0) {
278
+ isModified = true;
141
279
  unions.push(factory.createUnion(fullyOverlapping
142
- .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context))));
280
+ .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context)[1])));
143
281
  }
144
282
  if (partiallyOverlapping.length > 0) {
145
283
  unions.push(factory.createFilter(factory.createUnion(partiallyOverlapping, false), expression));
@@ -147,15 +285,73 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
147
285
  if (notOverlapping.length > 0) {
148
286
  unions.push(...notOverlapping);
149
287
  }
150
- return unions.length === 1 ? unions[0] : factory.createUnion(unions);
288
+ if (unions.length > 1) {
289
+ isModified = true;
290
+ }
291
+ if (isModified) {
292
+ this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);
293
+ }
294
+ return [isModified, unions.length === 1 ? unions[0] : factory.createUnion(unions)];
151
295
  }
152
296
  case sparqlalgebrajs_1.Algebra.types.VALUES:
153
297
  // Only keep filter if it overlaps with the variables
154
298
  if (this.variablesIntersect(operation.variables, expressionVariables)) {
155
- return factory.createFilter(operation, expression);
299
+ return [false, factory.createFilter(operation, expression)];
156
300
  }
157
- return operation;
158
- case sparqlalgebrajs_1.Algebra.types.LEFT_JOIN:
301
+ return [true, operation];
302
+ case sparqlalgebrajs_1.Algebra.types.LEFT_JOIN: {
303
+ if (this.pushIntoLeftJoins) {
304
+ const rightVariables = sparqlalgebrajs_1.Util.inScopeVariables(operation.input[1]);
305
+ if (!this.variablesIntersect(expressionVariables, rightVariables)) {
306
+ // If filter *only* applies to left entry of optional, push it down into that.
307
+ this.logDebug(context, `Push down filter into left join`);
308
+ return [true, factory.createLeftJoin(this.filterPushdown(expression, expressionVariables, operation.input[0], factory, context)[1], operation.input[1], operation.expression)];
309
+ }
310
+ }
311
+ // Don't push down in all other cases
312
+ return [false, factory.createFilter(operation, expression)];
313
+ }
314
+ case sparqlalgebrajs_1.Algebra.types.PATTERN: {
315
+ if (this.pushEqualityIntoPatterns) {
316
+ // Try to push simple FILTER(?s = <iri>) expressions into the pattern
317
+ const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);
318
+ if (pushableResult) {
319
+ let isModified = false;
320
+ const originalMetadata = operation.metadata;
321
+ operation = (0, rdf_terms_1.mapTermsNested)(operation, (value) => {
322
+ if (value.equals(pushableResult.variable)) {
323
+ isModified = true;
324
+ return pushableResult.term;
325
+ }
326
+ return value;
327
+ });
328
+ operation.type = sparqlalgebrajs_1.Algebra.types.PATTERN;
329
+ operation.metadata = originalMetadata;
330
+ if (isModified) {
331
+ this.logDebug(context, `Push down filter into pattern for ?${pushableResult.variable.value}`);
332
+ return [true, operation];
333
+ }
334
+ }
335
+ }
336
+ // Don't push down in all other cases
337
+ return [false, factory.createFilter(operation, expression)];
338
+ }
339
+ case sparqlalgebrajs_1.Algebra.types.PATH: {
340
+ if (this.pushEqualityIntoPatterns) {
341
+ // Try to push simple FILTER(?s = <iri>) expressions into the path
342
+ const pushableResult = this.getEqualityExpressionPushableIntoPattern(expression);
343
+ if (pushableResult &&
344
+ (operation.subject.equals(pushableResult.variable) || operation.object.equals(pushableResult.variable))) {
345
+ this.logDebug(context, `Push down filter into path for ?${pushableResult.variable.value}`);
346
+ const originalMetadata = operation.metadata;
347
+ operation = factory.createPath(operation.subject.equals(pushableResult.variable) ? pushableResult.term : operation.subject, operation.predicate, operation.object.equals(pushableResult.variable) ? pushableResult.term : operation.object);
348
+ operation.metadata = originalMetadata;
349
+ return [true, operation];
350
+ }
351
+ }
352
+ // Don't push down in all other cases
353
+ return [false, factory.createFilter(operation, expression)];
354
+ }
159
355
  case sparqlalgebrajs_1.Algebra.types.MINUS:
160
356
  case sparqlalgebrajs_1.Algebra.types.ALT:
161
357
  case sparqlalgebrajs_1.Algebra.types.ASK:
@@ -172,12 +368,10 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
172
368
  case sparqlalgebrajs_1.Algebra.types.NPS:
173
369
  case sparqlalgebrajs_1.Algebra.types.ONE_OR_MORE_PATH:
174
370
  case sparqlalgebrajs_1.Algebra.types.ORDER_BY:
175
- case sparqlalgebrajs_1.Algebra.types.PATTERN:
176
371
  case sparqlalgebrajs_1.Algebra.types.REDUCED:
177
372
  case sparqlalgebrajs_1.Algebra.types.SEQ:
178
373
  case sparqlalgebrajs_1.Algebra.types.SERVICE:
179
374
  case sparqlalgebrajs_1.Algebra.types.SLICE:
180
- case sparqlalgebrajs_1.Algebra.types.PATH:
181
375
  case sparqlalgebrajs_1.Algebra.types.ZERO_OR_MORE_PATH:
182
376
  case sparqlalgebrajs_1.Algebra.types.ZERO_OR_ONE_PATH:
183
377
  case sparqlalgebrajs_1.Algebra.types.COMPOSITE_UPDATE:
@@ -191,9 +385,64 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
191
385
  case sparqlalgebrajs_1.Algebra.types.COPY:
192
386
  // Operations that do not support pushing down
193
387
  // Left-join and minus might be possible to support in the future.
194
- return factory.createFilter(operation, expression);
388
+ return [false, factory.createFilter(operation, expression)];
195
389
  }
196
390
  }
391
+ /**
392
+ * Check if the given expression is a simple equals operation with one variable and one non-literal
393
+ * (or literal with canonical lexical form) term that can be pushed into a pattern.
394
+ * @param expression The current expression.
395
+ * @return The variable and term to fill into the pattern, or undefined.
396
+ */
397
+ getEqualityExpressionPushableIntoPattern(expression) {
398
+ if (expression.expressionType === sparqlalgebrajs_1.Algebra.expressionTypes.OPERATOR && expression.operator === '=') {
399
+ if (expression.args[0].expressionType === 'term' && expression.args[0].term.termType !== 'Variable' &&
400
+ (expression.args[0].term.termType !== 'Literal' ||
401
+ this.isLiteralWithCanonicalLexicalForm(expression.args[0].term)) &&
402
+ expression.args[1].expressionType === 'term' && expression.args[1].term.termType === 'Variable') {
403
+ return {
404
+ variable: expression.args[1].term,
405
+ term: expression.args[0].term,
406
+ };
407
+ }
408
+ if (expression.args[0].expressionType === 'term' && expression.args[0].term.termType === 'Variable' &&
409
+ expression.args[1].expressionType === 'term' && expression.args[1].term.termType !== 'Variable' &&
410
+ (expression.args[1].term.termType !== 'Literal' ||
411
+ this.isLiteralWithCanonicalLexicalForm(expression.args[1].term))) {
412
+ return {
413
+ variable: expression.args[0].term,
414
+ term: expression.args[1].term,
415
+ };
416
+ }
417
+ }
418
+ }
419
+ /**
420
+ * Check if the given term is a literal with datatype that where all values
421
+ * can only have one possible lexical representation.
422
+ * In other words, no variants of values exist that should be considered equal.
423
+ * For example: "01"^xsd:number and "1"^xsd:number will return false.
424
+ * @param term An RDF term.
425
+ * @protected
426
+ */
427
+ isLiteralWithCanonicalLexicalForm(term) {
428
+ if (term.termType === 'Literal') {
429
+ switch (term.datatype.value) {
430
+ case 'http://www.w3.org/2001/XMLSchema#string':
431
+ case 'http://www.w3.org/1999/02/22-rdf-syntax-ns#langString':
432
+ case 'http://www.w3.org/2001/XMLSchema#normalizedString':
433
+ case 'http://www.w3.org/2001/XMLSchema#anyURI':
434
+ case 'http://www.w3.org/2001/XMLSchema#base64Binary':
435
+ case 'http://www.w3.org/2001/XMLSchema#language':
436
+ case 'http://www.w3.org/2001/XMLSchema#Name':
437
+ case 'http://www.w3.org/2001/XMLSchema#NCName':
438
+ case 'http://www.w3.org/2001/XMLSchema#NMTOKEN':
439
+ case 'http://www.w3.org/2001/XMLSchema#token':
440
+ case 'http://www.w3.org/2001/XMLSchema#hexBinary':
441
+ return true;
442
+ }
443
+ }
444
+ return false;
445
+ }
197
446
  /**
198
447
  * Check if there is an overlap between the two given lists of variables.
199
448
  * @param varsA A list of variables.
@@ -219,6 +468,18 @@ class ActorOptimizeQueryOperationFilterPushdown extends bus_optimize_query_opera
219
468
  isExpressionFalse(expression) {
220
469
  return (expression.term && expression.term.termType === 'Literal' && expression.term.value === 'false');
221
470
  }
471
+ /**
472
+ * Get all directly nested filter expressions.
473
+ * As soon as a non-filter is found, it is returned as the input field.
474
+ * @param op A filter expression.
475
+ */
476
+ getNestedFilterExpressions(op) {
477
+ if (op.input.type === sparqlalgebrajs_1.Algebra.types.FILTER) {
478
+ const childData = this.getNestedFilterExpressions(op.input);
479
+ return { nestedExpressions: [op.expression, ...childData.nestedExpressions], input: childData.input };
480
+ }
481
+ return { nestedExpressions: [op.expression], input: op.input };
482
+ }
222
483
  }
223
484
  exports.ActorOptimizeQueryOperationFilterPushdown = ActorOptimizeQueryOperationFilterPushdown;
224
485
  //# sourceMappingURL=ActorOptimizeQueryOperationFilterPushdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ActorOptimizeQueryOperationFilterPushdown.js","sourceRoot":"","sources":["ActorOptimizeQueryOperationFilterPushdown.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n IActionOptimizeQueryOperation,\n IActorOptimizeQueryOperationOutput,\n IActorOptimizeQueryOperationArgs,\n} from '@comunica/bus-optimize-query-operation';\nimport { ActorOptimizeQueryOperation } from '@comunica/bus-optimize-query-operation';\nimport type { IActorTest } from '@comunica/core';\nimport type { IActionContext } from '@comunica/types';\nimport type * as RDF from '@rdfjs/types';\nimport { uniqTerms } from 'rdf-terms';\nimport type { Factory } from 'sparqlalgebrajs';\nimport { Algebra, Util } from 'sparqlalgebrajs';\n\n/**\n * A comunica Filter Pushdown Optimize Query Operation Actor.\n */\nexport class ActorOptimizeQueryOperationFilterPushdown extends ActorOptimizeQueryOperation {\n public constructor(args: IActorOptimizeQueryOperationArgs) {\n super(args);\n }\n\n public async test(_action: IActionOptimizeQueryOperation): Promise<IActorTest> {\n return true;\n }\n\n public async run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput> {\n // eslint-disable-next-line ts/no-this-alias\n const self = this;\n const operation = Util.mapOperation(action.operation, {\n filter(op: Algebra.Filter, factory: Factory) {\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 = self.getExpressionVariables(op.expression);\n return {\n recurse: true,\n result: self.filterPushdown(op.expression, variables, op.input, factory, action.context),\n };\n },\n });\n return { operation, context: action.context };\n }\n\n /**\n * Get all variables inside the given expression.\n * @param expression An expression.\n * @return An array of variables, or undefined if the expression is unsupported for pushdown.\n */\n public getExpressionVariables(expression: Algebra.Expression): RDF.Variable[] {\n switch (expression.expressionType) {\n case Algebra.expressionTypes.AGGREGATE:\n case Algebra.expressionTypes.WILDCARD:\n throw new Error(`Getting expression variables is not supported for ${expression.expressionType}`);\n case Algebra.expressionTypes.EXISTENCE:\n return Util.inScopeVariables(expression.input);\n case Algebra.expressionTypes.NAMED:\n return [];\n case Algebra.expressionTypes.OPERATOR:\n return uniqTerms(expression.args.flatMap(arg => this.getExpressionVariables(arg)));\n case Algebra.expressionTypes.TERM:\n if (expression.term.termType === 'Variable') {\n return [ expression.term ];\n }\n return [];\n }\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 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 ): Algebra.Operation {\n if (this.isExpressionFalse(expression)) {\n return factory.createUnion([]);\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 factory.createExtend(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context),\n operation.variable,\n operation.expression,\n );\n }\n return factory.createFilter(operation, expression);\n case Algebra.types.FILTER:\n // Always pass\n return factory.createFilter(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context),\n operation.expression,\n );\n case Algebra.types.JOIN: {\n // Don't push down for empty join\n if (operation.input.length === 0) {\n return 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 this.logDebug(context, `Push down filter across join entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);\n if (fullyOverlapping.length > 0) {\n joins.push(factory.createJoin(fullyOverlapping\n .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context))));\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 return joins.length === 1 ? joins[0] : factory.createJoin(joins);\n }\n case Algebra.types.NOP:\n return operation;\n case Algebra.types.PROJECT:\n // Push down if variables overlap\n if (this.variablesIntersect(operation.variables, expressionVariables)) {\n return factory.createProject(\n this.filterPushdown(expression, expressionVariables, operation.input, factory, context),\n operation.variables,\n );\n }\n // Void expression otherwise\n return 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 this.logDebug(context, `Push down filter across union entries with ${fullyOverlapping.length} fully overlapping, ${partiallyOverlapping.length} partially overlapping, and ${notOverlapping.length} not overlapping`);\n if (fullyOverlapping.length > 0) {\n unions.push(factory.createUnion(fullyOverlapping\n .map(input => this.filterPushdown(expression, expressionVariables, input, factory, context))));\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 return 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 factory.createFilter(operation, expression);\n }\n return operation;\n case Algebra.types.LEFT_JOIN:\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.PATTERN:\n case Algebra.types.REDUCED:\n case Algebra.types.SEQ:\n case Algebra.types.SERVICE:\n case Algebra.types.SLICE:\n case Algebra.types.PATH:\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 factory.createFilter(operation, expression);\n }\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"]}
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 { ActorQueryOperation } from '@comunica/bus-query-operation';\nimport type { IActorTest } from '@comunica/core';\nimport type { FragmentSelectorShape, IActionContext, IQuerySourceWrapper } from '@comunica/types';\nimport type * as RDF from '@rdfjs/types';\nimport { mapTermsNested, uniqTerms } from 'rdf-terms';\nimport type { Factory } from 'sparqlalgebrajs';\nimport { 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<IActorTest> {\n return true;\n }\n\n public async run(action: IActionOptimizeQueryOperation): Promise<IActorOptimizeQueryOperationOutput> {\n let operation: Algebra.Operation = action.operation;\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 });\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 if (!self.shouldAttemptPushDown(op, sources, sourceShapes)) {\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 = self.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 * - 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 */\n public shouldAttemptPushDown(\n operation: Algebra.Filter,\n sources: IQuerySourceWrapper[],\n sourceShapes: Map<IQuerySourceWrapper, FragmentSelectorShape>,\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 // Push down if federated and at least one accepts the filter\n if (sources.some(source => ActorQueryOperation.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 = ActorQueryOperation.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 /**\n * Get all variables inside the given expression.\n * @param expression An expression.\n * @return An array of variables, or undefined if the expression is unsupported for pushdown.\n */\n public getExpressionVariables(expression: Algebra.Expression): RDF.Variable[] {\n switch (expression.expressionType) {\n case Algebra.expressionTypes.AGGREGATE:\n case Algebra.expressionTypes.WILDCARD:\n throw new Error(`Getting expression variables is not supported for ${expression.expressionType}`);\n case Algebra.expressionTypes.EXISTENCE:\n return Util.inScopeVariables(expression.input);\n case Algebra.expressionTypes.NAMED:\n return [];\n case Algebra.expressionTypes.OPERATOR:\n return uniqTerms(expression.args.flatMap(arg => this.getExpressionVariables(arg)));\n case Algebra.expressionTypes.TERM:\n if (expression.term.termType === 'Variable') {\n return [ expression.term ];\n }\n return [];\n }\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.type === Algebra.types.EXPRESSION &&\n 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, operation ];\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, operation ];\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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comunica/actor-optimize-query-operation-filter-pushdown",
3
- "version": "3.2.1",
3
+ "version": "3.2.2",
4
4
  "description": "A filter-pushdown optimize-query-operation actor",
5
5
  "lsd:module": true,
6
6
  "license": "MIT",
@@ -38,11 +38,12 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@comunica/bus-optimize-query-operation": "^3.2.1",
41
+ "@comunica/bus-query-operation": "^3.2.2",
41
42
  "@comunica/core": "^3.2.1",
42
43
  "@comunica/types": "^3.2.1",
43
44
  "@rdfjs/types": "*",
44
45
  "rdf-terms": "^1.11.0",
45
46
  "sparqlalgebrajs": "^4.3.7"
46
47
  },
47
- "gitHead": "f558377c3cefbd1606c51ede80440b862e7dda4f"
48
+ "gitHead": "fbcc3a81f87738633ddf69ede5ca504236f7edd9"
48
49
  }