Issue #46: Add clause propagation

Signed-off-by: Lucas Fernandes de Oliveira's avatarLucas Fernandes de Oliveira <lfo14@inf.ufpr.br>
parent 4d5adf56
Pipeline #12194 passed with stage
in 50 seconds
......@@ -357,4 +357,23 @@ describe("postgres adapter", () => {
done();
});
});
it("should get data from view when joins can be propagated", (done) => {
let view = adapterScenario.propagatedClauseView;
adapter.getDataFromView(view, (err, result) => {
expect(err).to.be.a("null");
expect(result).to.be.an("array");
expect(result).to.have.length(2);
expect(result[0]).to.be.an("object");
let keys: string[] = [];
keys = keys.concat(view.metrics.map((item) => item.name));
keys = keys.concat(view.dimensions.map((item) => item.name));
result.forEach((row) => {
expect(row).to.be.an("object");
expect(row).to.have.all.keys(keys);
});
done();
});
});
});
......@@ -112,6 +112,7 @@ export class PostgresAdapter extends Adapter {
Partial Join represents how many sources still exists,
every join reduces this number.
*/
let clausesToCover = view.clauses.map((i) => i);
while (partialJoin.length > 1) {
/*
Variable map finds what dimenensions are still needed to
......@@ -158,6 +159,17 @@ export class PostgresAdapter extends Adapter {
}
}
/*
Also mark scores for dimensions inside clauses
*/
for (let i = 0; i < clausesToCover.length; ++i) {
for (let j = 0; j < clausesToCover[i].targets.length; ++j) {
if (map[clausesToCover[i].targets[j].name]) {
++map[clausesToCover[i].targets[j].name];
}
}
}
for (let i = 0; i < partialJoin.length; ++i) {
const dims = partialJoin[i].dimensions.filter((item) => {
return map[item.name] > 1;
......@@ -171,13 +183,32 @@ export class PostgresAdapter extends Adapter {
again, with less dimensions, removing this dimension
from the view.
*/
if (dims.length < partialJoin[i].dimensions.length) {
let coveredClauses: Clause[] = [];
let notCoveredClauses: Clause[] = [];
/*
If all dimensions in a clause are a sub set of the
dimensions of a view, this clause is apllied now,
propagating the clause to this point.
Then this clause is removed from the set of clauses
*/
for (let j = 0; j < clausesToCover.length; ++j) {
if (clausesToCover[j].isCovered(partialJoin[i].dimensions)) {
coveredClauses.push(clausesToCover[j]);
}
else {
notCoveredClauses.push(clausesToCover[j]);
}
}
clausesToCover = notCoveredClauses;
if (dims.length < partialJoin[i].dimensions.length || coveredClauses.length > 0) {
const partial = new View({
metrics: partialJoin[i].metrics,
dimensions: dims,
keys: keys,
origin: false,
clauses: partialJoin[i].clauses,
clauses: coveredClauses.concat(partialJoin[i].clauses),
materialized: false
});
const from = "(" +
......
......@@ -20,6 +20,8 @@
import { Filter } from "./filter";
import { Hash } from "../util/hash";
import { Dimension } from "./dimension";
import { Metric } from "./metric";
export interface ClauseOptions {
filters: Filter[];
......@@ -28,11 +30,29 @@ export interface ClauseOptions {
export class Clause {
public readonly id: string;
public readonly filters: Filter[];
public readonly targets: (Metric|Dimension)[];
constructor (options: ClauseOptions) {
this.filters = options.filters;
this.filters = options.filters.map((i) => i);
const t = this.filters.map((i) => i.target).sort((a, b) => {
return (a.name < b.name) ? -1 : 1;
});
if (t.length > 0) {
this.targets = [t[0]];
for (let i = 1; i < t.length; ++i) {
if (t[i - 1] !== t[i]) {
this.targets.push(t[i]);
}
}
}
else {
this.targets = [];
}
const filtersIds = this.filters.map((item) => item.id);
this.id = Hash.sha1(filtersIds.sort());
}
public isCovered(coverage: (Metric|Dimension)[]): boolean {
return coverage.every((i) => this.targets.some((j) => i.name === j.name));
}
}
......@@ -54,6 +54,7 @@ interface AdapterScenario {
notOriginCount: View;
unMaterializebleView: View;
partialJoinView: View;
propagatedClauseView: View;
}
interface DataCtrlScenario {
......@@ -117,6 +118,11 @@ const filters: { [key: string]: Filter } = {
operator: FilterOperator.NOTEQUAL,
value: "1"
}),
"dim:4" : new Filter({
target: dims[4],
operator: FilterOperator.NOTEQUAL,
value: "dim:4:1"
}),
"dim:5" : new Filter({
target: dims[5],
operator: FilterOperator.NOTEQUAL,
......@@ -137,6 +143,7 @@ const clauses: { [key: string]: Clause } = {
"view0le": new Clause({filters: [filters["dim:0:le"]]}),
"view0dim0": new Clause({filters: [filters["dim:0:0"], filters["dim:0:1"]]}),
"view9dim2": new Clause({filters: [filters["dim:2"]]}),
"view6dim4": new Clause({filters: [filters["dim:4"]]}),
"view7dim5": new Clause({filters: [filters["dim:5"]]})
};
......@@ -348,6 +355,15 @@ const partialJoinView = new View({
childViews: [views[3], views[5], views[6]]
});
const propagatedClauseView = new View({
metrics: [mets[8]],
dimensions: [dims[4]],
materialized: false,
origin: false,
childViews: [views[6], views[7]],
clauses: [clauses.view7dim5, clauses.view6dim4]
});
export const engineScenario: EngineScenario = {
metrics: mets,
dimensions: dims,
......@@ -374,7 +390,8 @@ export const adapterScenario: AdapterScenario = {
notMatchFilterView: notMatchFilterView,
notOriginCount: notOriginCount,
unMaterializebleView: unMaterializebleView,
partialJoinView: partialJoinView
partialJoinView: partialJoinView,
propagatedClauseView: propagatedClauseView
};
export const dataCtrlScenario: DataCtrlScenario = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment