Package com.orientechnologies.orient.core.sql

Source Code of com.orientechnologies.orient.core.sql.OFilterAnalyzer

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  *  you may not use this file except in compliance with the License.
  *  *  You may obtain a copy of the License at
  *  *
  *  *       http://www.apache.org/licenses/LICENSE-2.0
  *  *
  *  *  Unless required by applicable law or agreed to in writing, software
  *  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  *  See the License for the specific language governing permissions and
  *  *  limitations under the License.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */

package com.orientechnologies.orient.core.sql;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.metadata.schema.OClass;
import com.orientechnologies.orient.core.sql.filter.OSQLFilterCondition;
import com.orientechnologies.orient.core.sql.filter.OSQLFilterItemField;
import com.orientechnologies.orient.core.sql.operator.OIndexReuseType;
import com.orientechnologies.orient.core.sql.operator.OQueryOperator;
import com.orientechnologies.orient.core.sql.operator.OQueryOperatorBetween;
import com.orientechnologies.orient.core.sql.operator.OQueryOperatorIn;

/**
* @author <a href="mailto:enisher@gmail.com">Artem Orobets</a>
*/
public class OFilterAnalyzer {

  public List<OIndex<?>> getInvolvedIndexes(OClass iSchemaClass, OIndexSearchResult searchResultFields) {
    final Set<OIndex<?>> involvedIndexes = iSchemaClass.getInvolvedIndexes(searchResultFields.fields());

    final List<OIndex<?>> result = new ArrayList<OIndex<?>>(involvedIndexes.size());

    if (searchResultFields.lastField.isLong()) {
      result.addAll(OChainedIndexProxy.createProxies(iSchemaClass, searchResultFields.lastField));
    } else {
      for (OIndex<?> involvedIndex : involvedIndexes) {
        result.add(involvedIndex);
      }
    }

    return result;
  }

  /**
   * Analyzes a query filter for a possible indexation options. The results are sorted by amount of fields. So the most specific
   * items go first.
   *
   * @param condition
   *          to analyze
   * @param schemaClass
   *          the class that is scanned by query
   * @param context
   *          of the query
   * @return list of OIndexSearchResult items
   */
  public List<OIndexSearchResult> analyzeCondition(OSQLFilterCondition condition, final OClass schemaClass, OCommandContext context) {

    final List<OIndexSearchResult> indexSearchResults = new ArrayList<OIndexSearchResult>();
    analyzeFilterBranch(schemaClass, condition, indexSearchResults, context);

    Collections.sort(indexSearchResults, new Comparator<OIndexSearchResult>() {
      public int compare(final OIndexSearchResult searchResultOne, final OIndexSearchResult searchResultTwo) {
        return searchResultTwo.getFieldCount() - searchResultOne.getFieldCount();
      }
    });

    return indexSearchResults;
  }

  private OIndexSearchResult analyzeFilterBranch(final OClass iSchemaClass, OSQLFilterCondition condition,
      final List<OIndexSearchResult> iIndexSearchResults, OCommandContext iContext) {
    if (condition == null)
      return null;

    OQueryOperator operator = condition.getOperator();

    while (operator == null) {
      if (condition.getRight() == null && condition.getLeft() instanceof OSQLFilterCondition) {
        condition = (OSQLFilterCondition) condition.getLeft();
        operator = condition.getOperator();
      } else {
        return null;
      }
    }

    final OIndexReuseType indexReuseType = operator.getIndexReuseType(condition.getLeft(), condition.getRight());
    switch (indexReuseType) {
    case INDEX_INTERSECTION:
      return analyzeIntersection(iSchemaClass, condition, iIndexSearchResults, iContext);
    case INDEX_METHOD:
      return analyzeIndexMethod(iSchemaClass, condition, iIndexSearchResults);
    case INDEX_OPERATOR:
      return analyzeOperator(iSchemaClass, condition, iIndexSearchResults, iContext);
    default:
      return null;
    }
  }

  private OIndexSearchResult analyzeOperator(OClass iSchemaClass, OSQLFilterCondition condition,
      List<OIndexSearchResult> iIndexSearchResults, OCommandContext iContext) {
    return condition.getOperator().getOIndexSearchResult(iSchemaClass, condition, iIndexSearchResults, iContext);
  }

  private OIndexSearchResult analyzeIndexMethod(OClass iSchemaClass, OSQLFilterCondition condition,
      List<OIndexSearchResult> iIndexSearchResults) {
    OIndexSearchResult result = createIndexedProperty(condition, condition.getLeft());
    if (result == null)
      result = createIndexedProperty(condition, condition.getRight());

    if (result == null)
      return null;

    if (checkIndexExistence(iSchemaClass, result))
      iIndexSearchResults.add(result);

    return result;
  }

  private OIndexSearchResult analyzeIntersection(OClass iSchemaClass, OSQLFilterCondition condition,
      List<OIndexSearchResult> iIndexSearchResults, OCommandContext iContext) {
    final OIndexSearchResult leftResult = analyzeFilterBranch(iSchemaClass, (OSQLFilterCondition) condition.getLeft(),
        iIndexSearchResults, iContext);
    final OIndexSearchResult rightResult = analyzeFilterBranch(iSchemaClass, (OSQLFilterCondition) condition.getRight(),
        iIndexSearchResults, iContext);

    if (leftResult != null && rightResult != null) {
      if (leftResult.canBeMerged(rightResult)) {
        final OIndexSearchResult mergeResult = leftResult.merge(rightResult);
        if (iSchemaClass.areIndexed(mergeResult.fields()))
          iIndexSearchResults.add(mergeResult);
        return leftResult.merge(rightResult);
      }
    }

    return null;
  }

  /**
   * Add SQL filter field to the search candidate list.
   *
   * @param iCondition
   *          Condition item
   * @param iItem
   *          Value to search
   * @return true if the property was indexed and found, otherwise false
   */
  private OIndexSearchResult createIndexedProperty(final OSQLFilterCondition iCondition, final Object iItem) {
    if (iItem == null || !(iItem instanceof OSQLFilterItemField))
      return null;

    if (iCondition.getLeft() instanceof OSQLFilterItemField && iCondition.getRight() instanceof OSQLFilterItemField)
      return null;

    final OSQLFilterItemField item = (OSQLFilterItemField) iItem;

    if (item.hasChainOperators() && !item.isFieldChain())
      return null;

    final Object origValue = iCondition.getLeft() == iItem ? iCondition.getRight() : iCondition.getLeft();

    if (iCondition.getOperator() instanceof OQueryOperatorBetween || iCondition.getOperator() instanceof OQueryOperatorIn) {
      return new OIndexSearchResult(iCondition.getOperator(), item.getFieldChain(), origValue);
    }

    final Object value = OSQLHelper.getValue(origValue);
    return new OIndexSearchResult(iCondition.getOperator(), item.getFieldChain(), value);
  }

  private boolean checkIndexExistence(final OClass iSchemaClass, final OIndexSearchResult result) {
    return iSchemaClass.areIndexed(result.fields())
        && (!result.lastField.isLong() || checkIndexChainExistence(iSchemaClass, result));
  }

  private boolean checkIndexChainExistence(OClass iSchemaClass, OIndexSearchResult result) {
    final int fieldCount = result.lastField.getItemCount();
    OClass cls = iSchemaClass.getProperty(result.lastField.getItemName(0)).getLinkedClass();

    for (int i = 1; i < fieldCount; i++) {
      if (cls == null || !cls.areIndexed(result.lastField.getItemName(i))) {
        return false;
      }

      cls = cls.getProperty(result.lastField.getItemName(i)).getLinkedClass();
    }
    return true;
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.sql.OFilterAnalyzer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.