Commit 81b6b0eb authored by Lucas Fernandes de Oliveira's avatar Lucas Fernandes de Oliveira

Merge branch 'issue/33' into 'master'

Issue #33: Improve filter matching

See merge request !39
parents ffa8f933 f5050d55
Pipeline #12451 passed with stage
in 46 seconds
......@@ -382,7 +382,7 @@ describe("postgres adapter", () => {
adapter.getDataFromView(view, (err, result) => {
expect(err).to.be.a("null");
expect(result).to.be.an("array");
expect(result).to.have.length(8);
expect(result).to.have.length(4);
expect(result[0]).to.be.an("object");
let keys: string[] = [];
keys = keys.concat(view.metrics.map((item) => item.name));
......
......@@ -53,6 +53,6 @@ export class Clause {
}
public isCovered(coverage: (Metric|Dimension)[]): boolean {
return coverage.every((i) => this.targets.some((j) => i.name === j.name));
return this.targets.every((i) => coverage.some((j) => i.name === j.name));
}
}
......@@ -416,4 +416,243 @@ describe("graph class", () => {
expect(children.every((item) => item.id !== view3.id)).to.be.true;
});
it("should cover the query, using filters of intervals", () => {
let dims = [
new Dimension({name: "dim:0", dataType: "float"}),
new Dimension({name: "dim:1", dataType: "float"}),
new Dimension({name: "dim:2", dataType: "date"}),
];
const filters = [
new Filter({
target: dims[0],
operator: FilterOperator.GREATEREQ,
value: "0"
}),
new Filter({
target: dims[0],
operator: FilterOperator.LOWER,
value: "10"
}),
new Filter({
target: dims[1],
operator: FilterOperator.GREATER,
value: "0"
}),
new Filter({
target: dims[1],
operator: FilterOperator.LOWEREQ,
value: "10"
}),
new Filter({
target: dims[2],
operator: FilterOperator.GREATEREQ,
value: "0"
}),
new Filter({
target: dims[2],
operator: FilterOperator.LOWER,
value: "10"
})
];
const clauses = [
new Clause({filters: [filters[0]]}),
new Clause({filters: [filters[1]]}),
new Clause({filters: [filters[2]]}),
new Clause({filters: [filters[3]]}),
new Clause({filters: [filters[4]]}),
new Clause({filters: [filters[5]]}),
];
const filtersTest = [
new Filter({
target: dims[0],
operator: FilterOperator.GREATER,
value: "1"
}),
new Filter({
target: dims[0],
operator: FilterOperator.LOWEREQ,
value: "9"
}),
new Filter({
target: dims[1],
operator: FilterOperator.GREATEREQ,
value: "1"
}),
new Filter({
target: dims[1],
operator: FilterOperator.LOWER,
value: "9"
}),
new Filter({
target: dims[2],
operator: FilterOperator.GREATER,
value: "1"
}),
new Filter({
target: dims[2],
operator: FilterOperator.LOWEREQ,
value: "9"
})
];
const testClauses = [
new Clause({filters: [filtersTest[0]]}),
new Clause({filters: [filtersTest[1]]}),
new Clause({filters: [filtersTest[2]]}),
new Clause({filters: [filtersTest[3]]}),
new Clause({filters: [filtersTest[4]]}),
new Clause({filters: [filtersTest[5]]}),
];
let g = new Graph();
for (let i = 0; i < 3; ++i) {
expect(g.addDimension(dims[i])).to.be.true;
}
let view0 = new View({
metrics: [],
dimensions: dims,
origin: false,
materialized: true,
clauses: clauses
});
expect(g.addView(view0)).to.be.true;
const query: Query = { metrics: [], dimensions: dims, clauses: testClauses };
let children = g.cover(query);
expect(children).to.have.length(1);
expect(children[0].id === view0.id).to.be.true;
});
it("should cover the query, not using filters of intervals", () => {
let dims = [
new Dimension({name: "dim:0", dataType: "float"}),
new Dimension({name: "dim:1", dataType: "float"}),
new Dimension({name: "dim:2", dataType: "date"}),
];
const filters = [
new Filter({
target: dims[0],
operator: FilterOperator.GREATEREQ,
value: "10"
}),
new Filter({
target: dims[0],
operator: FilterOperator.LOWER,
value: "0"
}),
new Filter({
target: dims[1],
operator: FilterOperator.GREATER,
value: "10"
}),
new Filter({
target: dims[1],
operator: FilterOperator.LOWEREQ,
value: "0"
}),
new Filter({
target: dims[2],
operator: FilterOperator.GREATEREQ,
value: "10"
}),
new Filter({
target: dims[2],
operator: FilterOperator.LOWER,
value: "0"
})
];
const clauses = [
new Clause({filters: [filters[0]]}),
new Clause({filters: [filters[1]]}),
new Clause({filters: [filters[2]]}),
new Clause({filters: [filters[3]]}),
new Clause({filters: [filters[4]]}),
new Clause({filters: [filters[5]]}),
];
const filtersTest = [
new Filter({
target: dims[0],
operator: FilterOperator.GREATER,
value: "0"
}),
new Filter({
target: dims[0],
operator: FilterOperator.LOWEREQ,
value: "10"
}),
new Filter({
target: dims[1],
operator: FilterOperator.GREATEREQ,
value: "0"
}),
new Filter({
target: dims[1],
operator: FilterOperator.LOWER,
value: "11"
}),
new Filter({
target: dims[2],
operator: FilterOperator.GREATER,
value: "0"
}),
new Filter({
target: dims[2],
operator: FilterOperator.LOWEREQ,
value: "10"
})
];
const testClauses = [
new Clause({filters: [filtersTest[0]]}),
new Clause({filters: [filtersTest[1]]}),
new Clause({filters: [filtersTest[2]]}),
new Clause({filters: [filtersTest[3]]}),
new Clause({filters: [filtersTest[4]]}),
new Clause({filters: [filtersTest[5]]}),
];
let g = new Graph();
for (let i = 0; i < 3; ++i) {
expect(g.addDimension(dims[i])).to.be.true;
}
let views = [
new View({
metrics: [],
dimensions: dims,
origin: false,
materialized: true
})
];
for (let i = 0; i < testClauses.length; ++i) {
views.push(new View({
metrics: [],
dimensions: dims,
origin: false,
materialized: true,
clauses: [clauses[i]]
}));
}
for (let i = 0; i < views.length; ++i) {
expect(g.addView(views[i])).to.be.true;
}
const query: Query = { metrics: [], dimensions: dims, clauses: testClauses };
let children = g.cover(query);
expect(children).to.have.length(1);
expect(children[0].id === views[0].id).to.be.true;
});
});
......@@ -23,6 +23,7 @@ import { Metric } from "../core/metric";
import { Dimension } from "../core/dimension";
import { Query } from "../common/query";
import { Clause } from "../core/clause";
import { FilterOperator } from "../core/filter";
enum State {
UNVISITED,
......@@ -521,7 +522,7 @@ export class Graph {
/*
Check if a set of filter/clauses of a view suits for the query
*/
private passConstraints(constraints: Clause[], target: Clause[]) {
private passConstraints(queryClauses: Clause[], viewClauses: Clause[]) {
/*
TODO: Enhance constraint check.
......@@ -533,7 +534,65 @@ export class Graph {
only means that a more inneficient view must be choosen.
*/
return target.every((item) => constraints.some((c) => c.id === item.id));
return viewClauses.every((view) => queryClauses.some((query) => {
if (view.id === query.id) {
return true;
}
else if (query.filters.length === 1 && view.filters.length === 1) {
let queryFilter = query.filters[0];
let viewFilter = view.filters[0];
if (queryFilter.target.name !== viewFilter.target.name) {
return false;
}
let queryValue: number;
let viewValue: number;
if (queryFilter.target.dataType === "date") {
queryValue = new Date(queryFilter.value).getTime();
viewValue = new Date(viewFilter.value).getTime();
}
else {
queryValue = parseFloat(queryFilter.value);
viewValue = parseFloat(viewFilter.value);
}
if (viewFilter.operator === FilterOperator.GREATEREQ &&
queryValue >= viewValue ) {
if (queryFilter.operator === FilterOperator.GREATER ||
queryFilter.operator === FilterOperator.GREATEREQ) {
return true;
}
}
else if (viewFilter.operator === FilterOperator.GREATER &&
queryValue > viewValue ) {
if (queryFilter.operator === FilterOperator.GREATER ||
queryFilter.operator === FilterOperator.GREATEREQ) {
return true;
}
}
else if (viewFilter.operator === FilterOperator.LOWEREQ &&
queryValue <= viewValue ) {
if (queryFilter.operator === FilterOperator.LOWER ||
queryFilter.operator === FilterOperator.LOWEREQ) {
return true;
}
}
else if (viewFilter.operator === FilterOperator.LOWER &&
queryValue < viewValue ) {
if (queryFilter.operator === FilterOperator.LOWER ||
queryFilter.operator === FilterOperator.LOWEREQ) {
return true;
}
}
}
return false;
}));
}
......@@ -565,5 +624,4 @@ export class Graph {
}
}
}
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