You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2009/02/23 11:04:57 UTC
svn commit: r746946 [1/2] - in /jackrabbit/trunk/jackrabbit-core/src:
main/java/org/apache/jackrabbit/core/query/lucene/
main/resources/org/apache/jackrabbit/core/query/lucene/
test/java/org/apache/jackrabbit/core/query/
test/repository/workspaces/defa...
Author: mreutegg
Date: Mon Feb 23 10:04:53 2009
New Revision: 746946
URL: http://svn.apache.org/viewvc?rev=746946&view=rev
Log:
JCR-1990: Optimize queries with relative path in order by clause
Added:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractNamespaceMappings.java (with props)
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ComparableBoolean.java (with props)
jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/query/lucene/indexing-configuration-1.2.dtd (with props)
jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/indexing-configuration.xml (contents, props changed)
- copied, changed from r744177, jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/indexing-test/indexing-configuration.xml
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRule.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRuleImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FileBasedNamespaceMappings.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexFormatVersion.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationEntityResolver.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JQOM2LuceneQueryBuilder.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NSRegistryBasedNamespaceMappings.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameRangeQuery.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NamespaceMappings.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingletonTokenStream.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/IndexingAggregateTest.java
jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java
jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/workspace.xml
jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/indexing-test/indexing-configuration.xml
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractNamespaceMappings.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractNamespaceMappings.java?rev=746946&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractNamespaceMappings.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractNamespaceMappings.java Mon Feb 23 10:04:53 2009
@@ -0,0 +1,72 @@
+/*
+ * 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.core.query.lucene;
+
+import javax.jcr.NamespaceException;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+
+/**
+ * <code>AbstractNamespaceMappings</code> is the base class for index internal
+ * namespace mappings.
+ */
+public abstract class AbstractNamespaceMappings
+ implements NamespaceMappings, NamespaceResolver {
+
+ /**
+ * The name resolver used to translate the qualified name to JCR name
+ */
+ private final NamePathResolver resolver;
+
+ public AbstractNamespaceMappings() {
+ this.resolver = NamePathResolverImpl.create(this);
+ }
+
+ //----------------------------< NamespaceMappings >-------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public String translateName(Name qName)
+ throws IllegalNameException {
+ try {
+ return resolver.getJCRName(qName);
+ } catch (NamespaceException e) {
+ // should never happen actually, because we create yet unknown
+ // uri mappings on the fly.
+ throw new IllegalNameException("Internal error.", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String translatePath(Path path) throws IllegalNameException {
+ try {
+ return resolver.getJCRPath(path);
+ } catch (NamespaceException e) {
+ // should never happen actually, because we create yet unknown
+ // uri mappings on the fly.
+ throw new IllegalNameException("Internal error.", e);
+ }
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractNamespaceMappings.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRule.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRule.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRule.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRule.java Mon Feb 23 10:04:53 2009
@@ -18,6 +18,7 @@
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.PropertyState;
import javax.jcr.RepositoryException;
@@ -55,4 +56,17 @@
*/
NodeState[] getAggregatedNodeStates(NodeState nodeState)
throws ItemStateException;
+
+ /**
+ * Returns the property states that are part of the indexing aggregate of
+ * the <code>nodeState</code>.
+ *
+ * @param nodeState a node state
+ * @return the property states that are part of the indexing aggregate of
+ * <code>nodeState</code>. Returns <code>null</code> if this
+ * aggregate does not apply to <code>nodeState</code>.
+ * @throws ItemStateException if an error occurs.
+ */
+ public PropertyState[] getAggregatedPropertyStates(NodeState nodeState)
+ throws ItemStateException;
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRuleImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRuleImpl.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRuleImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AggregateRuleImpl.java Mon Feb 23 10:04:53 2009
@@ -27,8 +27,10 @@
import org.apache.jackrabbit.core.state.ItemStateManager;
import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.PropertyState;
import org.apache.jackrabbit.core.HierarchyManager;
import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.util.Text;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -36,6 +38,8 @@
import javax.jcr.RepositoryException;
import javax.jcr.NamespaceException;
+import javax.jcr.PathNotFoundException;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
@@ -60,9 +64,14 @@
private final Name nodeTypeName;
/**
- * The rules that define this indexing aggregate.
+ * The node includes of this indexing aggregate.
+ */
+ private final NodeInclude[] nodeIncludes;
+
+ /**
+ * The property includes of this indexing aggregate.
*/
- private final Rule[] rules;
+ private final PropertyInclude[] propertyIncludes;
/**
* The item state manager to retrieve additional item states.
@@ -91,11 +100,12 @@
AggregateRuleImpl(Node config,
NameResolver resolver,
ItemStateManager ism,
- HierarchyManager hmgr)
- throws MalformedPathException, IllegalNameException, NamespaceException {
+ HierarchyManager hmgr) throws MalformedPathException,
+ IllegalNameException, NamespaceException, PathNotFoundException {
this.resolver = resolver;
this.nodeTypeName = getNodeTypeName(config);
- this.rules = getRules(config);
+ this.nodeIncludes = getNodeIncludes(config);
+ this.propertyIncludes = getPropertyIncludes(config);
this.ism = ism;
this.hmgr = hmgr;
}
@@ -104,7 +114,7 @@
* Returns root node state for the indexing aggregate where
* <code>nodeState</code> belongs to.
*
- * @param nodeState
+ * @param nodeState the node state.
* @return the root node state of the indexing aggregate or
* <code>null</code> if <code>nodeState</code> does not belong to an
* indexing aggregate.
@@ -113,8 +123,16 @@
*/
public NodeState getAggregateRoot(NodeState nodeState)
throws ItemStateException, RepositoryException {
- for (int i = 0; i < rules.length; i++) {
- NodeState aggregateRoot = rules[i].matches(nodeState);
+ for (int i = 0; i < nodeIncludes.length; i++) {
+ NodeState aggregateRoot = nodeIncludes[i].matches(nodeState);
+ if (aggregateRoot != null
+ && aggregateRoot.getNodeTypeName().equals(nodeTypeName)) {
+ return aggregateRoot;
+ }
+ }
+ // check property includes
+ for (int i = 0; i < propertyIncludes.length; i++) {
+ NodeState aggregateRoot = propertyIncludes[i].matches(nodeState);
if (aggregateRoot != null
&& aggregateRoot.getNodeTypeName().equals(nodeTypeName)) {
return aggregateRoot;
@@ -137,8 +155,8 @@
throws ItemStateException {
if (nodeState.getNodeTypeName().equals(nodeTypeName)) {
List nodeStates = new ArrayList();
- for (int i = 0; i < rules.length; i++) {
- nodeStates.addAll(Arrays.asList(rules[i].resolve(nodeState)));
+ for (int i = 0; i < nodeIncludes.length; i++) {
+ nodeStates.addAll(Arrays.asList(nodeIncludes[i].resolve(nodeState)));
}
if (nodeStates.size() > 0) {
return (NodeState[]) nodeStates.toArray(new NodeState[nodeStates.size()]);
@@ -147,6 +165,25 @@
return null;
}
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyState[] getAggregatedPropertyStates(NodeState nodeState)
+ throws ItemStateException {
+ if (nodeState.getNodeTypeName().equals(nodeTypeName)) {
+ List propStates = new ArrayList();
+ for (int i = 0; i < propertyIncludes.length; i++) {
+ propStates.addAll(Arrays.asList(
+ propertyIncludes[i].resolvePropertyStates(nodeState)));
+ }
+ if (propStates.size() > 0) {
+ return (PropertyState[]) propStates.toArray(
+ new PropertyState[propStates.size()]);
+ }
+ }
+ return null;
+ }
+
//---------------------------< internal >-----------------------------------
/**
@@ -166,10 +203,10 @@
}
/**
- * Creates rules defined in the <code>config</code>.
+ * Creates node includes defined in the <code>config</code>.
*
* @param config the indexing aggregate configuration.
- * @return the rules defined in the <code>config</code>.
+ * @return the node includes defined in the <code>config</code>.
* @throws MalformedPathException if a path in the configuration is
* malformed.
* @throws IllegalNameException if the node type name contains illegal
@@ -177,9 +214,9 @@
* @throws NamespaceException if the node type contains an unknown
* prefix.
*/
- private Rule[] getRules(Node config)
+ private NodeInclude[] getNodeIncludes(Node config)
throws MalformedPathException, IllegalNameException, NamespaceException {
- List rules = new ArrayList();
+ List includes = new ArrayList();
NodeList childNodes = config.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node n = childNodes.item(i);
@@ -198,10 +235,44 @@
builder.addLast(resolver.getQName(elements[j]));
}
}
- rules.add(new Rule(builder.getPath(), ntName));
+ includes.add(new NodeInclude(builder.getPath(), ntName));
}
}
- return (Rule[]) rules.toArray(new Rule[rules.size()]);
+ return (NodeInclude[]) includes.toArray(new NodeInclude[includes.size()]);
+ }
+
+ /**
+ * Creates property includes defined in the <code>config</code>.
+ *
+ * @param config the indexing aggregate configuration.
+ * @return the property includes defined in the <code>config</code>.
+ * @throws MalformedPathException if a path in the configuration is
+ * malformed.
+ * @throws IllegalNameException if the node type name contains illegal
+ * characters.
+ * @throws NamespaceException if the node type contains an unknown
+ * prefix.
+ */
+ private PropertyInclude[] getPropertyIncludes(Node config) throws
+ MalformedPathException, IllegalNameException, NamespaceException,
+ PathNotFoundException {
+ List includes = new ArrayList();
+ NodeList childNodes = config.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node n = childNodes.item(i);
+ if (n.getNodeName().equals("include-property")) {
+ String[] elements = Text.explode(getTextContent(n), '/');
+ PathBuilder builder = new PathBuilder();
+ for (int j = 0; j < elements.length; j++) {
+ if (elements[j].equals("*")) {
+ throw new IllegalNameException("* not supported in include-property");
+ }
+ builder.addLast(resolver.getQName(elements[j]));
+ }
+ includes.add(new PropertyInclude(builder.getPath()));
+ }
+ }
+ return (PropertyInclude[]) includes.toArray(new PropertyInclude[includes.size()]);
}
//---------------------------< internal >-----------------------------------
@@ -222,17 +293,17 @@
return content.toString();
}
- private final class Rule {
+ private abstract class AbstractInclude {
/**
* Optional node type name.
*/
- private final Name nodeTypeName;
+ protected final Name nodeTypeName;
/**
* A relative path pattern.
*/
- private final Path pattern;
+ protected final Path pattern;
/**
* Creates a new rule with a relative path pattern and an optional node
@@ -242,7 +313,7 @@
* types are allowed.
* @param pattern a relative path pattern.
*/
- private Rule(Path pattern, Name nodeTypeName) {
+ AbstractInclude(Path pattern, Name nodeTypeName) {
this.nodeTypeName = nodeTypeName;
this.pattern = pattern;
}
@@ -255,6 +326,9 @@
* @return the root node state of the indexing aggregate or
* <code>null</code> if <code>nodeState</code> does not belong
* to an indexing aggregate defined by this rule.
+ * @throws ItemStateException if an error occurs while accessing node
+ * states.
+ * @throws RepositoryException if another error occurs.
*/
NodeState matches(NodeState nodeState)
throws ItemStateException, RepositoryException {
@@ -290,20 +364,6 @@
return null;
}
- /**
- * Resolves the <code>nodeState</code> using this rule.
- *
- * @param nodeState the root node of the enclosing indexing aggregate.
- * @return the descendant node states as defined by this rule.
- * @throws ItemStateException if an error occurs while resolving the
- * node states.
- */
- NodeState[] resolve(NodeState nodeState) throws ItemStateException {
- List nodeStates = new ArrayList();
- resolve(nodeState, nodeStates, 0);
- return (NodeState[]) nodeStates.toArray(new NodeState[nodeStates.size()]);
- }
-
//-----------------------------< internal >-----------------------------
/**
@@ -316,7 +376,7 @@
* @throws ItemStateException if an error occurs while accessing node
* states.
*/
- private void resolve(NodeState nodeState, List collector, int offset)
+ protected void resolve(NodeState nodeState, List collector, int offset)
throws ItemStateException {
Name currentName = pattern.getElements()[offset].getName();
List cne;
@@ -347,4 +407,68 @@
}
}
}
+
+ private final class NodeInclude extends AbstractInclude {
+
+ /**
+ * Creates a new node include with a relative path pattern and an
+ * optional node type name.
+ *
+ * @param nodeTypeName node type name or <code>null</code> if all node
+ * types are allowed.
+ * @param pattern a relative path pattern.
+ */
+ NodeInclude(Path pattern, Name nodeTypeName) {
+ super(pattern, nodeTypeName);
+ }
+
+ /**
+ * Resolves the <code>nodeState</code> using this rule.
+ *
+ * @param nodeState the root node of the enclosing indexing aggregate.
+ * @return the descendant node states as defined by this rule.
+ * @throws ItemStateException if an error occurs while resolving the
+ * node states.
+ */
+ NodeState[] resolve(NodeState nodeState) throws ItemStateException {
+ List nodeStates = new ArrayList();
+ resolve(nodeState, nodeStates, 0);
+ return (NodeState[]) nodeStates.toArray(new NodeState[nodeStates.size()]);
+ }
+ }
+
+ private final class PropertyInclude extends AbstractInclude {
+
+ private final Name propertyName;
+
+ PropertyInclude(Path pattern)
+ throws PathNotFoundException {
+ super(pattern.getAncestor(1), null);
+ this.propertyName = pattern.getNameElement().getName();
+ }
+
+ /**
+ * Resolves the <code>nodeState</code> using this rule.
+ *
+ * @param nodeState the root node of the enclosing indexing aggregate.
+ * @return the descendant property states as defined by this rule.
+ * @throws ItemStateException if an error occurs while resolving the
+ * property states.
+ */
+ PropertyState[] resolvePropertyStates(NodeState nodeState)
+ throws ItemStateException {
+ List nodeStates = new ArrayList();
+ resolve(nodeState, nodeStates, 0);
+ List propStates = new ArrayList();
+ for (Iterator it = nodeStates.iterator(); it.hasNext(); ) {
+ NodeState state = (NodeState) it.next();
+ if (state.hasPropertyName(propertyName)) {
+ PropertyId propId = new PropertyId(state.getNodeId(), propertyName);
+ propStates.add(ism.getItemState(propId));
+ }
+ }
+ return (PropertyState[]) propStates.toArray(
+ new PropertyState[propStates.size()]);
+ }
+ }
}
Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ComparableBoolean.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ComparableBoolean.java?rev=746946&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ComparableBoolean.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ComparableBoolean.java Mon Feb 23 10:04:53 2009
@@ -0,0 +1,43 @@
+/*
+ * 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.core.query.lucene;
+
+/**
+ * Represents a boolean that implement {@link Comparable}. This class can
+ * be removed when we move to Java 5.
+ */
+public final class ComparableBoolean implements Comparable {
+
+ private static final ComparableBoolean TRUE = new ComparableBoolean(true);
+
+ private static final ComparableBoolean FALSE = new ComparableBoolean(false);
+
+ private final boolean value;
+
+ private ComparableBoolean(boolean value) {
+ this.value = value;
+ }
+
+ public int compareTo(Object o) {
+ ComparableBoolean b = (ComparableBoolean) o;
+ return (b.value == value ? 0 : (value ? 1 : -1));
+ }
+
+ public static ComparableBoolean valueOf(boolean value) {
+ return value ? TRUE : FALSE;
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ComparableBoolean.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FileBasedNamespaceMappings.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FileBasedNamespaceMappings.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FileBasedNamespaceMappings.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FileBasedNamespaceMappings.java Mon Feb 23 10:04:53 2009
@@ -16,10 +16,7 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
-import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
-import org.apache.jackrabbit.spi.Name;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,8 +34,8 @@
import java.util.Properties;
/**
- * The class <code>NamespaceMappings</code> implements a {@link
- * org.apache.jackrabbit.core.NamespaceResolver} that holds a namespace
+ * The class <code>NamespaceMappings</code> implements a
+ * {@link NamespaceResolver} that holds a namespace
* mapping that is used internally in the search index. Storing paths with the
* full uri of a namespace would require too much space in the search index.
* <p/>
@@ -46,8 +43,7 @@
* prefix is created on the fly and associated with the namespace. Known
* namespace mappings are stored in a properties file.
*/
-public class FileBasedNamespaceMappings
- implements NamespaceResolver, NamespaceMappings {
+public class FileBasedNamespaceMappings extends AbstractNamespaceMappings {
/**
* Default logger instance for this class
@@ -60,11 +56,6 @@
private final File storage;
/**
- * The name resolver used to translate the qualified name to JCR name
- */
- private final NameResolver nameResolver;
-
- /**
* Map of uris indexed by prefixes
*/
private Map prefixToURI = new HashMap();
@@ -90,7 +81,6 @@
public FileBasedNamespaceMappings(File file) throws IOException {
storage = file;
load();
- nameResolver = NamePathResolverImpl.create(this);
}
/**
@@ -138,26 +128,6 @@
return prefix;
}
- //----------------------------< NamespaceMappings >-------------------------
-
- /**
- * Translates a property name from a session local namespace mapping
- * into a search index private namespace mapping.
- *
- * @param qName the property name to translate
- * @return the translated property name
- */
- public String translatePropertyName(Name qName)
- throws IllegalNameException {
- try {
- return nameResolver.getJCRName(qName);
- } catch (NamespaceException e) {
- // should never happen actually, because we create yet unknown
- // uri mappings on the fly.
- throw new IllegalNameException("Internal error.", e);
- }
- }
-
//-----------------------< internal >---------------------------------------
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexFormatVersion.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexFormatVersion.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexFormatVersion.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexFormatVersion.java Mon Feb 23 10:04:53 2009
@@ -79,6 +79,18 @@
}
/**
+ * Returns <code>true</code> if this version is at least as high as the
+ * given <code>version</code>.
+ *
+ * @param version the other version to compare.
+ * @return <code>true</code> if this version is at least as high as the
+ * provided; <code>false</code> otherwise.
+ */
+ public boolean isAtLeast(IndexFormatVersion version) {
+ return this.version >= version.getVersion();
+ }
+
+ /**
* @return a string representation of this index format version.
*/
public String toString() {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationEntityResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationEntityResolver.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationEntityResolver.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationEntityResolver.java Mon Feb 23 10:04:53 2009
@@ -45,6 +45,9 @@
systemIds.put(
"http://jackrabbit.apache.org/dtd/indexing-configuration-1.1.dtd",
"indexing-configuration-1.1.dtd");
+ systemIds.put(
+ "http://jackrabbit.apache.org/dtd/indexing-configuration-1.2.dtd",
+ "indexing-configuration-1.2.dtd");
SYSTEM_IDS = Collections.unmodifiableMap(systemIds);
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationImpl.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/IndexingConfigurationImpl.java Mon Feb 23 10:04:53 2009
@@ -162,7 +162,7 @@
if (propertyNode.getNodeName().equals("property")) {
// get property name
Name propName = resolver.getQName(getTextContent(propertyNode));
- String fieldName = nsMappings.translatePropertyName(propName);
+ String fieldName = nsMappings.translateName(propName);
// set analyzer for the fulltext property fieldname
int idx = fieldName.indexOf(':');
fieldName = fieldName.substring(0, idx + 1)
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JQOM2LuceneQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JQOM2LuceneQueryBuilder.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JQOM2LuceneQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JQOM2LuceneQueryBuilder.java Mon Feb 23 10:04:53 2009
@@ -690,7 +690,7 @@
NodeType[] superTypes = nt.getSupertypes();
if (Arrays.asList(superTypes).contains(base)) {
Name n = session.getQName(nt.getName());
- String ntName = nsMappings.translatePropertyName(n);
+ String ntName = nsMappings.translateName(n);
Term t;
if (nt.isMixin()) {
// search on jcr:mixinTypes
@@ -740,7 +740,7 @@
return LongField.longToString(value.getLong());
case PropertyType.NAME:
Name n = session.getQName(value.getString());
- return nsMappings.translatePropertyName(n);
+ return nsMappings.translateName(n);
case PropertyType.PATH:
Path p = session.getQPath(value.getString());
return npResolver.getJCRPath(p);
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java Mon Feb 23 10:04:53 2009
@@ -330,7 +330,7 @@
NodeType[] superTypes = nt.getSupertypes();
if (Arrays.asList(superTypes).contains(base)) {
Name n = session.getQName(nt.getName());
- String ntName = nsMappings.translatePropertyName(n);
+ String ntName = nsMappings.translateName(n);
Term t;
if (nt.isMixin()) {
// search on jcr:mixinTypes
@@ -954,7 +954,7 @@
// try to translate name
try {
Name n = session.getQName(literal);
- values.add(nsMappings.translatePropertyName(n));
+ values.add(nsMappings.translateName(n));
log.debug("Coerced " + literal + " into NAME.");
} catch (NameException e) {
log.debug("Unable to coerce '" + literal + "' into a NAME: " + e.toString());
@@ -1028,7 +1028,7 @@
// might be a name
try {
Name n = session.getQName(literal);
- values.add(nsMappings.translatePropertyName(n));
+ values.add(nsMappings.translateName(n));
log.debug("Coerced " + literal + " into NAME.");
} catch (Exception e) {
// not a name
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NSRegistryBasedNamespaceMappings.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NSRegistryBasedNamespaceMappings.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NSRegistryBasedNamespaceMappings.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NSRegistryBasedNamespaceMappings.java Mon Feb 23 10:04:53 2009
@@ -16,11 +16,7 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
-import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
import org.apache.jackrabbit.core.NamespaceRegistryImpl;
-import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
-import org.apache.jackrabbit.spi.Name;
import javax.jcr.NamespaceException;
@@ -28,19 +24,13 @@
* <code>NSRegistryBasedNamespaceMappings</code> implements a namespace mapping
* based on the stable index prefix provided by the namespace registry.
*/
-public class NSRegistryBasedNamespaceMappings
- implements NamespaceResolver, NamespaceMappings {
+public class NSRegistryBasedNamespaceMappings extends AbstractNamespaceMappings {
/**
* The namespace registry.
*/
private final NamespaceRegistryImpl nsReg;
- /**
- * The name resolver used to translate the qualified name to JCR name
- */
- private final NameResolver nameResolver;
-
/**
* Creates a new <code>NSRegistryBasedNamespaceMappings</code>.
*
@@ -48,7 +38,6 @@
*/
NSRegistryBasedNamespaceMappings(NamespaceRegistryImpl nsReg) {
this.nsReg = nsReg;
- this.nameResolver = NamePathResolverImpl.create(this);
}
//-------------------------------< NamespaceResolver >----------------------
@@ -77,20 +66,4 @@
"Unknown namespace URI: " + uri, e);
}
}
-
- //-------------------------------< NamespaceMappings >----------------------
-
- /**
- * {@inheritDoc}
- */
- public String translatePropertyName(Name qName)
- throws IllegalNameException {
- try {
- return nameResolver.getJCRName(qName);
- } catch (NamespaceException e) {
- // should never happen actually, there is always a stable index
- // prefix for a known namespace uri
- throw new IllegalNameException("Internal error.", e);
- }
- }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameQuery.java Mon Feb 23 10:04:53 2009
@@ -87,7 +87,7 @@
// use LABEL field
try {
return new TermQuery(new Term(FieldNames.LABEL,
- nsMappings.translatePropertyName(nodeName)));
+ nsMappings.translateName(nodeName)));
} catch (IllegalNameException e) {
throw Util.createIOException(e);
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameRangeQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameRangeQuery.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameRangeQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NameRangeQuery.java Mon Feb 23 10:04:53 2009
@@ -164,7 +164,7 @@
if (lowerName == null) {
text = nsMappings.getPrefix(upperName.getNamespaceURI()) + ":";
} else {
- text = nsMappings.translatePropertyName(lowerName);
+ text = nsMappings.translateName(lowerName);
}
return new Term(FieldNames.LABEL, text);
} catch (RepositoryException e) {
@@ -182,7 +182,7 @@
if (upperName == null) {
text = nsMappings.getPrefix(lowerName.getNamespaceURI()) + ":\uFFFF";
} else {
- text = nsMappings.translatePropertyName(upperName);
+ text = nsMappings.translateName(upperName);
}
return new Term(FieldNames.LABEL, text);
} catch (RepositoryException e) {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NamespaceMappings.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NamespaceMappings.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NamespaceMappings.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NamespaceMappings.java Mon Feb 23 10:04:53 2009
@@ -19,6 +19,7 @@
import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
/**
* The class <code>NamespaceMappings</code> holds a namespace mapping that is
@@ -28,12 +29,21 @@
public interface NamespaceMappings extends NamespaceResolver {
/**
- * Translates a property name from a session local namespace mapping into a
- * search index private namespace mapping.
+ * Translates a name from a session local namespace mapping into a search
+ * index private namespace mapping.
*
- * @param qName the property name to translate
- * @return the translated JCR property name
+ * @param name the name to translate
+ * @return the translated JCR name
+ * @throws IllegalNameException if the name cannot be translated.
*/
- String translatePropertyName(Name qName) throws IllegalNameException;
+ String translateName(Name name) throws IllegalNameException;
+ /**
+ * Translates a path into a search index private namespace mapping.
+ *
+ * @param path the path to translate
+ * @return the translated path.
+ * @throws IllegalNameException if the name cannot be translated.
+ */
+ String translatePath(Path path) throws IllegalNameException;
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java Mon Feb 23 10:04:53 2009
@@ -20,6 +20,7 @@
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.NodeIdIterator;
+import org.apache.jackrabbit.core.HierarchyManager;
import org.apache.jackrabbit.core.fs.FileSystem;
import org.apache.jackrabbit.core.fs.FileSystemResource;
import org.apache.jackrabbit.core.fs.FileSystemException;
@@ -33,6 +34,8 @@
import org.apache.jackrabbit.core.state.NodeState;
import org.apache.jackrabbit.core.state.NodeStateIterator;
import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.ItemStateException;
import org.apache.jackrabbit.extractor.DefaultTextExtractor;
import org.apache.jackrabbit.extractor.TextExtractor;
import org.apache.jackrabbit.spi.Name;
@@ -46,6 +49,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.Token;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.Term;
@@ -163,6 +167,11 @@
public static final int DEFAULT_TERM_INFOS_INDEX_DIVISOR = 1;
/**
+ * The path factory.
+ */
+ protected static final PathFactory PATH_FACTORY = PathFactoryImpl.getInstance();
+
+ /**
* The path of the root node.
*/
private static final Path ROOT_PATH;
@@ -173,10 +182,9 @@
private static final Path JCR_SYSTEM_PATH;
static {
- PathFactory factory = PathFactoryImpl.getInstance();
- ROOT_PATH = factory.create(NameConstants.ROOT);
+ ROOT_PATH = PATH_FACTORY.create(NameConstants.ROOT);
try {
- JCR_SYSTEM_PATH = factory.create(ROOT_PATH, NameConstants.JCR_SYSTEM, false);
+ JCR_SYSTEM_PATH = PATH_FACTORY.create(ROOT_PATH, NameConstants.JCR_SYSTEM, false);
} catch (RepositoryException e) {
// should never happen, path is always valid
throw new InternalError(e.getMessage());
@@ -1168,29 +1176,69 @@
return;
}
try {
+ ItemStateManager ism = getContext().getItemStateManager();
for (int i = 0; i < aggregateRules.length; i++) {
+ boolean ruleMatched = false;
+ // node includes
NodeState[] aggregates = aggregateRules[i].getAggregatedNodeStates(state);
- if (aggregates == null) {
- continue;
+ if (aggregates != null) {
+ ruleMatched = true;
+ for (int j = 0; j < aggregates.length; j++) {
+ Document aDoc = createDocument(aggregates[j],
+ getNamespaceMappings(),
+ index.getIndexFormatVersion());
+ // transfer fields to doc if there are any
+ Fieldable[] fulltextFields = aDoc.getFieldables(FieldNames.FULLTEXT);
+ if (fulltextFields != null) {
+ for (int k = 0; k < fulltextFields.length; k++) {
+ doc.add(fulltextFields[k]);
+ }
+ doc.add(new Field(FieldNames.AGGREGATED_NODE_UUID,
+ aggregates[j].getNodeId().getUUID().toString(),
+ Field.Store.NO,
+ Field.Index.NO_NORMS));
+ }
+ }
}
- for (int j = 0; j < aggregates.length; j++) {
- Document aDoc = createDocument(aggregates[j],
- getNamespaceMappings(),
- index.getIndexFormatVersion());
- // transfer fields to doc if there are any
- Fieldable[] fulltextFields = aDoc.getFieldables(FieldNames.FULLTEXT);
- if (fulltextFields != null) {
- for (int k = 0; k < fulltextFields.length; k++) {
- doc.add(fulltextFields[k]);
+ // property includes
+ PropertyState[] propStates = aggregateRules[i].getAggregatedPropertyStates(state);
+ if (propStates != null) {
+ ruleMatched = true;
+ for (int j = 0; j < propStates.length; j++) {
+ PropertyState propState = propStates[j];
+ String namePrefix = FieldNames.createNamedValue(
+ getNamespaceMappings().translateName(propState.getName()), "");
+ NodeState parent = (NodeState) ism.getItemState(propState.getParentId());
+ Document aDoc = createDocument(parent, getNamespaceMappings(), getIndex().getIndexFormatVersion());
+ // find the right fields to transfer
+ Fieldable[] fields = aDoc.getFieldables(FieldNames.PROPERTIES);
+ for (int k = 0; k < fields.length; k++) {
+ Fieldable field = fields[k];
+ // assume properties fields use SingleTokenStream
+ Token t = field.tokenStreamValue().next();
+ String value = new String(t.termBuffer(), 0, t.termLength());
+ if (value.startsWith(namePrefix)) {
+ // extract value
+ value = value.substring(namePrefix.length());
+ // create new named value
+ Path p = getRelativePath(state, propState);
+ String path = getNamespaceMappings().translatePath(p);
+ value = FieldNames.createNamedValue(path, value);
+ t.setTermText(value);
+ doc.add(new Field(field.name(), new SingletonTokenStream(t)));
+ doc.add(new Field(FieldNames.AGGREGATED_NODE_UUID,
+ parent.getNodeId().getUUID().toString(),
+ Field.Store.NO,
+ Field.Index.NO_NORMS));
+ }
}
- doc.add(new Field(FieldNames.AGGREGATED_NODE_UUID,
- aggregates[j].getNodeId().getUUID().toString(),
- Field.Store.NO,
- Field.Index.NO_NORMS));
}
}
+
// only use first aggregate definition that matches
- break;
+ if (ruleMatched) {
+ break;
+ }
}
} catch (Exception e) {
// do not fail if aggregate cannot be created
@@ -1201,6 +1249,38 @@
}
/**
+ * Returns the relative path from <code>nodeState</code> to
+ * <code>propState</code>.
+ *
+ * @param nodeState a node state.
+ * @param propState a property state.
+ * @return the relative path.
+ * @throws RepositoryException if an error occurs while resolving paths.
+ * @throws ItemStateException if an error occurs while reading item
+ * states.
+ */
+ protected Path getRelativePath(NodeState nodeState, PropertyState propState)
+ throws RepositoryException, ItemStateException {
+ HierarchyManager hmgr = getContext().getHierarchyManager();
+ Path nodePath = hmgr.getPath(nodeState.getId());
+ Path propPath = hmgr.getPath(propState.getId());
+ Path p = nodePath.computeRelativePath(propPath);
+ // make sure it does not contain indexes
+ boolean clean = true;
+ Path.Element[] elements = p.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i].getIndex() != 0) {
+ elements[i] = PATH_FACTORY.createElement(elements[i].getName());
+ clean = false;
+ }
+ }
+ if (!clean) {
+ p = PATH_FACTORY.create(elements);
+ }
+ return p;
+ }
+
+ /**
* Retrieves the root of the indexing aggregate for <code>state</code> and
* puts it into <code>map</code>.
*
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java Mon Feb 23 10:04:53 2009
@@ -18,8 +18,9 @@
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermDocs;
import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.index.TermPositions;
+import org.apache.lucene.index.TermDocs;
import org.apache.lucene.search.SortComparator;
import java.io.IOException;
@@ -27,6 +28,8 @@
import java.util.Map;
import java.util.WeakHashMap;
+import javax.jcr.PropertyType;
+
/**
* Implements a variant of the lucene class <code>org.apache.lucene.search.FieldCacheImpl</code>.
* The lucene FieldCache class has some sort of support for custom comparators
@@ -38,7 +41,7 @@
/**
* Expert: Stores term text values and document ordering data.
*/
- public static class StringIndex {
+ public static class ValueIndex {
/**
* Some heuristic factor that determines whether the array is sparse. Note that if less then
@@ -48,62 +51,62 @@
private static final int SPARSE_FACTOR = 100;
/**
- * Terms indexed by document id.
+ * Values indexed by document id.
*/
- private final String[] terms;
+ private final Comparable[] values;
/**
- * Terms map indexed by document id.
+ * Values (Comparable) map indexed by document id.
*/
- public final Map termsMap;
+ public final Map valuesMap;
/**
- * Boolean indicating whether the hashMap impl has to be used
+ * Boolean indicating whether the {@link #valuesMap} impl has to be used
*/
public final boolean sparse;
/**
* Creates one of these objects
*/
- public StringIndex(String[] terms, int setValues) {
- if (isSparse(terms, setValues)) {
+ public ValueIndex(Comparable[] values, int setValues) {
+ if (isSparse(values, setValues)) {
this.sparse = true;
- this.terms = null;
+ this.values = null;
if (setValues == 0) {
- this.termsMap = null;
+ this.valuesMap = null;
} else {
- this.termsMap = getTermsMap(terms, setValues);
+ this.valuesMap = getValuesMap(values, setValues);
}
} else {
this.sparse = false;
- this.terms = terms;
- this.termsMap = null;
+ this.values = values;
+ this.valuesMap = null;
}
}
- public String getTerm(int i) {
+ public Comparable getValue(int i) {
if (sparse) {
- return termsMap == null ? null : (String) termsMap.get(new Integer(i));
+ return valuesMap == null ? null : (Comparable) valuesMap.get(new Integer(i));
} else {
- return terms[i];
+ return values[i];
}
}
- private Map getTermsMap(String[] terms, int setValues) {
+ private Map getValuesMap(Comparable[] values, int setValues) {
Map map = new HashMap(setValues);
- for (int i = 0; i < terms.length && setValues > 0; i++) {
- if (terms[i] != null) {
- map.put(new Integer(i), terms[i]);
+ for (int i = 0; i < values.length && setValues > 0; i++) {
+ if (values[i] != null) {
+ map.put(new Integer(i), values[i]);
setValues--;
}
}
return map;
}
- private boolean isSparse(String[] terms, int setValues) {
+ private boolean isSparse(Comparable[] values, int setValues) {
// some really simple test to test whether the array is sparse. Currently, when less then 1% is set, the array is already sparse
// for this typical cache to avoid memory issues
- if (setValues * SPARSE_FACTOR < terms.length) {
+ if (setValues * SPARSE_FACTOR < values.length) {
return true;
}
return false;
@@ -127,26 +130,24 @@
}
/**
- * Creates a <code>StringIndex</code> for a <code>field</code> and a term
+ * Creates a <code>ValueIndex</code> for a <code>field</code> and a term
* <code>prefix</code>. The term prefix acts as the property name for the
* shared <code>field</code>.
* <p/>
* This method is an adapted version of: <code>FieldCacheImpl.getStringIndex()</code>
- * The returned string index will <b>not</b> have a term lookup array!
- * See {@link SharedFieldSortComparator} for more info.
*
* @param reader the <code>IndexReader</code>.
* @param field name of the shared field.
* @param prefix the property name, will be used as term prefix.
* @param comparator the sort comparator instance.
- * @return a StringIndex that contains the field values and order
+ * @return a ValueIndex that contains the field values and order
* information.
* @throws IOException if an error occurs while reading from the index.
*/
- public SharedFieldCache.StringIndex getStringIndex(IndexReader reader,
- String field,
- String prefix,
- SortComparator comparator)
+ public ValueIndex getValueIndex(IndexReader reader,
+ String field,
+ String prefix,
+ SortComparator comparator)
throws IOException {
if (reader instanceof ReadOnlyIndexReader) {
@@ -154,12 +155,22 @@
}
field = field.intern();
- SharedFieldCache.StringIndex ret = lookup(reader, field, prefix, comparator);
+ ValueIndex ret = lookup(reader, field, prefix, comparator);
if (ret == null) {
- final String[] retArray = new String[reader.maxDoc()];
+ Comparable[] retArray = new Comparable[reader.maxDoc()];
int setValues = 0;
if (retArray.length > 0) {
- TermDocs termDocs = reader.termDocs();
+ IndexFormatVersion version = IndexFormatVersion.getVersion(reader);
+ boolean hasPayloads = version.isAtLeast(IndexFormatVersion.V3);
+ TermDocs termDocs;
+ byte[] payload = null;
+ int type;
+ if (hasPayloads) {
+ termDocs = reader.termPositions();
+ payload = new byte[1];
+ } else {
+ termDocs = reader.termDocs();
+ }
TermEnum termEnum = reader.terms(new Term(field, prefix));
char[] tmp = new char[16];
@@ -185,8 +196,17 @@
termDocs.seek(termEnum);
while (termDocs.next()) {
+ type = PropertyType.UNDEFINED;
+ if (hasPayloads) {
+ TermPositions termPos = (TermPositions) termDocs;
+ termPos.nextPosition();
+ if (termPos.isPayloadAvailable()) {
+ payload = termPos.getPayload(payload, 0);
+ type = PropertyMetaData.fromByteArray(payload).getPropertyType();
+ }
+ }
setValues++;
- retArray[termDocs.doc()] = value;
+ retArray[termDocs.doc()] = getValue(value, type);
}
} while (termEnum.next());
} finally {
@@ -194,7 +214,7 @@
termEnum.close();
}
}
- SharedFieldCache.StringIndex value = new SharedFieldCache.StringIndex(retArray, setValues);
+ ValueIndex value = new ValueIndex(retArray, setValues);
store(reader, field, prefix, comparator, value);
return value;
}
@@ -202,9 +222,9 @@
}
/**
- * See if a <code>StringIndex</code> object is in the cache.
+ * See if a <code>ValueIndex</code> object is in the cache.
*/
- SharedFieldCache.StringIndex lookup(IndexReader reader, String field,
+ ValueIndex lookup(IndexReader reader, String field,
String prefix, SortComparator comparer) {
Key key = new Key(field, prefix, comparer);
synchronized (this) {
@@ -212,15 +232,15 @@
if (readerCache == null) {
return null;
}
- return (SharedFieldCache.StringIndex) readerCache.get(key);
+ return (ValueIndex) readerCache.get(key);
}
}
/**
- * Put a <code>StringIndex</code> <code>value</code> to cache.
+ * Put a <code>ValueIndex</code> <code>value</code> to cache.
*/
Object store(IndexReader reader, String field, String prefix,
- SortComparator comparer, SharedFieldCache.StringIndex value) {
+ SortComparator comparer, ValueIndex value) {
Key key = new Key(field, prefix, comparer);
synchronized (this) {
HashMap readerCache = (HashMap) cache.get(reader);
@@ -233,6 +253,29 @@
}
/**
+ * Returns a comparable for the given <code>value</code> that is read from
+ * the index.
+ *
+ * @param value the value as read from the index.
+ * @param type the property type.
+ * @return a comparable for the <code>value</code>.
+ */
+ private Comparable getValue(String value, int type) {
+ switch (type) {
+ case PropertyType.BOOLEAN:
+ return ComparableBoolean.valueOf(Boolean.valueOf(value).booleanValue());
+ case PropertyType.DATE:
+ return new Long(DateField.stringToTime(value));
+ case PropertyType.LONG:
+ return new Long(LongField.stringToLong(value));
+ case PropertyType.DOUBLE:
+ return new Double(DoubleField.stringToDouble(value));
+ default:
+ return value;
+ }
+ }
+
+ /**
* A compound <code>Key</code> that consist of <code>field</code>
* <code>prefix</code> and <code>comparator</code>.
*/
@@ -243,7 +286,7 @@
private final SortComparator comparator;
/**
- * Creates <code>Key</code> for StringIndex lookup.
+ * Creates <code>Key</code> for ValueIndex lookup.
*/
Key(String field, String prefix, SortComparator comparator) {
this.field = field.intern();
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java Mon Feb 23 10:04:53 2009
@@ -44,13 +44,6 @@
/**
* Implements a <code>SortComparator</code> which knows how to sort on a lucene
* field that contains values for multiple properties.
- * <p/>
- * <b>Important:</b> The ScoreDocComparator returned by {@link #newComparator}
- * does not implement the contract for {@link ScoreDocComparator#sortValue(ScoreDoc)}
- * properly. The method will always return an empty String to save memory consumption
- * on large property ranges. Those values are only of relevance when queries
- * are executed with a <code>MultiSearcher</code>, which is currently not the
- * case in Jackrabbit.
*/
public class SharedFieldSortComparator extends SortComparator {
@@ -108,15 +101,20 @@
throws IOException {
PathFactory factory = PathFactoryImpl.getInstance();
Path p = factory.create(relPath);
- if (p.getLength() == 1) {
- try {
- return new SimpleScoreDocComparator(reader,
- nsMappings.translatePropertyName(p.getNameElement().getName()));
- } catch (IllegalNameException e) {
- throw Util.createIOException(e);
+ try {
+ ScoreDocComparator simple = new SimpleScoreDocComparator(
+ reader, nsMappings.translatePath(p));
+ if (p.getLength() == 1) {
+ return simple;
+ } else {
+ return new CompoundScoreDocComparator(reader,
+ new ScoreDocComparator[]{
+ simple,
+ new RelPathScoreDocComparator(reader, p)
+ });
}
- } else {
- return new RelPathScoreDocComparator(reader, p);
+ } catch (IllegalNameException e) {
+ throw Util.createIOException(e);
}
}
@@ -250,17 +248,17 @@
/**
* The term look ups of the index segments.
*/
- protected final SharedFieldCache.StringIndex[] indexes;
+ protected final SharedFieldCache.ValueIndex[] indexes;
public SimpleScoreDocComparator(IndexReader reader,
String propertyName)
throws IOException {
super(reader);
- this.indexes = new SharedFieldCache.StringIndex[readers.size()];
+ this.indexes = new SharedFieldCache.ValueIndex[readers.size()];
for (int i = 0; i < readers.size(); i++) {
IndexReader r = (IndexReader) readers.get(i);
- indexes[i] = SharedFieldCache.INSTANCE.getStringIndex(r, field,
+ indexes[i] = SharedFieldCache.INSTANCE.getValueIndex(r, field,
FieldNames.createNamedValue(propertyName, ""),
SharedFieldSortComparator.this);
}
@@ -274,7 +272,7 @@
*/
public Comparable sortValue(ScoreDoc i) {
int idx = readerIndex(i.doc);
- return indexes[idx].getTerm(i.doc - starts[idx]);
+ return indexes[idx].getValue(i.doc - starts[idx]);
}
}
@@ -359,28 +357,34 @@
}
/**
- * Represents a boolean that implement {@link Comparable}. This class can
- * be removed when we move to Java 5.
+ * Implements a compound score doc comparator that delegates to several
+ * other comparators. The comparators are asked for a sort value in the
+ * sequence they are passed to the constructor. The first non-null value
+ * will be returned by {@link #sortValue(ScoreDoc)}.
*/
- private static final class ComparableBoolean implements Comparable {
-
- private static final ComparableBoolean TRUE = new ComparableBoolean(true);
+ private final class CompoundScoreDocComparator
+ extends AbstractScoreDocComparator {
- private static final ComparableBoolean FALSE = new ComparableBoolean(false);
-
- private final boolean value;
-
- private ComparableBoolean(boolean value) {
- this.value = value;
- }
+ private final ScoreDocComparator[] comparators;
- public int compareTo(Object o) {
- ComparableBoolean b = (ComparableBoolean) o;
- return (b.value == value ? 0 : (value ? 1 : -1));
+ public CompoundScoreDocComparator(IndexReader reader,
+ ScoreDocComparator[] comparators)
+ throws IOException {
+ super(reader);
+ this.comparators = comparators;
}
- static ComparableBoolean valueOf(boolean value) {
- return value ? TRUE : FALSE;
+ /**
+ * {@inheritDoc}
+ */
+ public Comparable sortValue(ScoreDoc i) {
+ for (int j = 0; j < comparators.length; j++) {
+ Comparable c = comparators[j].sortValue(i);
+ if (c != null) {
+ return c;
+ }
+ }
+ return null;
}
}
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingletonTokenStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingletonTokenStream.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingletonTokenStream.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingletonTokenStream.java Mon Feb 23 10:04:53 2009
@@ -46,6 +46,15 @@
}
/**
+ * Creates a new SingleTokenStream with the given token.
+ *
+ * @param t the token.
+ */
+ public SingletonTokenStream(Token t) {
+ this.t = t;
+ }
+
+ /**
* {@inheritDoc}
*/
public Token next() {
Added: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/query/lucene/indexing-configuration-1.2.dtd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/query/lucene/indexing-configuration-1.2.dtd?rev=746946&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/query/lucene/indexing-configuration-1.2.dtd (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/query/lucene/indexing-configuration-1.2.dtd Mon Feb 23 10:04:53 2009
@@ -0,0 +1,93 @@
+<!--
+ 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.
+-->
+<!--
+ The configuration element configures the indexing behaviour of the lucene
+ backed query handler in Jackrabbit. It allows you to define indexing
+ aggregates and configure which properties of a node are indexed.
+ This element must contain all the namespace declarations that are used
+ throughout this configuration.
+-->
+<!ELEMENT configuration (aggregate*,index-rule*)>
+
+<!--
+ Each aggregate element defines an indexing aggregate based on the name of a
+ primary node type.
+-->
+<!ELEMENT aggregate (include*,include-property)>
+<!ATTLIST aggregate primaryType CDATA #REQUIRED>
+
+<!--
+ An include element contains a relative path pattern using either an exact
+ node name or *. Nodes that match the path pattern against the root of an
+ indexing aggregate are included in the aggregated node index. An include
+ element may optionally specify a primary node type name that needs to match
+ for the included node.
+-->
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include primaryType CDATA #IMPLIED>
+
+<!--
+ An include-property element contains a relative path to a property. Properties
+ that match the path against the root of an indexing aggregate are included
+ in the aggregated node index. Aggregated properties may be used to speed
+ up sorting of query results when the order by clause references a property
+ with a relative path.
+-->
+<!ELEMENT include-property (#PCDATA)>
+
+<!--
+ An index-rule element defines which properties of a node should be indexed.
+ When a node is indexed the list of index-rules is check for a matching
+ node type and whether the condition is true. If a match is found the
+ property is looked up.
+ The index-rule element also contains a boost value for the entire node
+ being indexed. A value higher than 1.0 will boost the score value for a node
+ that matched this index-rule.
+-->
+<!ELEMENT index-rule (property*)>
+<!ATTLIST index-rule nodeType CDATA #REQUIRED
+ condition CDATA #IMPLIED
+ boost CDATA "1.0">
+
+<!--
+ A property element defines the boost value for a matching property and a
+ flag that indicates whether the value of a string property should also be
+ included in the node scope fulltext index. Both boost and nodeScopeIndex
+ attributes only affect string properties and are ignored if the property
+ is not of type string. If isRegexp is set to true the name of the property
+ is interpreted as a regular expression to match properties on a node. Please
+ note that you may only use a regular expression for the local part of a
+ property name. The attribute useInExcerpt controls whether the contents
+ of the property is used to construct an excerpt. The default value for this
+ attribute is true.
+-->
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property boost CDATA "1.0"
+ nodeScopeIndex CDATA "true"
+ isRegexp CDATA "false"
+ useInExcerpt CDATA "true">
+
+<!--
+ An analyzer element with property elements in it defines which analyzer is to
+ be used for indexing and parsing the full text of this property. If the analyzer
+ class can not be found, the default analyzer is used. The node scope is always
+ indexed with the default analyzer, so might return different results for search
+ queries in some rare cases.
+-->
+<!ELEMENT analyzers (analyzer*)>
+<!ELEMENT analyzer (property*)>
+<!ATTLIST analyzer class CDATA #REQUIRED>
Propchange: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/query/lucene/indexing-configuration-1.2.dtd
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/IndexingAggregateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/IndexingAggregateTest.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/IndexingAggregateTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/IndexingAggregateTest.java Mon Feb 23 10:04:53 2009
@@ -18,12 +18,18 @@
import javax.jcr.RepositoryException;
import javax.jcr.Node;
+import javax.jcr.query.Query;
+
import java.io.ByteArrayOutputStream;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Calendar;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
/**
* <code>IndexingAggregateTest</code> checks if the nt:file nt:resource
@@ -89,4 +95,96 @@
executeSQLQuery(sqlCat, new Node[]{file});
}
+
+ public void testContentLastModified() throws RepositoryException {
+ List expected = new ArrayList();
+ long time = System.currentTimeMillis();
+ for (int i = 0; i < 10; i++) {
+ expected.add(addFile(testRootNode, "file" + i, time));
+ time += 1000;
+ }
+ testRootNode.save();
+
+ String stmt = testPath + "/* order by jcr:content/@jcr:lastModified";
+ Query q = qm.createQuery(stmt, Query.XPATH);
+ checkResultSequence(q.execute().getRows(), (Node[]) expected.toArray(new Node[expected.size()]));
+
+ // descending
+ stmt = testPath + "/* order by jcr:content/@jcr:lastModified descending";
+ q = qm.createQuery(stmt, Query.XPATH);
+ Collections.reverse(expected);
+ checkResultSequence(q.execute().getRows(), (Node[]) expected.toArray(new Node[expected.size()]));
+
+ // reverse order in content
+ for (Iterator it = expected.iterator(); it.hasNext(); ) {
+ Node file = (Node) it.next();
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(time);
+ file.getNode("jcr:content").setProperty("jcr:lastModified", cal);
+ time -= 1000;
+ }
+ testRootNode.save();
+
+ stmt = testPath + "/* order by jcr:content/@jcr:lastModified descending";
+ q = qm.createQuery(stmt, Query.XPATH);
+ checkResultSequence(q.execute().getRows(), (Node[]) expected.toArray(new Node[expected.size()]));
+ }
+
+ public void disabled_testPerformance() throws RepositoryException {
+ createNodes(testRootNode, 10, 4, 0, new NodeCreationCallback() {
+ public void nodeCreated(Node node, int count) throws
+ RepositoryException {
+ node.addNode("child").setProperty("property", "value" + count);
+ // save once in a while
+ if (count % 1000 == 0) {
+ session.save();
+ System.out.println("added " + count + " nodes so far.");
+ }
+ }
+ });
+ session.save();
+
+ String xpath = testPath + "//*[child/@property] order by child/@property";
+ for (int i = 0; i < 3; i++) {
+ long time = System.currentTimeMillis();
+ Query query = qm.createQuery(xpath, Query.XPATH);
+ ((QueryImpl) query).setLimit(20);
+ query.execute().getNodes().getSize();
+ time = System.currentTimeMillis() - time;
+ System.out.println("executed query in " + time + " ms.");
+ }
+ }
+
+ private static Node addFile(Node folder, String name, long lastModified)
+ throws RepositoryException {
+ Node file = folder.addNode(name, "nt:file");
+ Node resource = file.addNode("jcr:content", "nt:resource");
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(lastModified);
+ resource.setProperty("jcr:lastModified", cal);
+ resource.setProperty("jcr:encoding", "UTF-8");
+ resource.setProperty("jcr:mimeType", "text/plain");
+ resource.setProperty("jcr:data", new ByteArrayInputStream("test".getBytes()));
+ return file;
+ }
+
+ private int createNodes(Node n, int nodesPerLevel, int levels,
+ int count, NodeCreationCallback callback)
+ throws RepositoryException {
+ levels--;
+ for (int i = 0; i < nodesPerLevel; i++) {
+ Node child = n.addNode("node" + i);
+ count++;
+ callback.nodeCreated(child, count);
+ if (levels > 0) {
+ count = createNodes(child, nodesPerLevel, levels, count, callback);
+ }
+ }
+ return count;
+ }
+
+ private static interface NodeCreationCallback {
+
+ public void nodeCreated(Node node, int count) throws RepositoryException;
+ }
}
Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java?rev=746946&r1=746945&r2=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/OrderByTest.java Mon Feb 23 10:04:53 2009
@@ -145,31 +145,6 @@
checkChildAxis(new Value[]{getValue(2.0), getValue(1)});
}
- public void disabled_testPerformance() throws RepositoryException {
- createNodes(testRootNode, 10, 4, 0, new NodeCreationCallback() {
- public void nodeCreated(Node node, int count) throws
- RepositoryException {
- node.addNode("child").setProperty("property", "value" + count);
- // save once in a while
- if (count % 1000 == 0) {
- superuser.save();
- System.out.println("added " + count + " nodes so far.");
- }
- }
- });
- superuser.save();
-
- String xpath = testPath + "//*[child/@property] order by child/@property";
- for (int i = 0; i < 3; i++) {
- long time = System.currentTimeMillis();
- Query query = qm.createQuery(xpath, Query.XPATH);
- ((QueryImpl) query).setLimit(20);
- query.execute().getNodes().getSize();
- time = System.currentTimeMillis() - time;
- System.out.println("executed query in " + time + " ms.");
- }
- }
-
//------------------------------< helper >----------------------------------
private Value getValue(String value) throws RepositoryException {
@@ -208,27 +183,55 @@
* @throws RepositoryException if an error occurs.
*/
private void checkChildAxis(Value[] values) throws RepositoryException {
+ // child/prop is part of the test indexing configuration,
+ // this will use SimpleScoreDocComparator internally
+ checkChildAxis(values, "child", "prop");
+ cleanUpTestRoot(superuser);
+ // c/p is not in the indexing configuration,
+ // this will use RelPathScoreDocComparator internally
+ checkChildAxis(values, "c", "p");
+ }
+
+ /**
+ * Checks if order by with a relative path works on the the passed values.
+ * The values are expected to be in ascending order.
+ *
+ * @param values the values in ascending order.
+ * @param child the name of the child node.
+ * @param property the name of the property.
+ * @throws RepositoryException if an error occurs.
+ */
+ private void checkChildAxis(Value[] values, String child, String property)
+ throws RepositoryException {
+ List vals = new ArrayList();
+ // add initial value null -> property not set
+ // inexistent property is always less than any property value set
+ vals.add(null);
+ vals.addAll(Arrays.asList(values));
+
List expected = new ArrayList();
- for (int i = 0; i < values.length; i++) {
+ for (int i = 0; i < vals.size(); i++) {
Node n = testRootNode.addNode("node" + i);
expected.add(n.getPath());
- n.addNode("child").setProperty("prop", values[i]);
+ Node c = n.addNode(child);
+ if (vals.get(i) != null) {
+ c.setProperty(property, (Value) vals.get(i));
+ }
}
testRootNode.save();
- String xpath = testPath + "/* order by child/@prop";
+ String xpath = testPath + "/* order by " + child + "/@" + property;
assertEquals(expected, collectPaths(executeQuery(xpath)));
// descending
Collections.reverse(expected);
- xpath = testPath + "/* order by child/@prop descending";
+ xpath += " descending";
assertEquals(expected, collectPaths(executeQuery(xpath)));
- // reverse order in content
- Collections.reverse(Arrays.asList(values));
- for (int i = 0; i < values.length; i++) {
- Node child = testRootNode.getNode("node" + i).getNode("child");
- child.setProperty("prop", values[i]);
+ Collections.reverse(vals);
+ for (int i = 0; i < vals.size(); i++) {
+ Node c = testRootNode.getNode("node" + i).getNode(child);
+ c.setProperty(property, (Value) vals.get(i));
}
testRootNode.save();
@@ -244,24 +247,4 @@
}
return paths;
}
-
- private int createNodes(Node n, int nodesPerLevel, int levels,
- int count, NodeCreationCallback callback)
- throws RepositoryException {
- levels--;
- for (int i = 0; i < nodesPerLevel; i++) {
- Node child = n.addNode("node" + i);
- count++;
- callback.nodeCreated(child, count);
- if (levels > 0) {
- count = createNodes(child, nodesPerLevel, levels, count, callback);
- }
- }
- return count;
- }
-
- private static interface NodeCreationCallback {
-
- public void nodeCreated(Node node, int count) throws RepositoryException;
- }
}
Copied: jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/indexing-configuration.xml (from r744177, jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/indexing-test/indexing-configuration.xml)
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/indexing-configuration.xml?p2=jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/indexing-configuration.xml&p1=jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/indexing-test/indexing-configuration.xml&r1=744177&r2=746946&rev=746946&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/indexing-test/indexing-configuration.xml (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/repository/workspaces/default/indexing-configuration.xml Mon Feb 23 10:04:53 2009
@@ -1,49 +1,10 @@
<?xml version="1.0"?>
-<!DOCTYPE configuration SYSTEM "http://jackrabbit.apache.org/dtd/indexing-configuration-1.1.dtd">
+<!DOCTYPE configuration SYSTEM "http://jackrabbit.apache.org/dtd/indexing-configuration-1.2.dtd">
<configuration xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
- <index-rule nodeType="nt:unstructured" condition="@rule='boost1'">
- <!-- default boost: 1.0 -->
- <property>text</property>
- </index-rule>
-
- <index-rule nodeType="nt:unstructured" condition="@rule='boost2'">
- <!-- boost: 2.0 -->
- <property boost="2.0">text</property>
- </index-rule>
-
- <index-rule nodeType="nt:unstructured" condition="@rule='boost3'">
- <!-- boost: 3.0 -->
- <property boost="3.0">text</property>
- </index-rule>
-
- <index-rule nodeType="nt:unstructured" condition="@rule='nsiTrue'">
- <!-- default value for nodeScopeIndex is true -->
- <property>text</property>
- </index-rule>
-
- <index-rule nodeType="nt:unstructured" condition="@rule='nsiFalse'">
- <!-- do not include text in node scope index -->
- <property nodeScopeIndex="false">text</property>
- </index-rule>
-
- <index-rule nodeType="nt:unstructured" condition="@rule='regexp'">
- <property isRegexp="true">.*Text</property>
- </index-rule>
-
- <index-rule nodeType="nt:unstructured" condition="@rule='excerpt'">
- <property useInExcerpt="false">title</property>
- <property>text</property>
- </index-rule>
-
- <index-rule nodeType="nt:hierarchyNode">
- <!-- do not index any properties -->
- </index-rule>
-
- <aggregate primaryType="nt:file">
- <include>jcr:content</include>
- <include>jcr:content/*</include>
+ <aggregate primaryType="nt:unstructured">
+ <include-property>child/prop</include-property>
</aggregate>
</configuration>
\ No newline at end of file