All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.modeshape.jcr.query.engine.IndexQueryEngine Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 *
 * 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.
 */
package org.modeshape.jcr.query.engine;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import org.modeshape.common.logging.Logger;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.JcrI18n;
import org.modeshape.jcr.query.NodeSequence;
import org.modeshape.jcr.query.QueryContext;
import org.modeshape.jcr.query.QueryEngine;
import org.modeshape.jcr.query.QueryResults.Columns;
import org.modeshape.jcr.query.model.QueryCommand;
import org.modeshape.jcr.query.optimize.AddIndexes;
import org.modeshape.jcr.query.optimize.Optimizer;
import org.modeshape.jcr.query.optimize.OptimizerRule;
import org.modeshape.jcr.query.optimize.RuleBasedOptimizer;
import org.modeshape.jcr.query.plan.PlanHints;
import org.modeshape.jcr.query.plan.PlanNode;
import org.modeshape.jcr.query.plan.Planner;
import org.modeshape.jcr.spi.index.Index;
import org.modeshape.jcr.spi.index.IndexCostCalculator;
import org.modeshape.jcr.spi.index.IndexManager;
import org.modeshape.jcr.spi.index.provider.IndexPlanner;
import org.modeshape.jcr.spi.index.provider.IndexProvider;

/**
 * A {@link QueryEngine} implementation that uses available indexes to more quickly produce query results.
 * 

* This query engine is capable of producing results for a query by scanning all nodes in the workspace(s) and filtering out any * node that does not satisfy the criteria. This scanning is not very efficient and can result in slow queries, especially when * the repository is quite large or when the number of nodes that satisfies the query's criteria is a small fraction of all * possible nodes in the workspace(s). *

*

* This engine can use indexes for certain properties so that it can more quickly identify the nodes that have property values * satisfying the constraints of a query. It is possible to index all properties, but this requires significant space and * evaluating all constraints using indexes may actually not be the most efficient and fastest approach. This query engine * attempts to use a minimum number of indexes that will most quickly produce the set of nodes closest to the actual expected * results. *

*

* Indexes are access from the repository's {@link IndexProvider} instances. */ public class IndexQueryEngine extends ScanningQueryEngine { /** We don't use the standard logging convention here; we want clients to easily configure logging for the indexes */ protected static final Logger LOGGER = Logger.getLogger("org.modeshape.jcr.query"); protected static final boolean TRACE = LOGGER.isTraceEnabled(); protected static final boolean DEBUG = LOGGER.isDebugEnabled(); public static class Builder extends ScanningQueryEngine.Builder { @Override public QueryEngine build() { // Determine the names of the query index providers ... Set providerNames = indexManager().getProviderNames(); if (providerNames.isEmpty()) { // There are no providers and thus we're not using any explicit indexes. There's no reason to use this engine ... return super.build(); } // Get the planner for each provider ... Map plannersByProviderName = new HashMap<>(); for (String providerName : indexManager().getProviderNames()) { IndexProvider provider = indexManager().getProvider(providerName); if (provider != null) { IndexPlanner planner = provider.getIndexPlanner(); if (planner == null) { throw new IllegalStateException(JcrI18n.indexProviderMissingPlanner.text(providerName, repositoryName())); } plannersByProviderName.put(providerName, planner); } } // Create the optimizer for the query engine ... IndexPlanners indexPlanners = IndexPlanners.withProviders(plannersByProviderName); Optimizer optimizer = optimizer(); if (optimizer == null) { // Create a single indexing rule that will use the index planner from all the providers ... final OptimizerRule indexingRule = AddIndexes.with(indexPlanners); // Create the optimizer that will add the providers' indexes using the same IndexingRule instance optimizer = new RuleBasedOptimizer() { @Override protected void populateIndexingRules( LinkedList ruleStack, PlanHints hints ) { ruleStack.addLast(indexingRule); } }; } // Finally create the query engine ... return new IndexQueryEngine(context(), repositoryName(), planner(), optimizer, indexManager()); } @Override protected final Optimizer defaultOptimizer() { return null; } } /** * A {@link IndexPlanner} implementation that passes through only those indexes that are owned by the named provider. * * @author Randall Hauch ([email protected]) */ protected static class ProviderIndexPlanner extends IndexPlanner { protected final String providerName; private final IndexPlanner providerPlanner; protected ProviderIndexPlanner( String providerName, IndexPlanner providerPlanner ) { this.providerName = providerName; this.providerPlanner = providerPlanner; } @Override public void applyIndexes( QueryContext context, IndexCostCalculator calculator ) { if (!context.getIndexDefinitions().hasIndexDefinitions()) return; providerPlanner.applyIndexes(context, calculator); } @Override public String toString() { return providerPlanner.toString(); } } /** * Obtain a builder that can be used to create new query engine instances. * * @return the builder; never null */ public static Builder builder() { return new Builder(); } private final IndexManager indexManager; protected IndexQueryEngine( ExecutionContext context, String repositoryName, Planner planner, Optimizer optimizer, IndexManager indexManager ) { super(context, repositoryName, planner, optimizer); this.indexManager = indexManager; } @Override protected NodeSequence createNodeSequenceForSource( QueryCommand originalQuery, QueryContext context, PlanNode sourceNode, IndexPlan indexPlan, Columns columns, QuerySources sources ) { // First let the supertype try to determine a node sequence. This will find the native indexes ... NodeSequence sequence = super.createNodeSequenceForSource(originalQuery, context, sourceNode, indexPlan, columns, sources); if (sequence != null) return sequence; // Look up the index by name ... String providerName = indexPlan.getProviderName(); IndexProvider provider = indexManager.getProvider(providerName); if (provider != null) { // Use the index to get a NodeSequence ... Index index = provider.getIndex(indexPlan.getName(), indexPlan.getWorkspaceName()); if (index != null) { return sources.fromIndex(index, indexPlan.getConstraints(), context.getVariables(), indexPlan.getParameters(), context.getExecutionContext().getValueFactories(), 100); } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy