diff --git a/src/common/types.ts b/src/common/types.ts
index 8197a08687863b45b8a99a465d367f351d8cfc0a..6f07921e49bc11ca56dad2cb8d95daf25338688d 100644
--- a/src/common/types.ts
+++ b/src/common/types.ts
@@ -18,9 +18,14 @@
  * along with blend.  If not, see <http://www.gnu.org/licenses/>.
  */
 
- export enum AggregationType {
-    SUM,
-    AVG,
-    COUNT,
-    NONE
- };
+export enum AggregationType {
+   NONE,
+   SUM,
+   AVG,
+   COUNT
+};
+
+export enum RelationType {
+   NONE,
+   DAY
+};
diff --git a/src/core/dimension.ts b/src/core/dimension.ts
index f0b27898fb363ef38594430e61afe40f52dd182f..de6abccebeba0f0cef4c01208c6b2bf63555059e 100644
--- a/src/core/dimension.ts
+++ b/src/core/dimension.ts
@@ -18,14 +18,22 @@
  * along with blend.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+import { RelationType } from "../common/types";
+
 export interface DimensionOptions {
     name: string;
+    parent?: string;
+    relation?: RelationType;
 }
 
 export class Dimension {
     public readonly name: string;
+    public readonly parent: string;
+    public readonly relation: RelationType;
 
     constructor(options: DimensionOptions) {
         this.name = options.name;
+        this.relation = (options.relation) ? options.relation : RelationType.NONE;
+        this.parent = (options.parent) ? options.parent : "";
     }
 }
diff --git a/src/core/engine.spec.ts b/src/core/engine.spec.ts
index 2b9d24b6a0891c1705b34c2a77590d5d284b3f19..5788e7c9dd95b63abfcf4c4bf93dcc807d2fad2a 100644
--- a/src/core/engine.spec.ts
+++ b/src/core/engine.spec.ts
@@ -25,6 +25,7 @@ import { Metric } from "./metric";
 import { Dimension } from "./dimension";
 import { View } from "./view";
 import { AggregationType } from "../common/types";
+import { RelationType } from "../common/types";
 
 describe("engine class", () => {
     const engine = new Engine();
@@ -53,6 +54,12 @@ describe("engine class", () => {
     const dim10 = new Dimension({ name: "dim:10" });
     const dim11 = new Dimension({ name: "dim:11" });
 
+    const subdim1 = new Dimension({ name: "sub:1", parent: "dim:1", relation: RelationType.DAY });
+    const subdim2 = new Dimension({ name: "sub:2", parent: "dim:9", relation: RelationType.DAY });
+    const subdim3 = new Dimension({ name: "sub:3", parent: "sub:1", relation: RelationType.DAY });
+    const subdim4 = new Dimension({ name: "sub:4", parent: "sub:0", relation: RelationType.DAY });
+    const subdim5 = new Dimension({ name: "sub:5", parent: "dim:2", relation: RelationType.DAY });
+
     engine.addMetric(met1);
     engine.addMetric(met2);
     engine.addMetric(met3);
@@ -75,6 +82,12 @@ describe("engine class", () => {
     engine.addDimension(dim9);
     engine.addDimension(dim10);
 
+    engine.addDimension(subdim1);
+    engine.addDimension(subdim2);
+    engine.addDimension(subdim3);
+    engine.addDimension(subdim4);
+    engine.addDimension(subdim5);
+
     let views: View[] = [
         new View({ metrics: [met1, met2, met3], dimensions: [dim1, dim2]}),
         new View({ metrics: [met1, met3, met5], dimensions: [dim1, dim2]}),
@@ -102,6 +115,13 @@ describe("engine class", () => {
         childViews: [views[7], views[8], views[9]]
     }));
 
+    views.push(new View({
+        metrics: [met1],
+        dimensions: [subdim1, subdim2],
+        materialized: false,
+        childViews: [views[0], views[9]]
+    }));
+
     views.forEach((view) => engine.addView(view));
 
     it("should be create a fill that cover the query and has 4 children", () => {
@@ -156,4 +176,80 @@ describe("engine class", () => {
         }
         expect(error);
     });
+
+    it("should be create a fill that cover the query, that match perfectly with a existent view", () => {
+        let query = {
+            metrics : [met1, met2, met3]
+            , dimensions : [dim1, dim2]
+        };
+        let optimalView = engine.query(query);
+        expect(optimalView).to.be.an("object");
+        expect(optimalView).to.have.property("metrics");
+        expect(optimalView).to.have.property("dimensions");
+        expect(optimalView).to.have.property("childViews");
+        expect(optimalView.metrics).to.be.an("array");
+        expect(optimalView.dimensions).to.be.an("array");
+        expect(optimalView.childViews).to.be.an("array");
+        expect(optimalView.metrics.length === 3);
+        expect(optimalView.dimensions.length === 2);
+        expect(optimalView.childViews.length === 0);
+
+        expect(optimalView.id === views[0].id);
+    });
+
+    it("should be create a fill that cover the query, using sub dimensions", () => {
+        let emptyMetrics: Metric[] = [];
+        let query = {
+            metrics : emptyMetrics
+            , dimensions : [subdim1, subdim2]
+        };
+        let optimalView = engine.query(query);
+        expect(optimalView).to.be.an("object");
+        expect(optimalView).to.have.property("metrics");
+        expect(optimalView).to.have.property("dimensions");
+        expect(optimalView).to.have.property("childViews");
+        expect(optimalView.metrics).to.be.an("array");
+        expect(optimalView.dimensions).to.be.an("array");
+        expect(optimalView.childViews).to.be.an("array");
+        expect(optimalView.metrics.length === 0);
+        expect(optimalView.dimensions.length === 2);
+        expect(optimalView.childViews.length === 1);
+
+        expect(optimalView.childViews[0].dimensions.some((item) => item.name === subdim1.name));
+        expect(optimalView.childViews[0].dimensions.some((item) => item.name === subdim2.name));
+    });
+
+    it("should be create a fill that cover the query, using the parents of sub dimensions", () => {
+        let emptyMetrics: Metric[] = [];
+        let query = {
+            metrics : emptyMetrics
+            , dimensions : [subdim3, subdim5]
+        };
+        let optimalView = engine.query(query);
+        expect(optimalView).to.be.an("object");
+        expect(optimalView).to.have.property("metrics");
+        expect(optimalView).to.have.property("dimensions");
+        expect(optimalView).to.have.property("childViews");
+        expect(optimalView.metrics).to.be.an("array");
+        expect(optimalView.dimensions).to.be.an("array");
+        expect(optimalView.childViews).to.be.an("array");
+        expect(optimalView.metrics.length === 0);
+        expect(optimalView.dimensions.length === 2);
+        expect(optimalView.childViews.length === 1);
+
+        expect(optimalView.id === views[0].id);
+    });
+
+    it("should throw an exception, sub-dimension with non-existent parent", () => {
+        let error: boolean = false;
+        try {
+            engine.query({metrics: [met11], dimensions: [subdim4]});
+        }
+        catch (e){
+            error = true;
+            expect(e.message).to.be.equal("The dimension named " + subdim4.parent + " was not found");
+
+        }
+        expect(error);
+    });
 });
diff --git a/src/core/engine.ts b/src/core/engine.ts
index e810f570b64e1cf022961217d766c6d460dbad1e..8fe8091b68b0d88b8bac32617eb8cb02a64249d8 100644
--- a/src/core/engine.ts
+++ b/src/core/engine.ts
@@ -22,6 +22,7 @@ import { Dimension } from "./dimension";
 import { Metric } from "./metric";
 import { View } from "./view";
 import { Query } from "../common/query";
+import { RelationType } from "../common/types";
 
 export class Engine {
     private views: View[] = [];
@@ -74,34 +75,49 @@ export class Engine {
     }
 
     private selectOptimalView (q: Query) {
-        let metricsName = q.metrics.map((met) => met.name);
-        let dimensionsName = q.dimensions.map((dim) => dim.name);
-        let objective = metricsName.concat(dimensionsName);
+        let metUncovered = q.metrics.map((met) => met);
+        let dimUncovered = q.dimensions.map((dim) => dim);
         let optimalViews: View[] = [];
         let activeViews = this.getViews();
 
         // run this block until all metrics and dimmensions are covered
-        while (objective.length  > 0) {
+        while (metUncovered.length  > 0 || dimUncovered.length > 0) {
             let bestView: View;
-            let shortestDistance = objective.length + 1;
+            let coverLength = metUncovered.length + dimUncovered.length;
+            let shortestDistance = coverLength + 1;
 
             // remove views from the activeViews if they don't intersect
             // with the objective
             activeViews = activeViews.filter((view: View) => {
-                metricsName = view.metrics.map((met) => met.name);
-                dimensionsName = view.dimensions.map((dim) => dim.name);
-                let cover = metricsName.concat(dimensionsName);
-                let intersection = cover.filter((item: string) => {
-                    return objective.indexOf(item) !== -1;
+                let metIntersection = metUncovered.filter((met: Metric) => {
+                    return view.metrics.some((item) => item.name === met.name);
                 });
 
-                if (intersection.length > 0) {
-                    let distance = objective.length - intersection.length;
+                let dimIntersection = dimUncovered.filter((dim: Dimension) => {
+                    let r: boolean = view.dimensions.some((item) => item.name === dim.name);
+                    while (!r && dim.relation !== RelationType.NONE) {
+                        r = view.dimensions.some((item) => item.name === dim.parent);
+                        dim = this.getDimensionByName(dim.parent);
+                    }
+                    return r;
+                });
+
+                let intersection = metIntersection.length + dimIntersection.length;
+
+                if (intersection > 0) {
+                    let distance = coverLength - intersection;
 
                     if (distance < shortestDistance) {
                         bestView = view;
                         shortestDistance = distance;
                     }
+
+                    else if (distance === shortestDistance &&
+                            view.dimensions.length < bestView.dimensions.length) {
+                        // priorizes views with less dimensions
+                        bestView = view;
+                    }
+
                     return true;
                 }
 
@@ -110,7 +126,7 @@ export class Engine {
                 return false;
             });
 
-            if (shortestDistance  === objective.length + 1) {
+            if (shortestDistance  === coverLength + 1) {
                 throw new Error("Engine views cannot cover the query");
             }
 
@@ -118,22 +134,29 @@ export class Engine {
 
             // remove metrics and dimensions corvered by the bestView from the
             // objective (i.e. the object is already met for those metrics/dimensions)
-            objective = objective.filter((item: string) => {
-                metricsName = bestView.metrics.map((met) => met.name);
-                dimensionsName = bestView.dimensions.map((dim) => dim.name);
-                let cover = dimensionsName.concat(metricsName);
-                return cover.indexOf(item) === -1;
+
+            metUncovered = metUncovered.filter((met: Metric) => {
+                return !bestView.metrics.some((item) => item.name === met.name);
+            });
+
+            dimUncovered = dimUncovered.filter((dim: Dimension) => {
+                let r: boolean = bestView.dimensions.some((item) => item.name === dim.name);
+                while (!r && dim.relation !== RelationType.NONE) {
+                    r = bestView.dimensions.some((item) => item.name === dim.parent);
+                    dim = this.getDimensionByName(dim.parent);
+                }
+                return !r;
             });
         }
 
-        if (optimalViews.length === 1) {
-            // if there is a single view that covers the query, we just return it
-            return optimalViews.pop();
+        // If all the metrics and dimensions are the same and only exist one child view
+        // return this single child view
+        if (optimalViews.length === 1 &&
+            q.metrics.every((item) => optimalViews[0].metrics.indexOf(item) !== -1) &&
+            q.dimensions.every((item) => optimalViews[0].dimensions.indexOf(item) !== -1)) {
+            return optimalViews[0];
         }
         else {
-            // if more than one view is necessary to cover the query,
-            // we need to compose them into a new singular virtual view
-
             let options = {
                 metrics: q.metrics,
                 dimensions: q.dimensions,
diff --git a/src/core/view.ts b/src/core/view.ts
index b1f5fb60e511ac548cd3ec852bad6b76e2f0b3cc..823fe240f3530c42e204d5eeceee600ced9665a0 100644
--- a/src/core/view.ts
+++ b/src/core/view.ts
@@ -37,14 +37,14 @@ export class View {
     public childViews: View[];
 
     constructor (options: ViewOptions) {
-        this.metrics = options.metrics;
-        this.dimensions = options.dimensions;
+        this.metrics = options.metrics.sort();
+        this.dimensions = options.dimensions.sort();
         this.materialized = options.materialized || true;
         this.childViews = options.childViews || [];
 
         // calculate the id of the view based on it's metrics and dimensions
         let metricsNames = this.metrics.map(metric => metric.name);
         let dimensionsNames = this.dimensions.map(dimension => dimension.name);
-        this.id = Hash.sha1(metricsNames.concat(dimensionsNames));
+        this.id = Hash.sha1(metricsNames.concat(dimensionsNames).sort());
     }
 }