}
private SelectorExecutionPlan getBestSelectorExecutionPlan(
NodeState rootState, FilterImpl filter,
QueryIndexProvider indexProvider, boolean traversalEnabled) {
QueryIndex bestIndex = null;
if (LOG.isDebugEnabled()) {
LOG.debug("cost using filter " + filter);
}
double bestCost = Double.POSITIVE_INFINITY;
IndexPlan bestPlan = null;
for (QueryIndex index : indexProvider.getQueryIndexes(rootState)) {
double cost;
IndexPlan indexPlan = null;
if (index instanceof AdvancedQueryIndex) {
AdvancedQueryIndex advIndex = (AdvancedQueryIndex) index;
List<OrderEntry> sortOrder = null;
if (orderings != null) {
sortOrder = new ArrayList<OrderEntry>();
for (OrderingImpl o : orderings) {
DynamicOperandImpl op = o.getOperand();
if (!(op instanceof PropertyValueImpl)) {
// ordered by a function: currently not supported
break;
}
PropertyValueImpl p = (PropertyValueImpl) op;
SelectorImpl s = p.getSelectors().iterator().next();
if (!s.equals(filter.getSelector())) {
// ordered by a different selector
continue;
}
OrderEntry e = new OrderEntry(
p.getPropertyName(),
Type.UNDEFINED,
o.isDescending() ?
OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
sortOrder.add(e);
}
if (sortOrder.size() == 0) {
sortOrder = null;
}
}
long maxEntryCount = limit;
if (offset > 0) {
if (offset + limit < 0) {
// long overflow
maxEntryCount = Long.MAX_VALUE;
} else {
maxEntryCount = offset + limit;
}
}
List<IndexPlan> ipList = advIndex.getPlans(
filter, sortOrder, rootState);
cost = Double.POSITIVE_INFINITY;
for (IndexPlan p : ipList) {
long entryCount = Math.min(maxEntryCount, p.getEstimatedEntryCount());
double c = p.getCostPerExecution() + entryCount * p.getCostPerEntry();
if (c < cost) {
cost = c;
indexPlan = p;
}
}
} else {
cost = index.getCost(filter, rootState);
}
if (LOG.isDebugEnabled()) {
LOG.debug("cost for " + index.getIndexName() + " is " + cost);
}
if (cost < 0) {
LOG.error("cost below 0 for " + index.getIndexName() + " is " + cost);
}
if (cost < bestCost) {
bestCost = cost;
bestIndex = index;
bestPlan = indexPlan;
}
}
if (traversalEnabled) {
QueryIndex traversal = new TraversingIndex();
double cost = traversal.getCost(filter, rootState);
if (LOG.isDebugEnabled()) {
LOG.debug("cost for " + traversal.getIndexName() + " is " + cost);
}
if (cost < bestCost || bestCost == Double.POSITIVE_INFINITY) {
bestCost = cost;
bestIndex = traversal;
}