Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 2AC75108FA for ; Wed, 5 Mar 2014 13:58:50 +0000 (UTC) Received: (qmail 24485 invoked by uid 500); 5 Mar 2014 13:58:50 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 24433 invoked by uid 500); 5 Mar 2014 13:58:45 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-dev@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 24318 invoked by uid 99); 5 Mar 2014 13:58:41 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Mar 2014 13:58:41 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 05 Mar 2014 13:58:40 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id A0A1323888D7; Wed, 5 Mar 2014 13:58:19 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1574491 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java test/java/org/apache/jackrabbit/oak/query/index/AdvancedIndexTest.java Date: Wed, 05 Mar 2014 13:58:19 -0000 To: oak-commits@jackrabbit.apache.org From: thomasm@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140305135819.A0A1323888D7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: thomasm Date: Wed Mar 5 13:58:19 2014 New Revision: 1574491 URL: http://svn.apache.org/r1574491 Log: OAK-622 Improve QueryIndex interface (WIP) Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/AdvancedIndexTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java?rev=1574491&r1=1574490&r2=1574491&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java Wed Mar 5 13:58:19 2014 @@ -18,8 +18,12 @@ */ package org.apache.jackrabbit.oak.spi.query; +import java.util.ArrayList; +import java.util.List; + import javax.annotation.CheckForNull; +import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator; import org.apache.jackrabbit.oak.spi.state.NodeState; @@ -125,104 +129,279 @@ public interface QueryIndex { } -// /** -// * Return the possible index plans for the given filter and sort order. -// * Please note this method is supposed to run quickly. That means it should -// * usually not read any data from the storage. -// * -// * @param filter the filter -// * @param sortOrder the sort order or null if no sorting is required -// * @param rootState root state of the current repository snapshot -// * @return the list of index plans (null if none) -// */ -// List getPlans(Filter filter, List sortOrder, NodeState rootState); -// -// /** -// * Get the query plan description (for logging purposes). -// * -// * @param plan the index plan -// * @return the query plan description -// */ -// String getPlanDescription(IndexPlan plan); -// -// /** -// * Start a query. The filter and sort order of the index plan is to be used. -// * -// * @param plan the index plan to use -// * @param rootState root state of the current repository snapshot -// * @return a cursor to iterate over the result -// */ -// Cursor query(IndexPlan plan, NodeState rootState); -// -// /** -// * An index plan. -// */ -// public static class IndexPlan { -// -// /** -// * The cost to execute the query once. The returned value should -// * approximately match the number of disk read operations plus the -// * number of network roundtrips (worst case). -// */ -// double costPerExecution; -// -// /** -// * The cost to read one entry from the cursor. The returned value should -// * approximately match the number of disk read operations plus the -// * number of network roundtrips (worst case). -// */ -// double costPerEntry; -// -// /** -// * The estimated number of entries. This value does not have to be -// * accurate. -// */ -// long estimatedEntryCount; -// -// /** -// * The filter to use. -// */ -// Filter filter; -// -// /** -// * Whether the index is not always up-to-date. -// */ -// boolean isDelayed; -// -// /** -// * Whether the fulltext part of the filter is evaluated (possibly with -// * an extended syntax). If set, the fulltext part of the filter is not -// * evaluated any more within the query engine. -// */ -// boolean isFulltextIndex; -// -// /** -// * Whether the cursor is able to read all properties from a node. -// */ -// boolean includesNodeData; -// -// /** -// * The sort order of the returned entries, or null if unsorted. -// */ -// List sortOrder; -// -// } -// -// /** -// * A sort order entry. -// */ -// static class Order { -// -// /** -// * The property name on where to sort. -// */ -// String propertyName; -// -// /** -// * True for descending, false for ascending. -// */ -// boolean descending; -// -// } + /** + * An query index that may support using multiple access orders + * (returning the rows in a specific order), and that can provide detailed + * information about the cost. + */ + public interface AdvancedQueryIndex { + + /** + * Return the possible index plans for the given filter and sort order. + * Please note this method is supposed to run quickly. That means it + * should usually not read any data from the storage. + * + * @param filter the filter + * @param sortOrder the sort order or null if no sorting is required + * @param rootState root state of the current repository snapshot + * @return the list of index plans (null if none) + */ + List getPlans(Filter filter, List sortOrder, + NodeState rootState); + + /** + * Get the query plan description (for logging purposes). + * + * @param plan the index plan + * @return the query plan description + */ + String getPlanDescription(IndexPlan plan); + + /** + * Start a query. The filter and sort order of the index plan is to be + * used. + * + * @param plan the index plan to use + * @param rootState root state of the current repository snapshot + * @return a cursor to iterate over the result + */ + Cursor query(IndexPlan plan, NodeState rootState); + + } + + /** + * An index plan. + */ + public interface IndexPlan { + + /** + * The cost to execute the query once. The returned value should + * approximately match the number of disk read operations plus the + * number of network roundtrips (worst case). + * + * @return the cost per execution, in estimated number of I/O operations + */ + double getCostPerExecution(); + + /** + * The cost to read one entry from the cursor. The returned value should + * approximately match the number of disk read operations plus the + * number of network roundtrips (worst case). + * + * @return the lookup cost per entry, in estimated number of I/O operations + */ + double getCostPerEntry(); + + /** + * The estimated number of entries. This value does not have to be + * accurate. + * + * @return the estimated number of entries + */ + long getEstimatedEntryCount(); + + /** + * The filter to use. + * + * @return the filter + */ + Filter getFilter(); + + /** + * Whether the index is not always up-to-date. + * + * @return whether the index might be updated asynchronously + */ + boolean isDelayed(); + + /** + * Whether the fulltext part of the filter is evaluated (possibly with + * an extended syntax). If set, the fulltext part of the filter is not + * evaluated any more within the query engine. + * + * @return whether the index supports full-text extraction + */ + boolean isFulltextIndex(); + + /** + * Whether the cursor is able to read all properties from a node. + * If yes, then the query engine will not have to read the data itself. + * + * @return wheter node data is returned + */ + boolean includesNodeData(); + + /** + * The sort order of the returned entries, or null if unsorted. + * + * @return the sort order + */ + List getSortOrder(); + + /** + * A builder for index plans. + */ + public class Builder { + + protected double costPerExecution = 1.0; + protected double costPerEntry = 1.0; + protected long estimatedEntryCount = 1000000; + protected Filter filter; + protected boolean isDelayed; + protected boolean isFulltextIndex; + protected boolean includesNodeData; + protected List sortOrder; + + public Builder setCostPerExecution(double costPerExecution) { + this.costPerExecution = costPerExecution; + return this; + } + + public Builder setCostPerEntry(double costPerEntry) { + this.costPerEntry = costPerEntry; + return this; + } + + public Builder setEstimatedEntryCount(long estimatedEntryCount) { + this.estimatedEntryCount = estimatedEntryCount; + return this; + } + + public Builder setFilter(Filter filter) { + this.filter = filter; + return this; + } + + public Builder setDelayed(boolean isDelayed) { + this.isDelayed = isDelayed; + return this; + } + + public Builder setFulltextIndex(boolean isFulltextIndex) { + this.isFulltextIndex = isFulltextIndex; + return this; + } + + public Builder setIncludesNodeData(boolean includesNodeData) { + this.includesNodeData = includesNodeData; + return this; + } + + public Builder setSortOrder(List sortOrder) { + this.sortOrder = sortOrder; + return this; + } + + public IndexPlan build() { + + return new IndexPlan() { + + private final double costPerExecution = + Builder.this.costPerExecution; + private final double costPerEntry = + Builder.this.costPerEntry; + private final long estimatedEntryCount = + Builder.this.estimatedEntryCount; + private final Filter filter = + Builder.this.filter; + private final boolean isDelayed = + Builder.this.isDelayed; + private final boolean isFulltextIndex = + Builder.this.isFulltextIndex; + private final boolean includesNodeData = + Builder.this.includesNodeData; + private final List sortOrder = + Builder.this.sortOrder == null ? + null : new ArrayList( + Builder.this.sortOrder); + + @Override + public double getCostPerExecution() { + return costPerExecution; + } + + @Override + public double getCostPerEntry() { + return costPerEntry; + } + + @Override + public long getEstimatedEntryCount() { + return estimatedEntryCount; + } + + @Override + public Filter getFilter() { + return filter; + } + + @Override + public boolean isDelayed() { + return isDelayed; + } + + @Override + public boolean isFulltextIndex() { + return isFulltextIndex; + } + + @Override + public boolean includesNodeData() { + return includesNodeData; + } + + @Override + public List getSortOrder() { + return sortOrder; + } + + }; + } + + } + + } + + /** + * A sort order entry. + */ + static class OrderEntry { + + /** + * The property name on where to sort. + */ + private final String propertyName; + + /** + * The property type. Null if not known. + */ + private final Type propertyType; + + /** + * The sort order (ascending or descending). + */ + public enum Order { ASCENDING, DESCENDING }; + + private final Order order; + + OrderEntry(String propertyName, Type propertyType, Order order) { + this.propertyName = propertyName; + this.propertyType = propertyType; + this.order = order; + } + + public String getPropertyName() { + return propertyName; + } + + public Order getOrder() { + return order; + } + + public Type getPropertyType() { + return propertyType; + } + + } } Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/AdvancedIndexTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/AdvancedIndexTest.java?rev=1574491&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/AdvancedIndexTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/AdvancedIndexTest.java Wed Mar 5 13:58:19 2014 @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.jackrabbit.oak.query.index; + +import static org.junit.Assert.assertEquals; + +import org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan; +import org.junit.Test; + +/** + * Test the advanced query index feature. + */ +public class AdvancedIndexTest { + + @Test + public void builder() { + IndexPlan.Builder b = new IndexPlan.Builder(); + IndexPlan plan = b.setEstimatedEntryCount(10).build(); + assertEquals(10, plan.getEstimatedEntryCount()); + b.setEstimatedEntryCount(20); + assertEquals(10, plan.getEstimatedEntryCount()); + } + +}