/* * 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.index.elasticsearch; import org.modeshape.common.collection.Problems; import org.modeshape.jcr.ExecutionContext; import org.modeshape.jcr.NodeTypes; import org.modeshape.jcr.api.index.IndexDefinition; import org.modeshape.jcr.api.query.qom.ChildCount; import org.modeshape.jcr.cache.change.ChangeSetAdapter; import org.modeshape.jcr.index.elasticsearch.client.EsClient; import org.modeshape.jcr.query.QueryContext; import org.modeshape.jcr.query.model.FullTextSearch; import org.modeshape.jcr.query.model.Or; import org.modeshape.jcr.spi.index.IndexCostCalculator; import org.modeshape.jcr.spi.index.provider.IndexProvider; import org.modeshape.jcr.spi.index.provider.IndexUsage; import org.modeshape.jcr.spi.index.provider.ManagedIndexBuilder; import javax.jcr.RepositoryException; import javax.jcr.query.qom.ChildNodeJoinCondition; import javax.jcr.query.qom.DescendantNodeJoinCondition; import javax.jcr.query.qom.DynamicOperand; import javax.jcr.query.qom.JoinCondition; import java.util.Collection; /** * @author kulikov */ public class EsIndexProvider extends IndexProvider { private String host = "localhost"; private int port = 9200; private EsClient client; @Override protected void doInitialize() throws RepositoryException { logger().debug("Elasticsearch index provider for repository '{0}' " + "is trying to connect to cluster", getRepositoryName()); client = new EsClient(host, port); } /** * Gets ES instance address. * * @return ip address or domain name. */ public String getHost() { return host; } /** * Assigns ES instance address. * * @param host ip address or domain name. */ public void setHost(String host) { this.host = host; } /** * Gets ES instance port number. * * @return port number */ public int getPort() { return port; } /** * Gets ES instance port number. * * @return port number */ public void setPort(int port) { this.port = port; } @Override protected void postShutdown() { logger().debug("Shutting down the elasticsearch index provider '{0}' in repository '{1}'", getName(), getRepositoryName()); } @Override protected int getCostEstimate() { return IndexCostCalculator.Costs.REMOTE; } @Override public void validateProposedIndex(ExecutionContext context, IndexDefinition defn, NodeTypes.Supplier nodeTypeSupplier, Problems problems) { // first perform some custom validations } @Override protected ManagedIndexBuilder getIndexBuilder(IndexDefinition defn, String workspaceName, NodeTypes.Supplier nodeTypesSupplier, ChangeSetAdapter.NodeTypePredicate matcher) { return EsManagedIndexBuilder.create(client, context(), defn, nodeTypesSupplier, workspaceName, matcher); } @Override protected IndexUsage evaluateUsage(QueryContext context, final IndexCostCalculator calculator, final IndexDefinition defn) { return new IndexUsage(context, calculator, defn) { @Override protected boolean applies(ChildCount operand) { // nothing to do about this... return false; } @Override protected boolean applies(DynamicOperand operand) { if (IndexDefinition.IndexKind.TEXT == defn.getKind() && !(operand instanceof FullTextSearch)) { // text indexes only support FTS operands... return false; } return super.applies(operand); } @Override protected boolean indexAppliesTo(Or or) { boolean appliesToConstraints = super.indexAppliesTo(or); if (!appliesToConstraints) { return false; } Collection<JoinCondition> joinConditions = calculator.joinConditions(); if (joinConditions.isEmpty()) { return true; } for (JoinCondition joinCondition : joinConditions) { if (joinCondition instanceof ChildNodeJoinCondition || joinCondition instanceof DescendantNodeJoinCondition) { // the index can't handle OUTER JOINS with OR criteria (see https://issues.jboss.org/browse/MODE-2054) // so reject it, making the query engine fallback to the default behavior which works return false; } } return true; } }; } }