From: <all...@us...> - 2011-08-31 09:11:19
|
Revision: 1773 http://ogsa-dai.svn.sourceforge.net/ogsa-dai/?rev=1773&view=rev Author: allyhume Date: 2011-08-31 09:11:12 +0000 (Wed, 31 Aug 2011) Log Message: ----------- Initial commit of preliminary histogram based cardinality estimation work. Added Paths: ----------- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/ArithmeticOperator.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeHistogramBin.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeStatistics.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalitySelectVisitor.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalityStatistics.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/HistogramBasedAttributeStatistics.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/NumericAttributeHistogramBin.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/QueryPlanWalkUpFromLeaves.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/SimpleCardinalityStatistics.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimatingOperatorVisitor.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimationOptimiser.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsPhysicalSchema.java ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StringAttributeHistogramBin.java Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/ArithmeticOperator.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/ArithmeticOperator.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/ArithmeticOperator.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,10 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +public enum ArithmeticOperator { + EQUAL, + LESS_THAN, + GREATER_THAN, + LESS_THAN_OR_EQUAL, + GREATER_THAN_OR_EQUAL, + NOT_EQUAL +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/ArithmeticOperator.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeHistogramBin.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeHistogramBin.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeHistogramBin.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,28 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +public interface AttributeHistogramBin +{ + /** + * Tests if the bin contains the given value. + * + * @param value value + * + * @return 0 if the bin contains the value, -1 if the value is less than + * the bin range, 1 if the value is greater than the bin range. + */ + int containsValue(Object value); + + long getNumRows(); + + /** + * Rescale the bin to contain the specified number of rows. + * + * @param numRows + */ + void rescale(long numRows); + + AttributeHistogramBin makeCopy(); + + long processOperatorConstant(ArithmeticOperator op, Object constant); + +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeHistogramBin.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeStatistics.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeStatistics.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeStatistics.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,19 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +public interface AttributeStatistics +{ + long getNumRows(); + + /** + * Rescale the statistics to contain the specified number of rows. + * + * @param numRows new total number of rows + */ + void rescale(long numRows); + + AttributeStatistics makeCopy(); + + void processOperatorConstant(ArithmeticOperator op, Object constant); + + +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/AttributeStatistics.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalitySelectVisitor.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalitySelectVisitor.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalitySelectVisitor.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,213 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import uk.org.ogsadai.dqp.lqp.Attribute; +import uk.org.ogsadai.dqp.lqp.AttributeImpl; +import uk.org.ogsadai.expression.AndExpression; +import uk.org.ogsadai.expression.ArithmeticExpressionOperand; +import uk.org.ogsadai.expression.ComparisonExpression; +import uk.org.ogsadai.expression.EqualExpression; +import uk.org.ogsadai.expression.ExpressionEvaluationException; +import uk.org.ogsadai.expression.ExpressionVisitor; +import uk.org.ogsadai.expression.GreaterThanExpression; +import uk.org.ogsadai.expression.GreaterThanOrEqualExpression; +import uk.org.ogsadai.expression.InExpression; +import uk.org.ogsadai.expression.IsNullExpression; +import uk.org.ogsadai.expression.LessThanExpression; +import uk.org.ogsadai.expression.LessThanOrEqualExpression; +import uk.org.ogsadai.expression.LikeExpression; +import uk.org.ogsadai.expression.NotEqualExpression; +import uk.org.ogsadai.expression.NotExpression; +import uk.org.ogsadai.expression.OrExpression; +import uk.org.ogsadai.expression.arithmetic.ArithmeticExpression; +import uk.org.ogsadai.expression.arithmetic.TableColumn; +import uk.org.ogsadai.expression.arithmetic.visitors.OperandTypeArithmeticExprVisitor; +import uk.org.ogsadai.expression.arithmetic.visitors.OperandTypeArithmeticExprVisitor.OperandType; + +public class CardinalitySelectVisitor implements ExpressionVisitor +{ + private SimpleCardinalityStatistics mResult; + + public CardinalitySelectVisitor( + SimpleCardinalityStatistics cardStats) + { + mResult = cardStats; + } + + public SimpleCardinalityStatistics getResult() + { + return mResult; + } + + @Override + public void visitAndExpression(AndExpression expression) + { + throw new RuntimeException("Not supported"); + } + + @Override + public void visitOrExpression(OrExpression expression) + { + throw new RuntimeException("Not supported"); + } + + @Override + public void visitLessThanExpression(LessThanExpression expression) + { + processArithmeticOperator(expression, ArithmeticOperator.LESS_THAN); + } + + @Override + public void visitLessThanOrEqualExpression(LessThanOrEqualExpression expression) + { + processArithmeticOperator( + expression, ArithmeticOperator.LESS_THAN_OR_EQUAL); + } + + @Override + public void visitGreaterThanExpression(GreaterThanExpression expression) + { + processArithmeticOperator(expression, ArithmeticOperator.GREATER_THAN); + } + + @Override + public void visitGreaterThanOrEqualExpression( + GreaterThanOrEqualExpression expression) + { + processArithmeticOperator( + expression, ArithmeticOperator.GREATER_THAN_OR_EQUAL); + } + + @Override + public void visitEqualExpression(EqualExpression expression) + { + processArithmeticOperator(expression, ArithmeticOperator.EQUAL); + } + + @Override + public void visitNotEqualExpression(NotEqualExpression expression) + { + processArithmeticOperator(expression, ArithmeticOperator.NOT_EQUAL); + } + + @Override + public void visitNotExpression(NotExpression expression) + { + throw new RuntimeException("Not supported"); + + } + + @Override + public void visitIsNullExpression(IsNullExpression expression) + { + throw new RuntimeException("Not supported"); + + } + + @Override + public void visitLikeExpression(LikeExpression expression) + { + throw new RuntimeException("Not supported"); + + } + + @Override + public void visitInExpression(InExpression expression) + { + throw new RuntimeException("Not supported"); + + } + + private void processAttrOperatorConstant( + TableColumn tableColumn, + ArithmeticOperator op, + ArithmeticExpression constant) + { + try + { + // Evaluate the constant + constant.evaluate(null); + Object constantValue = constant.getResult(); + + // Get attribute + Attribute attr = new AttributeImpl( + tableColumn.getName(), tableColumn.getSource()); + + // Find statistics + AttributeStatistics stats = mResult.getStatistics(attr); + + // Update statistics + stats.processOperatorConstant(op, constantValue); + + // Update other attribute statistics + long newNumRows = stats.getNumRows(); + + for (AttributeStatistics attrStats : + mResult.getStatistics().values()) + { + if (attrStats != stats) + { + attrStats.rescale(newNumRows); + } + } + } + catch (ExpressionEvaluationException e) + { + throw new RuntimeException(e); + } + } + + + private ArithmeticExpression[] getArithmeticExpressions(ComparisonExpression expression) + { + ArithmeticExpression left = + ((ArithmeticExpressionOperand) expression.getLeftOperand()).getExpression(); + ArithmeticExpression right = + ((ArithmeticExpressionOperand) expression.getRightOperand()).getExpression(); + + return new ArithmeticExpression[]{left, right}; + } + + private OperandType[] getOperandTypes(ArithmeticExpression[] expressions) + { + OperandType[] result = new OperandType[expressions.length]; + + for (int i=0; i<expressions.length; ++i) + { + result[i] = getOperandType(expressions[i]); + } + return result; + + } + + private OperandType getOperandType(ArithmeticExpression expression) + { + OperandTypeArithmeticExprVisitor operandTypeVisitor = + new OperandTypeArithmeticExprVisitor(); + expression.accept(operandTypeVisitor); + return operandTypeVisitor.getOperandType(); + } + + private void processArithmeticOperator( + ComparisonExpression expression, ArithmeticOperator op) + { + ArithmeticExpression expressions[] = + getArithmeticExpressions(expression); + OperandType[] operandTypes = getOperandTypes(expressions); + + for (int i=0; i<2; ++i) + { + if (operandTypes[i] == OperandType.ATTR && + operandTypes[1-i] == OperandType.CONST) + { + processAttrOperatorConstant( + (TableColumn)expressions[i], + op, + expressions[1-i]); + return; + } + } + + throw new RuntimeException("Not supported, only supprot ATTR<CONST just now"); + } + +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalitySelectVisitor.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalityStatistics.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalityStatistics.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalityStatistics.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,19 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import uk.org.ogsadai.dqp.lqp.Attribute; +import uk.org.ogsadai.dqp.lqp.Predicate; + +public interface CardinalityStatistics +{ + /** + * Gets the cardinality of the associated operator. + * + * @return cardinality + */ + long getCardinality(); + + AttributeStatistics getStatistics(Attribute attr); + + CardinalityStatistics processSelect(Predicate pred); + +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/CardinalityStatistics.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/HistogramBasedAttributeStatistics.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/HistogramBasedAttributeStatistics.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/HistogramBasedAttributeStatistics.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,177 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import java.util.LinkedList; +import java.util.List; + +public class HistogramBasedAttributeStatistics implements AttributeStatistics +{ + private List<AttributeHistogramBin> mBins; + + public HistogramBasedAttributeStatistics() + { + mBins = new LinkedList<AttributeHistogramBin>(); + } + + public void addBin(AttributeHistogramBin histogramBin) + { + mBins.add(histogramBin); + } + + + @Override + public long getNumRows() + { + long result = 0; + for (AttributeHistogramBin bin : mBins) + { + result += bin.getNumRows(); + } + return result; + } + + @Override + public AttributeStatistics makeCopy() + { + HistogramBasedAttributeStatistics result = + new HistogramBasedAttributeStatistics(); + for( AttributeHistogramBin bin : mBins) + { + result.addBin(bin.makeCopy()); + } + return result; + } + + public void processOperatorConstant(ArithmeticOperator op, Object constant) + { + switch(op) + { + case EQUAL: + processEqualConstant(constant); + break; + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + processInequalityConstant(op, constant); + break; + case NOT_EQUAL: + processNotEqualConstant(constant); + break; + } + } + + private void processEqualConstant(Object constant) + { + AttributeHistogramBin bin = findBin(constant); + mBins.clear(); + if (bin != null) + { + mBins.add(bin); + bin.processOperatorConstant(ArithmeticOperator.EQUAL, constant); + } + } + + private void processNotEqualConstant(Object constant) + { + AttributeHistogramBin bin = findBin(constant); + if (bin != null) + { + bin.processOperatorConstant(ArithmeticOperator.NOT_EQUAL, constant); + } + } + + private void processInequalityConstant( + ArithmeticOperator op, Object constant) + { + List<AttributeHistogramBin> mBinsToKeep = + new LinkedList<AttributeHistogramBin>(); + for(AttributeHistogramBin bin : mBins) + { + int comparison = bin.containsValue(constant); + + if (op == ArithmeticOperator.GREATER_THAN || + op == ArithmeticOperator.GREATER_THAN_OR_EQUAL ) + { + comparison = comparison * -1; + } + + switch(comparison) + { + case 1 : + mBinsToKeep.add(bin); + break; + case 0 : + if (bin.processOperatorConstant(op, constant) != 0) + { + mBinsToKeep.add(bin); + } + break; + } + } + mBins = mBinsToKeep; + } + + + + private AttributeHistogramBin findBin(Object value) + { + for(AttributeHistogramBin bin : mBins) + { + if (bin.containsValue(value) == 0) + { + return bin; + } + } + return null; + } + + @Override + public void rescale(long numRows) + { + double factor = (double)numRows / (double) getNumRows(); + + for(AttributeHistogramBin bin : mBins) + { + long newBinRows = Math.round((double)bin.getNumRows() * factor); + bin.rescale(newBinRows); + } + + long newTotalRows = getNumRows(); + long rowsDifference = newTotalRows - numRows; + + for(AttributeHistogramBin bin : mBins) + { + if (rowsDifference < 0) + { + bin.rescale( bin.getNumRows() + 1); + ++rowsDifference; + } + else if (rowsDifference > 0) + { + bin.rescale( bin.getNumRows() - 1); + --rowsDifference; + } + else + { + break; + } + } + } + + /** + * Gets the histogram bins. This methods should only be used by test + * classes that need to validate the histograms produced. + * + * @return list of histogram bins. + */ + public List<AttributeHistogramBin> getBins() + { + return mBins; + } + + + public String toString() + { + return mBins.toString(); + } +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/HistogramBasedAttributeStatistics.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/NumericAttributeHistogramBin.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/NumericAttributeHistogramBin.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/NumericAttributeHistogramBin.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,264 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + + +public class NumericAttributeHistogramBin implements AttributeHistogramBin +{ + double mMin; + boolean mIsMinInclusive; + double mMax; + boolean mIsMaxInclusive; + long mNumRows; + long mNumValues; + + public NumericAttributeHistogramBin( + double min, + boolean isMinInclusive, + double max, + boolean isMaxInclusive, + long numRows, + long numValues) + { + mNumRows = numRows; + mNumValues = numValues; + mMin = min; + mMax = max; + mIsMaxInclusive = isMaxInclusive; + mIsMinInclusive = isMinInclusive; + } + + + @Override + public int containsValue(Object obj) + { + double value = getDouble(obj); + + if(value < mMin) + { + return -1; + } + else if (value == mMin) + { + if (mIsMinInclusive) + { + return 0; + } + else + { + return -1; + } + } + else if (value < mMax) + { + return 0; + } + else if (value == mMax) + { + if (mIsMaxInclusive) + { + return 0; + } + else + { + return 1; + } + } + else + { + return 1; + } + } + + @Override + public void rescale(long numRows) + { + mNumRows = numRows; + if (mNumValues > mNumRows) mNumValues = mNumRows; + } + + + @Override + public long getNumRows() + { + return mNumRows; + } + + + @Override + public AttributeHistogramBin makeCopy() + { + return new NumericAttributeHistogramBin( + mMin, + mIsMinInclusive, + mMax, + mIsMaxInclusive, + mNumRows, + mNumValues); + } + + @Override + public long processOperatorConstant(ArithmeticOperator op, Object constant) + { + switch(op) + { + case EQUAL: + return processEqualsConstant(constant); + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + return processInequalityConstant(op, constant); + case NOT_EQUAL: + return processNotEqualsConstant(constant); + default: + throw new RuntimeException("Unsupported operator: " + op); + } + } + + private long processEqualsConstant(Object obj) + { + if (mNumRows == 0) return 0; + + double constant = getDouble(obj); + + mMin = constant; + mMax = constant; + mIsMinInclusive = true; + mIsMaxInclusive = true; + mNumRows = mNumRows/mNumValues; + mNumValues = 1; + + return mNumRows; + } + + private long processNotEqualsConstant(Object obj) + { + if (mNumRows == 0) return 0; + + double constant = getDouble(obj); + double factor = (mNumValues-1)/(double) mNumValues; + + mNumRows = Math.round(factor * mNumRows); + mNumValues = mNumValues -1; + + if (constant == mMin) mIsMinInclusive = false; + if (constant == mMax) mIsMaxInclusive = false; + + return mNumRows; + } + + private long processInequalityConstant(ArithmeticOperator op, Object obj) + { + if (mMin == mMax ) + { + if (op == ArithmeticOperator.GREATER_THAN || + op == ArithmeticOperator.LESS_THAN) + { + // Can only have one value in this bin and we want those less + // than it so that must give zero rows and zero values + mNumRows = 0; + mNumValues = 0; + } + // else just keep the bin as it is + } + else + { + double constant = getDouble(obj); + + double factor = (constant-mMin)/(mMax-mMin); + + switch(op) + { + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + mMax = constant; + mIsMaxInclusive = (op == ArithmeticOperator.LESS_THAN_OR_EQUAL); + break; + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + mMin = constant; + mIsMinInclusive = + (op == ArithmeticOperator.GREATER_THAN_OR_EQUAL); + break; + } + + mNumRows = Math.round(factor * mNumRows); + mNumValues = Math.round(factor * mNumValues); + } + + return mNumRows; + } + + /** + * TODO + * + * This method should only be used by test + * classes that need to validate the histograms produced. + * + * @return TODO + */ + public double getMin() + { + return mMin; + } + + /** + * TODO + * + * This method should only be used by test + * classes that need to validate the histograms produced. + * + * @return TODO + */ + public double getMax() + { + return mMax; + } + + /** + * TODO + * + * This method should only be used by test + * classes that need to validate the histograms produced. + * + * @return TODO + */ + public long getNumValues() + { + return mNumValues; + } + + public boolean getIsMinInclusive() + { + return mIsMinInclusive; + } + + public boolean getIsMaxInclusive() + { + return mIsMaxInclusive; + } + + + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append("HistogramBin(").append(mMin).append(",").append(mMax); + sb.append(",").append(mIsMinInclusive).append(","); + sb.append(mIsMaxInclusive).append(",").append(mNumRows).append(","); + sb.append(mNumValues).append(")"); + return sb.toString(); + } + + double getDouble(Object obj) + { + if (! (obj instanceof Number)) + { + throw new RuntimeException( + "Object is not a Number : " + obj.getClass().getName()); + } + return ((Number)obj).doubleValue(); + + } + + +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/NumericAttributeHistogramBin.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/QueryPlanWalkUpFromLeaves.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/QueryPlanWalkUpFromLeaves.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/QueryPlanWalkUpFromLeaves.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,70 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import java.util.List; + +import uk.org.ogsadai.dqp.lqp.Branch; +import uk.org.ogsadai.dqp.lqp.Operator; +import uk.org.ogsadai.dqp.lqp.OperatorID; +import uk.org.ogsadai.dqp.lqp.OperatorVisitor; +import uk.org.ogsadai.dqp.lqp.operators.BinaryOperator; +import uk.org.ogsadai.dqp.lqp.optimiser.OptimiserUtils; + +/** + * Walks a query plan calling the specified visitor for each operator starting + * at the leaves and climbing up such at an operator is only visited + * when all its children have been visited. + * + */ +public class QueryPlanWalkUpFromLeaves +{ + private OperatorVisitor mVisitor; + + public QueryPlanWalkUpFromLeaves() + { + } + + public void setVisitor(OperatorVisitor visitor) + { + mVisitor = visitor; + } + + public Operator walk(Operator lqpRoot) + { + List<Operator> leafList = + OptimiserUtils.getLeafs(Branch.RIGHT, lqpRoot); + for(Operator op : leafList) + { + walkUp(op); + } + + return lqpRoot; + } + + /** + * Walk up the tree starting from leafs. + * + * @param currentOperator + */ + private void walkUp(Operator currentOperator) + { + if (currentOperator.getID() == OperatorID.NIL) + { + return; + } + + currentOperator.accept(mVisitor); + + if (currentOperator.getParent().isBinary()) + { + if (((BinaryOperator) currentOperator.getParent()) + .getChildIndex(currentOperator) == 0) + { + walkUp(currentOperator.getParent()); + } + } + else + { + walkUp(currentOperator.getParent()); + } + } +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/QueryPlanWalkUpFromLeaves.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/SimpleCardinalityStatistics.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/SimpleCardinalityStatistics.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/SimpleCardinalityStatistics.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,92 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import uk.org.ogsadai.dqp.lqp.Attribute; +import uk.org.ogsadai.dqp.lqp.AttributeMatchMode; +import uk.org.ogsadai.dqp.lqp.AttributeUtils; +import uk.org.ogsadai.dqp.lqp.Predicate; + +public class SimpleCardinalityStatistics + implements CardinalityStatistics +{ + private Map<Attribute,AttributeStatistics> mStatistics; + + public SimpleCardinalityStatistics() + { + mStatistics = new HashMap<Attribute, AttributeStatistics>(); + } + + void addAttributeStatistics( + Attribute attr, AttributeStatistics attrStatistics) + { + mStatistics.put(attr, attrStatistics); + } + + @Override + public long getCardinality() + { + return mStatistics.values().iterator().next().getNumRows(); + } + + @Override + public CardinalityStatistics processSelect(Predicate pred) + { + CardinalitySelectVisitor visitor = + new CardinalitySelectVisitor(makeCopy()); + pred.getExpression().accept(visitor); + return visitor.getResult(); + } + + private SimpleCardinalityStatistics makeCopy() + { + SimpleCardinalityStatistics result = + new SimpleCardinalityStatistics(); + for (Entry<Attribute,AttributeStatistics> entry : mStatistics.entrySet()) + { + result.addAttributeStatistics( + entry.getKey(), entry.getValue().makeCopy()); + } + return result; + } + + + @Override + public AttributeStatistics getStatistics(Attribute attr) + { + List<Attribute> matchingAttrs = + AttributeUtils.getMatching( + attr, mStatistics.keySet(), + AttributeMatchMode.NAME_AND_NULL_SOURCE); + + if (matchingAttrs.size() == 1) + { + return mStatistics.get(matchingAttrs.iterator().next()); + } + else + { + throw new RuntimeException( + "Unexpected number of matching attributes: " + + matchingAttrs.size()); + } + } + + /** + * Gets the attribute to attribute statistics map. This method should only + * be used by test classes to validate the statistics produced. + * + * @return the attribute to statistics map. + */ + public Map<Attribute,AttributeStatistics> getStatistics() + { + return mStatistics; + } + + public String toString() + { + return mStatistics.toString(); + } +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/SimpleCardinalityStatistics.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimatingOperatorVisitor.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimatingOperatorVisitor.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimatingOperatorVisitor.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,290 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import uk.org.ogsadai.dqp.common.DataDictionary; +import uk.org.ogsadai.dqp.common.PhysicalSchema; +import uk.org.ogsadai.dqp.lqp.Annotation; +import uk.org.ogsadai.dqp.lqp.Operator; +import uk.org.ogsadai.dqp.lqp.OperatorVisitor; +import uk.org.ogsadai.dqp.lqp.Predicate; +import uk.org.ogsadai.dqp.lqp.exceptions.TableNotFoundException; +import uk.org.ogsadai.dqp.lqp.operators.AntiSemiJoinOperator; +import uk.org.ogsadai.dqp.lqp.operators.ApplyOperator; +import uk.org.ogsadai.dqp.lqp.operators.BinaryRelFunctionOperator; +import uk.org.ogsadai.dqp.lqp.operators.DifferenceOperator; +import uk.org.ogsadai.dqp.lqp.operators.DuplicateEliminationOperator; +import uk.org.ogsadai.dqp.lqp.operators.ExchangeOperator; +import uk.org.ogsadai.dqp.lqp.operators.FullOuterJoinOperator; +import uk.org.ogsadai.dqp.lqp.operators.GroupByOperator; +import uk.org.ogsadai.dqp.lqp.operators.InnerThetaJoinOperator; +import uk.org.ogsadai.dqp.lqp.operators.IntersectionOperator; +import uk.org.ogsadai.dqp.lqp.operators.LeftOuterJoinOperator; +import uk.org.ogsadai.dqp.lqp.operators.OneRowOnlyOperator; +import uk.org.ogsadai.dqp.lqp.operators.ProductOperator; +import uk.org.ogsadai.dqp.lqp.operators.ProjectOperator; +import uk.org.ogsadai.dqp.lqp.operators.RenameOperator; +import uk.org.ogsadai.dqp.lqp.operators.RightOuterJoinOperator; +import uk.org.ogsadai.dqp.lqp.operators.ScalarGroupByOperator; +import uk.org.ogsadai.dqp.lqp.operators.ScanRelFunctionOperator; +import uk.org.ogsadai.dqp.lqp.operators.SelectOperator; +import uk.org.ogsadai.dqp.lqp.operators.SemiJoinOperator; +import uk.org.ogsadai.dqp.lqp.operators.SortOperator; +import uk.org.ogsadai.dqp.lqp.operators.TableScanOperator; +import uk.org.ogsadai.dqp.lqp.operators.UnaryRelFunctionOperator; +import uk.org.ogsadai.dqp.lqp.operators.UnionOperator; + +public class StatisticsCardinalityEstimatingOperatorVisitor + implements OperatorVisitor +{ + private DataDictionary mDataDictionary; + + public StatisticsCardinalityEstimatingOperatorVisitor() + { + } + + public void setDataDictionary(DataDictionary dataDictionary) + { + mDataDictionary = dataDictionary; + } + + private void rubbishEstimation(Operator operator) + { + long resultCard = operator.getChild(0).getResultCardinality(); + Annotation.addCardinalityAnnotation(operator, resultCard); + } + + @Override + public void visit(SelectOperator operator) + { + Predicate pred = operator.getPredicate(); + Operator child = operator.getChild(0); + CardinalityStatistics childCardStats = getCardinalityStats(child); + + CardinalityStatistics cardStats = + childCardStats.processSelect(pred); + + System.out.println("Card stats = " + cardStats); + + addCardinalityStatistics(operator, cardStats); + } + + @Override + public void visit(ProjectOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(RenameOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(DuplicateEliminationOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(SortOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(OneRowOnlyOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(GroupByOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(ScalarGroupByOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(TableScanOperator operator) + { + try + { + // Go to physical data dictionary and get table scan count + PhysicalSchema physicalSchema = + mDataDictionary.getTableSchema(operator.getTableName()). + getPhysicalSchema(); + + if (physicalSchema != null && + physicalSchema instanceof StatisticsPhysicalSchema) + { + StatisticsPhysicalSchema statsPhysicalSchema = + (StatisticsPhysicalSchema) physicalSchema; + + CardinalityStatistics cardStats = + statsPhysicalSchema.getCardinalityStatistics(); + addCardinalityStatistics(operator, cardStats); + } + else if (physicalSchema == null) + { + throw new RuntimeException( + "No physical schema data for table : " + + operator.getTableName()); + } + else + { + throw new RuntimeException( + "Physical schema not StatisticsPhysicalSchema, table : " + + operator.getTableName()); + } + } + catch(TableNotFoundException ex) + { + throw new RuntimeException(ex); + } + } + + @Override + public void visit(ExchangeOperator operator) + { + rubbishEstimation(operator); + } + + @Override + public void visit(ProductOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(InnerThetaJoinOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(SemiJoinOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(AntiSemiJoinOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(FullOuterJoinOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(LeftOuterJoinOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(RightOuterJoinOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(ApplyOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(UnionOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(IntersectionOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(DifferenceOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(UnaryRelFunctionOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(BinaryRelFunctionOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(ScanRelFunctionOperator operator) + { + rubbishEstimation(operator); + + } + + @Override + public void visit(Operator operator) + { + rubbishEstimation(operator); + + } + + private void addCardinalityStatistics( + Operator op, CardinalityStatistics stats) + { + op.addAnnotation("CardinalityStatistics", stats); + Annotation.addCardinalityAnnotation(op, stats.getCardinality()); + } + + private CardinalityStatistics getCardinalityStats(Operator op) + { + Object cardStats = op.getAnnotation("CardinalityStatistics"); + + if (cardStats == null) + { + throw new RuntimeException( + "Child operator has no CardinalityStatistics annotation"); + + } + else if (!(cardStats instanceof CardinalityStatistics)) + { + throw new RuntimeException( + "Child operator CardinalityStatistics annotation is not of " + + " type CardinalityStatistics"); + } + else + { + return (CardinalityStatistics) cardStats; + } + } +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimatingOperatorVisitor.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimationOptimiser.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimationOptimiser.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimationOptimiser.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,33 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import uk.org.ogsadai.dqp.common.CompilerConfiguration; +import uk.org.ogsadai.dqp.common.RequestDetails; +import uk.org.ogsadai.dqp.lqp.Operator; +import uk.org.ogsadai.dqp.lqp.exceptions.LQPException; +import uk.org.ogsadai.dqp.lqp.optimiser.Optimiser; +import uk.org.ogsadai.resource.dataresource.dqp.RequestDQPFederation; + +public class StatisticsCardinalityEstimationOptimiser implements Optimiser +{ + public StatisticsCardinalityEstimationOptimiser() + { + } + + @Override + public Operator optimise(Operator lqpRoot, + RequestDQPFederation requestFederation, + CompilerConfiguration compilerConfiguration, + RequestDetails requestDetails) throws LQPException + { + StatisticsCardinalityEstimatingOperatorVisitor estimator = + new StatisticsCardinalityEstimatingOperatorVisitor(); + estimator.setDataDictionary(requestFederation.getDataDictionary()); + + QueryPlanWalkUpFromLeaves walker = new QueryPlanWalkUpFromLeaves(); + walker.setVisitor(estimator); + + walker.walk(lqpRoot); + + return lqpRoot; + } +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsCardinalityEstimationOptimiser.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsPhysicalSchema.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsPhysicalSchema.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsPhysicalSchema.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,15 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + +import uk.org.ogsadai.dqp.common.PhysicalSchema; + +public interface StatisticsPhysicalSchema extends PhysicalSchema +{ + /** + * Gets the cardinality statistics. + * + * @return cardinality statistics data structure. This data structure + * must not be altered. + */ + CardinalityStatistics getCardinalityStatistics(); + +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StatisticsPhysicalSchema.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StringAttributeHistogramBin.java =================================================================== --- ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StringAttributeHistogramBin.java (rev 0) +++ ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StringAttributeHistogramBin.java 2011-08-31 09:11:12 UTC (rev 1773) @@ -0,0 +1,255 @@ +package uk.org.ogsadai.dqp.lqp.cardinality; + + +public class StringAttributeHistogramBin implements AttributeHistogramBin +{ + String mMin; + boolean mIsMinInclusive; + String mMax; + boolean mIsMaxInclusive; + long mNumRows; + long mNumValues; + + public StringAttributeHistogramBin( + String min, + boolean isMinInclusive, + String max, + boolean isMaxInclusive, + long numRows, + long numValues) + { + mNumRows = numRows; + mNumValues = numValues; + mMin = min; + mMax = max; + mIsMaxInclusive = isMaxInclusive; + mIsMinInclusive = isMinInclusive; + } + + + @Override + public int containsValue(Object value) + { + String str = value.toString(); + + int compToMin = str.compareTo(mMin); + int compToMax = str.compareTo(mMax); + + if (compToMin < 0) + { + return -1; + } + else if (compToMin == 0) + { + if (mIsMinInclusive) + { + return 0; + } + else + { + return -1; + } + } + else if (compToMax < 0) + { + return 0; + } + else if (compToMax == 0) + { + if (mIsMaxInclusive) + { + return 0; + } + else + { + return 1; + } + } + else + { + return 1; + } + } + + @Override + public void rescale(long numRows) + { + mNumRows = numRows; + if (mNumValues > mNumRows) mNumValues = mNumRows; + } + + + @Override + public long getNumRows() + { + return mNumRows; + } + + + @Override + public AttributeHistogramBin makeCopy() + { + return new StringAttributeHistogramBin( + mMin, + mIsMinInclusive, + mMax, + mIsMaxInclusive, + mNumRows, + mNumValues); + } + + @Override + public long processOperatorConstant(ArithmeticOperator op, Object constant) + { + switch(op) + { + case EQUAL: + return processEqualsConstant(constant); + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + return processInequalityConstant(op, constant); + case NOT_EQUAL: + return processNotEqualsConstant(constant); + default: + throw new RuntimeException("Unsupported operator: " + op); + } + } + + + private long processEqualsConstant(Object constant) + { + if (mNumRows == 0) return 0; + + String str = constant.toString(); + mMin = str; + mMax = str; + mIsMinInclusive = true; + mIsMaxInclusive = true; + mNumRows = mNumRows/mNumValues; + mNumValues = 1; + + return mNumRows; + } + + private long processNotEqualsConstant(Object constant) + { + if (mNumRows == 0) return 0; + + String str = constant.toString(); + double factor = (mNumValues-1)/(double) mNumValues; + + mNumRows = Math.round(factor * mNumRows); + mNumValues = mNumValues -1; + + if (str.equals(mMin)) mIsMinInclusive = false; + if (str.equals(mMax)) mIsMaxInclusive = false; + + return mNumRows; + } + + private long processInequalityConstant( + ArithmeticOperator op, Object constant) + { + String str = constant.toString(); + + if (mMin.equals(mMax) || str.equals(mMin)) + { + if (op == ArithmeticOperator.GREATER_THAN || + op == ArithmeticOperator.LESS_THAN) + { + // Can only have one value in this bin and we want those less + // than it so that must give zero rows and zero values + mNumRows = 0; + mNumValues = 0; + } + // else just keep the bin as it is + } + else + { + double factor = 0.5; // Just an estimate, we can't do too much + + switch(op) + { + case LESS_THAN: + case LESS_THAN_OR_EQUAL: + mMax = str; + mIsMaxInclusive = (op == ArithmeticOperator.LESS_THAN_OR_EQUAL); + break; + case GREATER_THAN: + case GREATER_THAN_OR_EQUAL: + mMin = str; + mIsMinInclusive = + (op == ArithmeticOperator.GREATER_THAN_OR_EQUAL); + break; + } + + mNumRows = Math.round(factor * mNumRows); + mNumValues = Math.round(factor * mNumValues); + } + + return mNumRows; + } + + /** + * TODO + * + * This method should only be used by test + * classes that need to validate the histograms produced. + * + * @return TODO + */ + public String getMin() + { + return mMin; + } + + /** + * TODO + * + * This method should only be used by test + * classes that need to validate the histograms produced. + * + * @return TODO + */ + public String getMax() + { + return mMax; + } + + /** + * TODO + * + * This method should only be used by test + * classes that need to validate the histograms produced. + * + * @return TODO + */ + public long getNumValues() + { + return mNumValues; + } + + public boolean getIsMinInclusive() + { + return mIsMinInclusive; + } + + public boolean getIsMaxInclusive() + { + return mIsMaxInclusive; + } + + + public String toString() + { + StringBuilder sb = new StringBuilder(); + + sb.append("HistogramBin(").append(mMin).append(",").append(mMax); + sb.append(",").append(mIsMinInclusive).append(","); + sb.append(mIsMaxInclusive).append(",").append(mNumRows).append(","); + sb.append(mNumValues).append(")"); + return sb.toString(); + } +} Property changes on: ogsa-dai/trunk/extensions/dqp/server/src/main/java/uk/org/ogsadai/dqp/lqp/cardinality/StringAttributeHistogramBin.java ___________________________________________________________________ Added: svn:mime-type + text/plain This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |