Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Implement index optimization on SELECT queries
new executor
  • Loading branch information
luigidellaquila committed Jul 29, 2016
1 parent b5dc089 commit 4de5cb9
Show file tree
Hide file tree
Showing 18 changed files with 846 additions and 45 deletions.
Expand Up @@ -18,15 +18,20 @@
* Created by luigidellaquila on 23/07/16. * Created by luigidellaquila on 23/07/16.
*/ */
public class FetchFromIndexStep extends AbstractExecutionStep { public class FetchFromIndexStep extends AbstractExecutionStep {
private final OIndex index; private final OIndex index;
private final OBooleanExpression condition; private final OBinaryCondition additional;

OBooleanExpression condition;

private boolean inited = false; private boolean inited = false;
private OIndexCursor cursor; private OIndexCursor cursor;


public FetchFromIndexStep(OIndex<?> index, OBooleanExpression condition, OCommandContext ctx) { public FetchFromIndexStep(OIndex<?> index, OBooleanExpression condition, OBinaryCondition additionalRangeCondition,
OCommandContext ctx) {
super(ctx); super(ctx);
this.index = index; this.index = index;
this.condition = condition; this.condition = condition;
this.additional = additionalRangeCondition;
} }


@Override public OTodoResultSet syncPull(OCommandContext ctx, int nRecords) throws OTimeoutException { @Override public OTodoResultSet syncPull(OCommandContext ctx, int nRecords) throws OTimeoutException {
Expand Down Expand Up @@ -72,20 +77,47 @@ private void init() {
} }
inited = true; inited = true;


if (index.getDefinition() == null) { if (condition != null) {
return; init(condition);
} }
}
}


if (condition instanceof OBinaryCondition) { private void init(OBooleanExpression condition) {
processBinaryCondition(); if (index.getDefinition() == null) {
} else if (condition instanceof OBetweenCondition) { return;
processBetweenCondition(); }
} else { if (condition == null) {
throw new OCommandExecutionException("search for index for " + condition + " is not supported yet"); throw new OCommandExecutionException("Implement search from index without condition!");
} } else if (condition instanceof OBinaryCondition) {
processBinaryCondition();
} else if (condition instanceof OBetweenCondition) {
processBetweenCondition();
} else if (condition instanceof OAndBlock) {
processAndBlock();
} else {
throw new OCommandExecutionException("search for index for " + condition + " is not supported yet");
} }
} }


/**
* it's not key = [...] but a real condition on field names, already ordered (field names will be ignored)
*/
private void processAndBlock() {
OCollection fromKey = indexKeyFrom((OAndBlock) condition, additional);
OCollection toKey = indexKeyTo((OAndBlock) condition, additional);
boolean fromKeyIncluded = indexKeyFromIncluded((OAndBlock) condition, additional);
boolean toKeyIncluded = indexKeyToIncluded((OAndBlock) condition, additional);
init(fromKey, fromKeyIncluded, toKey, toKeyIncluded);
}

private void init(OCollection fromKey, boolean fromKeyIncluded, OCollection toKey, boolean toKeyIncluded) {
Object secondValue = fromKey.execute((OResult) null, ctx);
Object thirdValue = toKey.execute((OResult) null, ctx);
OIndexDefinition indexDef = index.getDefinition();
cursor = index.iterateEntriesBetween(toBetweenIndexKey(indexDef, secondValue), fromKeyIncluded, toBetweenIndexKey(indexDef, thirdValue), toKeyIncluded, isOrderAsc());
}

private void processBetweenCondition() { private void processBetweenCondition() {
OIndexDefinition definition = index.getDefinition(); OIndexDefinition definition = index.getDefinition();
OExpression key = ((OBetweenCondition) condition).getFirst(); OExpression key = ((OBetweenCondition) condition).getFirst();
Expand All @@ -97,7 +129,7 @@ private void processBetweenCondition() {


Object secondValue = second.execute((OResult) null, ctx); Object secondValue = second.execute((OResult) null, ctx);
Object thirdValue = third.execute((OResult) null, ctx); Object thirdValue = third.execute((OResult) null, ctx);
cursor = index.iterateEntriesBetween(secondValue, true, thirdValue, true, true); cursor = index.iterateEntriesBetween(toBetweenIndexKey(definition, secondValue), true, toBetweenIndexKey(definition, thirdValue), true, isOrderAsc());
} }


private void processBinaryCondition() { private void processBinaryCondition() {
Expand All @@ -112,13 +144,28 @@ private void processBinaryCondition() {
} }


private Collection toIndexKey(OIndexDefinition definition, Object rightValue) { private Collection toIndexKey(OIndexDefinition definition, Object rightValue) {
if (definition.getFields().size() == 1 && rightValue instanceof Collection) {
rightValue = ((Collection) rightValue).iterator().next();
}
rightValue = definition.createValue(rightValue); rightValue = definition.createValue(rightValue);
if (!(rightValue instanceof Collection)) { if (!(rightValue instanceof Collection)) {
rightValue = Collections.singleton(rightValue); rightValue = Collections.singleton(rightValue);
} }
return (Collection) rightValue; return (Collection) rightValue;
} }


private Object toBetweenIndexKey(OIndexDefinition definition, Object rightValue) {
if (definition.getFields().size() == 1 && rightValue instanceof Collection) {
rightValue = ((Collection) rightValue).iterator().next();
}
rightValue = definition.createValue(rightValue);

if (definition.getFields().size()>1 && !(rightValue instanceof Collection)) {
rightValue = Collections.singleton(rightValue);
}
return rightValue;
}

private OIndexCursor createCursor(OBinaryCompareOperator operator, OIndexDefinition definition, Object value, private OIndexCursor createCursor(OBinaryCompareOperator operator, OIndexDefinition definition, Object value,
OCommandContext ctx) { OCommandContext ctx) {
boolean orderAsc = isOrderAsc(); boolean orderAsc = isOrderAsc();
Expand All @@ -139,7 +186,7 @@ private OIndexCursor createCursor(OBinaryCompareOperator operator, OIndexDefinit
} }


private boolean isOrderAsc() { private boolean isOrderAsc() {
return true; return true;//TODO
} }


@Override public void asyncPull(OCommandContext ctx, int nRecords, OExecutionCallback callback) throws OTimeoutException { @Override public void asyncPull(OCommandContext ctx, int nRecords, OExecutionCallback callback) throws OTimeoutException {
Expand All @@ -150,8 +197,110 @@ private boolean isOrderAsc() {


} }


private OCollection indexKeyFrom(OAndBlock keyCondition, OBinaryCondition additional) {
OCollection result = new OCollection(-1);
for (OBooleanExpression exp : keyCondition.getSubBlocks()) {
if (exp instanceof OBinaryCondition) {
OBinaryCondition binaryCond = ((OBinaryCondition) exp);
OBinaryCompareOperator operator = binaryCond.getOperator();
if ((operator instanceof OEqualsCompareOperator) || (operator instanceof OGtOperator)
|| (operator instanceof OGeOperator)) {
result.add(binaryCond.getRight());
} else if (additional != null) {
result.add(additional.getRight());
}
} else {
throw new UnsupportedOperationException("Cannot execute index query with " + exp);
}
}
return result;
}

private OCollection indexKeyTo(OAndBlock keyCondition, OBinaryCondition additional) {
OCollection result = new OCollection(-1);
for (OBooleanExpression exp : keyCondition.getSubBlocks()) {
if (exp instanceof OBinaryCondition) {
OBinaryCondition binaryCond = ((OBinaryCondition) exp);
OBinaryCompareOperator operator = binaryCond.getOperator();
if ((operator instanceof OEqualsCompareOperator) || (operator instanceof OLtOperator)
|| (operator instanceof OLeOperator)) {
result.add(binaryCond.getRight());
} else if (additional != null) {
result.add(additional.getRight());
}
} else {
throw new UnsupportedOperationException("Cannot execute index query with " + exp);
}
}
return result;
}

private boolean indexKeyFromIncluded(OAndBlock keyCondition, OBinaryCondition additional) {
OBooleanExpression exp = keyCondition.getSubBlocks().get(keyCondition.getSubBlocks().size() - 1);
if (exp instanceof OBinaryCondition) {
OBinaryCompareOperator operator = ((OBinaryCondition) exp).getOperator();
OBinaryCompareOperator additionalOperator = additional == null ? null : ((OBinaryCondition) additional).getOperator();
if (isGreaterOperator(operator)) {
if(isIncludeOperator(operator)) {
return true;
}else {
return false;
}
} else if (additionalOperator==null || (isIncludeOperator(additionalOperator) && isGreaterOperator(additionalOperator))) {
return true;
} else {
return false;
}
} else {
throw new UnsupportedOperationException("Cannot execute index query with " + exp);
}
}

private boolean isGreaterOperator(OBinaryCompareOperator operator) {
if (operator == null) {
return false;
}
return operator instanceof OGeOperator || operator instanceof OGtOperator;
}

private boolean isLessOperator(OBinaryCompareOperator operator) {
if (operator == null) {
return false;
}
return operator instanceof OLeOperator || operator instanceof OLtOperator;
}

private boolean isIncludeOperator(OBinaryCompareOperator operator) {
if (operator == null) {
return false;
}
return operator instanceof OGeOperator || operator instanceof OLeOperator;
}

private boolean indexKeyToIncluded(OAndBlock keyCondition, OBinaryCondition additional) {
OBooleanExpression exp = keyCondition.getSubBlocks().get(keyCondition.getSubBlocks().size() - 1);
if (exp instanceof OBinaryCondition) {
OBinaryCompareOperator operator = ((OBinaryCondition) exp).getOperator();
OBinaryCompareOperator additionalOperator = additional == null ? null : ((OBinaryCondition) additional).getOperator();
if (isLessOperator(operator)) {
if(isIncludeOperator(operator)) {
return true;
}else{
return false;
}
} else if (additionalOperator == null || (isIncludeOperator(additionalOperator) && isLessOperator(additionalOperator))) {
return true;
} else {
return false;
}
} else {
throw new UnsupportedOperationException("Cannot execute index query with " + exp);
}
}

@Override public String prettyPrint(int depth, int indent) { @Override public String prettyPrint(int depth, int indent) {
return OExecutionStepInternal.getIndent(depth, indent) + "+ FETCH FROM INDEX " + index.getName() + "\n" + return OExecutionStepInternal.getIndent(depth, indent) + "+ FETCH FROM INDEX " + index.getName() + "\n" +
OExecutionStepInternal.getIndent(depth, indent) + " " + condition; OExecutionStepInternal.getIndent(depth, indent) + " " + condition + (additional == null ? "" : " and " + additional);
} }

} }
Expand Up @@ -114,7 +114,7 @@ private void fetchNextItem() {
} }


@Override public String prettyPrint(int depth, int indent) { @Override public String prettyPrint(int depth, int indent) {
return OExecutionStepInternal.getIndent(depth, indent) + "+ CALCULATE WHERE CONDITION : " + whereClause.toString(); return OExecutionStepInternal.getIndent(depth, indent) + "+ CALCULATE WHERE CONDITION \n" +OExecutionStepInternal.getIndent(depth, indent)+" "+ whereClause.toString();
} }


} }
@@ -0,0 +1,42 @@
package com.orientechnologies.orient.core.sql.executor;

import com.orientechnologies.orient.core.sql.parser.OAndBlock;
import com.orientechnologies.orient.core.sql.parser.OBinaryCondition;

/**
* For internal use.
* It is used to keep info about an index range search,
* where the main condition has the lower bound and the additional condition has the upper bound on last field only
*/
class IndexCondPair {

OAndBlock mainCondition;
OBinaryCondition additionalRange;

public IndexCondPair(OAndBlock keyCondition, OBinaryCondition additionalRangeCondition) {
this.mainCondition = keyCondition;
this.additionalRange = additionalRangeCondition;
}

@Override public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;

IndexCondPair that = (IndexCondPair) o;

if (mainCondition != null ? !mainCondition.equals(that.mainCondition) : that.mainCondition != null)
return false;
if (additionalRange != null ? !additionalRange.equals(that.additionalRange) : that.additionalRange != null)
return false;

return true;
}

@Override public int hashCode() {
int result = mainCondition != null ? mainCondition.hashCode() : 0;
result = 31 * result + (additionalRange != null ? additionalRange.hashCode() : 0);
return result;
}
}
Expand Up @@ -3,6 +3,7 @@
import com.orientechnologies.orient.core.command.OCommandContext; import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.index.OIndex; import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.sql.parser.OAndBlock; import com.orientechnologies.orient.core.sql.parser.OAndBlock;
import com.orientechnologies.orient.core.sql.parser.OBinaryCondition;
import com.orientechnologies.orient.core.sql.parser.OBooleanExpression; import com.orientechnologies.orient.core.sql.parser.OBooleanExpression;


/** /**
Expand All @@ -11,11 +12,14 @@
public class IndexSearchDescriptor { public class IndexSearchDescriptor {
protected OIndex idx; protected OIndex idx;
protected OAndBlock keyCondition; protected OAndBlock keyCondition;
protected OBinaryCondition additionalRangeCondition;
protected OBooleanExpression remainingCondition; protected OBooleanExpression remainingCondition;


public IndexSearchDescriptor(OIndex idx, OAndBlock keyCondition, OBooleanExpression remainingCondition) { public IndexSearchDescriptor(OIndex idx, OAndBlock keyCondition, OBinaryCondition additional,
OBooleanExpression remainingCondition) {
this.idx = idx; this.idx = idx;
this.keyCondition = keyCondition; this.keyCondition = keyCondition;
this.additionalRangeCondition = additional;
this.remainingCondition = remainingCondition; this.remainingCondition = remainingCondition;
} }


Expand Down
Expand Up @@ -57,4 +57,9 @@ default String getTargetNode() {
default List<OExecutionStep> getSubSteps() { default List<OExecutionStep> getSubSteps() {
return Collections.EMPTY_LIST; return Collections.EMPTY_LIST;
} }

default List<OExecutionPlan> getSubExecutionPlans() {
return Collections.EMPTY_LIST;
}

} }

0 comments on commit 4de5cb9

Please sign in to comment.