You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2015/06/23 21:47:25 UTC

incubator-tinkerpop git commit: CountMatchAlgorithm has a nicer sorting algorithm. Updated MatchStepTest with compilation tests and CountMatchAlgorithm tests. Added a static helper method to StartStep.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master d299f9491 -> f909e3571


CountMatchAlgorithm has a nicer sorting algorithm. Updated MatchStepTest with compilation tests and CountMatchAlgorithm tests. Added a static helper method to StartStep.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/f909e357
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/f909e357
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/f909e357

Branch: refs/heads/master
Commit: f909e357182cb8ecacfbb9b06bb7a9dca6a57776
Parents: d299f94
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Tue Jun 23 13:47:11 2015 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Tue Jun 23 13:47:11 2015 -0600

----------------------------------------------------------------------
 .../process/traversal/step/map/MatchStep.java   |  92 ++++++++---
 .../traversal/step/sideEffect/StartStep.java    |   5 +
 .../traversal/step/map/MatchStepTest.java       | 155 +++++++++++++------
 3 files changed, 180 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f909e357/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
index f5b8216..3e82b9e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
@@ -50,6 +50,7 @@ import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -456,8 +457,15 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
 
     public interface MatchAlgorithm extends Function<Traverser.Admin<Object>, Traversal.Admin<Object, Object>>, Serializable {
 
+        public static enum Type {WHERE_PREDICATE, WHERE_TRAVERSAL, MATCH_TRAVERSAL}
+
         public static Function<List<Traversal.Admin<Object, Object>>, IllegalStateException> UNMATCHABLE_PATTERN = traversals -> new IllegalStateException("The provided match pattern is unsolvable: " + traversals);
 
+        public static Optional<String> getBindingLabel(final Traversal.Admin<Object, Object> traversal) {
+            final Step<?, ?> endStep = traversal.getEndStep();
+            return endStep instanceof MatchEndStep ? ((MatchEndStep) endStep).getMatchKey() : Optional.empty();
+        }
+
         public static Set<String> getRequiredLabels(final Traversal.Admin<Object, Object> traversal) {
             final Step<?, ?> startStep = traversal.getStartStep();
             if (startStep instanceof Scoping)
@@ -466,6 +474,16 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
                 throw new IllegalArgumentException("The provided start step must be a scoping step: " + startStep);
         }
 
+        public static Type getTraversalType(final Traversal.Admin<Object, Object> traversal) {
+            final Step<?, ?> startStep = traversal.getStartStep();
+            if (startStep.getNextStep() instanceof WherePredicateStep)
+                return Type.WHERE_PREDICATE;
+            else if (startStep.getNextStep() instanceof WhereTraversalStep)
+                return Type.WHERE_TRAVERSAL;
+            else
+                return Type.MATCH_TRAVERSAL;
+        }
+
         public void initialize(final List<Traversal.Admin<Object, Object>> traversals);
 
         public default void recordStart(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
@@ -508,43 +526,69 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
 
     public static class CountMatchAlgorithm implements MatchAlgorithm {
 
-        protected List<Traversal.Admin<Object, Object>> traversals;
-        protected List<Integer[]> counts;
-        protected List<String> traversalLabels;
-        protected List<Set<String>> requiredLabels;
-        protected Map<Traversal.Admin<Object, Object>, Boolean> whereTraversals;
+        protected List<Bundle> traversalBundles;
 
         @Override
         public void initialize(final List<Traversal.Admin<Object, Object>> traversals) {
-            this.traversals = traversals;
-            this.whereTraversals = new HashMap<>();
-            this.counts = new ArrayList<>();
-            this.traversalLabels = new ArrayList<>();
-            this.requiredLabels = new ArrayList<>();
-            for (int i = 0; i < this.traversals.size(); i++) {
-                final Traversal.Admin<Object, Object> traversal = this.traversals.get(i);
-                this.traversalLabels.add(traversal.getStartStep().getId());
-                this.requiredLabels.add(MatchAlgorithm.getRequiredLabels(traversal));
-                this.counts.add(new Integer[]{i, 0});
-                this.whereTraversals.put(traversal, traversal.getStartStep().getNextStep() instanceof WhereTraversalStep || traversal.getStartStep().getNextStep() instanceof WherePredicateStep);
-            }
+            this.traversalBundles = traversals.stream().map(Bundle::of).collect(Collectors.toList());
         }
 
         @Override
         public Traversal.Admin<Object, Object> apply(final Traverser.Admin<Object> traverser) {
             final Path path = traverser.path();
-            for (final Integer[] indexCounts : this.counts) {
-                if (!path.hasLabel(this.traversalLabels.get(indexCounts[0])) && !this.requiredLabels.get(indexCounts[0]).stream().filter(label -> !path.hasLabel(label)).findAny().isPresent()) {
-                    return this.traversals.get(indexCounts[0]);
+            for (final Bundle bundle : this.traversalBundles) {
+                if (!path.hasLabel(bundle.traversalLabel) && !bundle.requiredLabels.stream().filter(label -> !path.hasLabel(label)).findAny().isPresent()) {
+                    return bundle.traversal;
                 }
             }
-            throw UNMATCHABLE_PATTERN.apply(this.traversals);
+            throw UNMATCHABLE_PATTERN.apply(this.traversalBundles.stream().map(record -> record.traversal).collect(Collectors.toList()));
         }
 
+        @Override
+        public void recordStart(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
+            this.getBundle(traversal).startsCount++;
+        }
+
+        @Override
         public void recordEnd(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
-            final int currentIndex = this.traversals.indexOf(traversal);
-            this.counts.stream().filter(array -> currentIndex == array[0]).findAny().get()[1]++;
-            Collections.sort(this.counts, (a, b) -> this.whereTraversals.get(traversal) ? 1 : a[1].compareTo(b[1]));
+            final Bundle bundle = this.getBundle(traversal);
+            bundle.endsCount++;
+            bundle.calculateSelectivity();
+            Collections.sort(this.traversalBundles, Comparator.<Bundle>comparingInt(r -> r.traversalType.ordinal()).thenComparingDouble(r -> r.selectivity));
+        }
+
+        protected Bundle getBundle(final Traversal.Admin<Object, Object> traversal) {
+            return this.traversalBundles.stream().filter(b -> b.traversal == traversal).findAny().get();
+        }
+
+        ///////////
+
+        public static class Bundle {
+            public Traversal.Admin<Object, Object> traversal;
+            public String traversalLabel;
+            public Set<String> requiredLabels;
+            //public String bindingLabel;
+            public Type traversalType;
+            public long startsCount;
+            public long endsCount;
+            public double selectivity;
+
+            public static Bundle of(final Traversal.Admin<Object, Object> traversal) {
+                final Bundle bundle = new Bundle();
+                bundle.traversal = traversal;
+                bundle.traversalLabel = traversal.getStartStep().getId();
+                bundle.traversalType = MatchAlgorithm.getTraversalType(traversal);
+                bundle.requiredLabels = MatchAlgorithm.getRequiredLabels(traversal);
+                //bundle.bindingLabel = MatchAlgorithm.getBindingLabel(traversal).orElse(null);
+                bundle.startsCount = 0l;
+                bundle.endsCount = 0l;
+                bundle.selectivity = 0.0d;
+                return bundle;
+            }
+
+            public final void calculateSelectivity() {
+                this.selectivity = (double) this.endsCount / (double) this.startsCount;
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f909e357/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StartStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StartStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StartStep.java
index 7fdbd81..fa471b6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StartStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/StartStep.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
@@ -96,4 +97,8 @@ public class StartStep<S> extends AbstractStep<S, S> {
     public boolean isVariableStartStep() {
         return null == this.start && this.getClass().equals(StartStep.class) && this.getLabels().size() == 1;
     }
+
+    public static boolean isVariableStartStep(final Step<?, ?> step) {
+        return step instanceof StartStep && ((StartStep) step).isVariableStartStep();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/f909e357/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStepTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStepTest.java
index fa06a74..d9217c1 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStepTest.java
@@ -193,63 +193,122 @@ public class MatchStepTest extends StepTest {
         Traversal.Admin<?, ?> traversal = __.match("a", as("a").out().as("b"), as("c").in().as("d")).asAdmin();
         MatchStep.CountMatchAlgorithm countMatchAlgorithm = new MatchStep.CountMatchAlgorithm();
         countMatchAlgorithm.initialize(((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren());
-        assertEquals(2, countMatchAlgorithm.counts.size());
-        countMatchAlgorithm.counts.stream().forEach(ints -> assertEquals(Integer.valueOf(0), ints[1]));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(0));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(0));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(1));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(1));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(1));
-        assertEquals(Integer.valueOf(0), countMatchAlgorithm.counts.get(0)[0]);
-        assertEquals(Integer.valueOf(2), countMatchAlgorithm.counts.get(0)[1]);
+        Traversal.Admin<Object, Object> firstPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(0);
+        Traversal.Admin<Object, Object> secondPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(1);
         //
-        assertEquals(Integer.valueOf(1), countMatchAlgorithm.counts.get(1)[0]);
-        assertEquals(Integer.valueOf(3), countMatchAlgorithm.counts.get(1)[1]);
+        assertEquals(2, countMatchAlgorithm.traversalBundles.size());
+        countMatchAlgorithm.traversalBundles.stream().forEach(bundle -> assertEquals(0.0d, bundle.selectivity, 0.0d));
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), firstPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), firstPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
+        assertEquals(MatchStep.MatchAlgorithm.Type.MATCH_TRAVERSAL, countMatchAlgorithm.getBundle(firstPattern).traversalType);
+        assertEquals(MatchStep.MatchAlgorithm.Type.MATCH_TRAVERSAL, countMatchAlgorithm.getBundle(secondPattern).traversalType);
+        assertEquals(2l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
+        assertEquals(3l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
+        ////
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        assertEquals(2l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
+        assertEquals(3l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
+        assertEquals(3l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
+        assertEquals(0.5d, countMatchAlgorithm.getBundle(firstPattern).selectivity, 0.01d);
+        assertEquals(1.0d, countMatchAlgorithm.getBundle(secondPattern).selectivity, 0.01d);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
         // CHECK RE-SORTING AS MORE DATA COMES IN
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(0));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(0));
-        assertEquals(Integer.valueOf(1), countMatchAlgorithm.counts.get(0)[0]);
-        assertEquals(Integer.valueOf(3), countMatchAlgorithm.counts.get(0)[1]);
-        //
-        assertEquals(Integer.valueOf(0), countMatchAlgorithm.counts.get(1)[0]);
-        assertEquals(Integer.valueOf(4), countMatchAlgorithm.counts.get(1)[1]);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
+        assertEquals(1.5d, countMatchAlgorithm.getBundle(firstPattern).selectivity, 0.01d);
+        assertEquals(1.0d, countMatchAlgorithm.getBundle(secondPattern).selectivity, 0.01d);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
 
 
         ///////  MAKE SURE WHERE PREDICATE TRAVERSALS ARE ALWAYS FIRST AS THEY ARE SIMPLY .hasNext() CHECKS
         traversal = __.match("a", as("a").out().as("b"), as("c").in().as("d"), where("a", P.eq("b"))).asAdmin();
         countMatchAlgorithm = new MatchStep.CountMatchAlgorithm();
         countMatchAlgorithm.initialize(((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren());
-        assertEquals(3, countMatchAlgorithm.counts.size());
-        countMatchAlgorithm.counts.stream().forEach(ints -> assertEquals(Integer.valueOf(0), ints[1]));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(0));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(1));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(1));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(2));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(2));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(2));
-        //
-        assertEquals(Integer.valueOf(2), countMatchAlgorithm.counts.get(0)[0]);
-        assertEquals(Integer.valueOf(3), countMatchAlgorithm.counts.get(0)[1]);
-        //
-        assertEquals(Integer.valueOf(0), countMatchAlgorithm.counts.get(1)[0]);
-        assertEquals(Integer.valueOf(1), countMatchAlgorithm.counts.get(1)[1]);
-        //
-        assertEquals(Integer.valueOf(1), countMatchAlgorithm.counts.get(2)[0]);
-        assertEquals(Integer.valueOf(2), countMatchAlgorithm.counts.get(2)[1]);
+        assertEquals(3, countMatchAlgorithm.traversalBundles.size());
+        firstPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(0);
+        secondPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(1);
+        Traversal.Admin<Object, Object> thirdPattern = ((MatchStep<?, ?>) traversal.getStartStep()).getGlobalChildren().get(2);
+        ///
+        countMatchAlgorithm.traversalBundles.stream().forEach(bundle -> assertEquals(0.0d, bundle.selectivity, 0.0d));
+        assertEquals(MatchStep.MatchAlgorithm.Type.MATCH_TRAVERSAL, countMatchAlgorithm.getBundle(firstPattern).traversalType);
+        assertEquals(MatchStep.MatchAlgorithm.Type.MATCH_TRAVERSAL, countMatchAlgorithm.getBundle(secondPattern).traversalType);
+        assertEquals(MatchStep.MatchAlgorithm.Type.WHERE_PREDICATE, countMatchAlgorithm.getBundle(thirdPattern).traversalType);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
+        assertEquals(thirdPattern, countMatchAlgorithm.traversalBundles.get(2).traversal);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), firstPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), firstPattern);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(thirdPattern).startsCount);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(thirdPattern).endsCount);
+        assertEquals(1.0d, countMatchAlgorithm.getBundle(firstPattern).selectivity, 0.01d);
+        assertEquals(0.0d, countMatchAlgorithm.getBundle(secondPattern).selectivity, 0.01d);
+        assertEquals(0.0d, countMatchAlgorithm.getBundle(thirdPattern).selectivity, 0.01d);
+        assertEquals(thirdPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(2).traversal);
         //
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(2));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(2));
-        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), countMatchAlgorithm.traversals.get(2));
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), thirdPattern);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
+        assertEquals(3l, countMatchAlgorithm.getBundle(thirdPattern).startsCount);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
+        assertEquals(0l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
+        assertEquals(6l, countMatchAlgorithm.getBundle(thirdPattern).endsCount);
+        assertEquals(1.0d, countMatchAlgorithm.getBundle(firstPattern).selectivity, 0.01d);
+        assertEquals(0.0d, countMatchAlgorithm.getBundle(secondPattern).selectivity, 0.01d);
+        assertEquals(2.0d, countMatchAlgorithm.getBundle(thirdPattern).selectivity, 0.01d);
+        assertEquals(thirdPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(2).traversal);
         //
-        assertEquals(Integer.valueOf(2), countMatchAlgorithm.counts.get(0)[0]);
-        assertEquals(Integer.valueOf(6), countMatchAlgorithm.counts.get(0)[1]);
-        //
-        assertEquals(Integer.valueOf(0), countMatchAlgorithm.counts.get(1)[0]);
-        assertEquals(Integer.valueOf(1), countMatchAlgorithm.counts.get(1)[1]);
-        //
-        assertEquals(Integer.valueOf(1), countMatchAlgorithm.counts.get(2)[0]);
-        assertEquals(Integer.valueOf(2), countMatchAlgorithm.counts.get(2)[1]);
-        //
-
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordStart(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        countMatchAlgorithm.recordEnd(EmptyTraverser.instance(), secondPattern);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).startsCount);
+        assertEquals(4l, countMatchAlgorithm.getBundle(secondPattern).startsCount);
+        assertEquals(3l, countMatchAlgorithm.getBundle(thirdPattern).startsCount);
+        assertEquals(1l, countMatchAlgorithm.getBundle(firstPattern).endsCount);
+        assertEquals(6l, countMatchAlgorithm.getBundle(secondPattern).endsCount);
+        assertEquals(6l, countMatchAlgorithm.getBundle(thirdPattern).endsCount);
+        assertEquals(1.0d, countMatchAlgorithm.getBundle(firstPattern).selectivity, 0.01d);
+        assertEquals(1.5d, countMatchAlgorithm.getBundle(secondPattern).selectivity, 0.01d);
+        assertEquals(2.0d, countMatchAlgorithm.getBundle(thirdPattern).selectivity, 0.01d);
+        assertEquals(thirdPattern, countMatchAlgorithm.traversalBundles.get(0).traversal);
+        assertEquals(firstPattern, countMatchAlgorithm.traversalBundles.get(1).traversal);
+        assertEquals(secondPattern, countMatchAlgorithm.traversalBundles.get(2).traversal);
     }
 }