You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2012/07/01 22:22:30 UTC
svn commit: r1356004 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/lucene/
main/java/org/apache/jackrabbit/oak/query/index/
main/java/org/apache/jackrabbit/oak/spi/
test/java/org/apache/jackrabbit/oak/plugins/lucene/
Author: jukka
Date: Sun Jul 1 20:22:29 2012
New Revision: 1356004
URL: http://svn.apache.org/viewvc?rev=1356004&view=rev
Log:
OAK-154: Full text search index
Add a Lucene-based QueryIndexProvider
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndexProvider.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/OakDirectory.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java?rev=1356004&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndex.java Sun Jul 1 20:22:29 2012
@@ -0,0 +1,188 @@
+/*
+ * 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.plugins.lucene;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.jackrabbit.oak.spi.Cursor;
+import org.apache.jackrabbit.oak.spi.Filter;
+import org.apache.jackrabbit.oak.spi.Filter.PropertyRestriction;
+import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause.Occur;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.PrefixQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TermRangeQuery;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+
+public class LuceneIndex implements QueryIndex {
+
+ private final NodeStore store;
+
+ private final String[] path;
+
+ public LuceneIndex(NodeStore store, String... path) {
+ this.store = store;
+ this.path = path;
+ }
+
+ @Override
+ public String getIndexName() {
+ return "lucene";
+ }
+
+ @Override
+ public double getCost(Filter filter) {
+ return 1.0;
+ }
+
+ @Override
+ public String getPlan(Filter filter) {
+ return getQuery(filter).toString();
+ }
+
+ @Override
+ public Cursor query(Filter filter, String revisionId) {
+ try {
+ Directory directory =
+ new OakDirectory(store, store.getRoot(), path);
+ try {
+ IndexReader reader = IndexReader.open(directory);
+ try {
+ IndexSearcher searcher = new IndexSearcher(reader);
+ try {
+ Collection<String> paths = new ArrayList<String>();
+
+ Query query = getQuery(filter);
+ if (query != null) {
+ TopDocs docs = searcher.search(query, Integer.MAX_VALUE);
+ for (ScoreDoc doc : docs.scoreDocs) {
+ String path = reader.document(doc.doc).get(":path");
+ if ("".equals(path)) {
+ paths.add("/");
+ } else if (path != null) {
+ paths.add(path);
+ }
+ }
+ }
+
+ return new PathCursor(paths);
+ } finally {
+ searcher.close();
+ }
+ } finally {
+ reader.close();
+ }
+ } finally {
+ directory.close();
+ }
+ } catch (IOException e) {
+ return new PathCursor(Collections.<String>emptySet());
+ }
+ }
+
+ private Query getQuery(Filter filter) {
+ List<Query> qs = new ArrayList<Query>();
+
+ String path = filter.getPath();
+ if (path.equals("/")) {
+ path = "";
+ }
+ switch (filter.getPathRestriction()) {
+ case ALL_CHILDREN:
+ qs.add(new PrefixQuery(new Term(":path", path + "/")));
+ break;
+ case DIRECT_CHILDREN:
+ qs.add(new PrefixQuery(new Term(":path", path + "/"))); // FIXME
+ break;
+ case EXACT:
+ qs.add(new TermQuery(new Term(":path", path)));
+ break;
+ case PARENT:
+ int slash = path.lastIndexOf('/');
+ if (slash != -1) {
+ String parent = path.substring(0, slash);
+ qs.add(new TermQuery(new Term(":path", parent)));
+ } else {
+ return null; // there's no parent of the root node
+ }
+ break;
+ }
+
+ for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
+ String name = pr.propertyName;
+ String first = pr.first.getString();
+ String last = pr.last.getString();
+ if (first .equals(last) && pr.firstIncluding && pr.lastIncluding) {
+ qs.add(new TermQuery(new Term(name, first)));
+ } else {
+ qs.add(new TermRangeQuery(
+ name, first, last, pr.firstIncluding, pr.lastIncluding));
+ }
+ }
+
+ if (qs.size() > 1) {
+ BooleanQuery bq = new BooleanQuery();
+ for (Query q : qs) {
+ bq.add(q, Occur.MUST);
+ }
+ return bq;
+ } else {
+ return qs.get(1);
+ }
+ }
+
+ private static class PathCursor implements Cursor {
+
+ private final Iterator<String> iterator;
+
+ private String path = null;
+
+ public PathCursor(Collection<String> paths) {
+ this.iterator = paths.iterator();
+ }
+
+ public boolean next() {
+ if (iterator.hasNext()) {
+ path = iterator.next();
+ return true;
+ } else {
+ path = null;
+ return false;
+ }
+ }
+
+ @Override
+ public String currentPath() {
+ return path;
+ }
+
+ };
+
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndexProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndexProvider.java?rev=1356004&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndexProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneIndexProvider.java Sun Jul 1 20:22:29 2012
@@ -0,0 +1,37 @@
+/*
+ * 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.plugins.lucene;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
+import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.commit.EmptyEditor;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+
+public class LuceneIndexProvider implements QueryIndexProvider {
+
+ @Override
+ public List<QueryIndex> getQueryIndexes(MicroKernel mk) {
+ NodeStore store = new KernelNodeStore(mk, EmptyEditor.INSTANCE);
+ return Collections.<QueryIndex>singletonList(new LuceneIndex(store));
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/OakDirectory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/OakDirectory.java?rev=1356004&r1=1356003&r2=1356004&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/OakDirectory.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/lucene/OakDirectory.java Sun Jul 1 20:22:29 2012
@@ -60,7 +60,7 @@ class OakDirectory extends Directory {
NodeState state = root;
builders[0] = store.getBuilder(state);
for (int i = 0; i < path.length; i++) {
- NodeState child = root.getChildNode(path[i]);
+ NodeState child = state.getChildNode(path[i]);
if (child == null) {
builders[i + 1] = store.getBuilder(null);
state = builders[i + 1].getNodeState();
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java?rev=1356004&r1=1356003&r2=1356004&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java Sun Jul 1 20:22:29 2012
@@ -24,6 +24,7 @@ import org.apache.jackrabbit.oak.query.a
import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
import org.apache.jackrabbit.oak.spi.Filter;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map.Entry;
@@ -133,6 +134,11 @@ public class FilterImpl implements Filte
return selector;
}
+ @Override
+ public Collection<PropertyRestriction> getPropertyRestrictions() {
+ return propertyRestrictions.values();
+ }
+
/**
* Get the restriction for the given property, if any.
*
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java?rev=1356004&r1=1356003&r2=1356004&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java Sun Jul 1 20:22:29 2012
@@ -18,6 +18,8 @@
*/
package org.apache.jackrabbit.oak.spi;
+import java.util.Collection;
+
import org.apache.jackrabbit.oak.api.CoreValue;
/**
@@ -25,6 +27,8 @@ import org.apache.jackrabbit.oak.api.Cor
*/
public interface Filter {
+ Collection<PropertyRestriction> getPropertyRestrictions();
+
/**
* Get the property restriction for the given property, if any.
*
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java?rev=1356004&r1=1356003&r2=1356004&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/lucene/LuceneEditorTest.java Sun Jul 1 20:22:29 2012
@@ -17,6 +17,8 @@
package org.apache.jackrabbit.oak.plugins.lucene;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import org.apache.jackrabbit.mk.api.MicroKernel;
import org.apache.jackrabbit.mk.core.MicroKernelImpl;
@@ -26,33 +28,38 @@ import org.apache.jackrabbit.oak.core.De
import org.apache.jackrabbit.oak.core.RootImpl;
import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
import org.apache.jackrabbit.oak.plugins.memory.MemoryValueFactory;
-import org.apache.lucene.index.IndexReader;
+import org.apache.jackrabbit.oak.query.ast.Operator;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.Cursor;
+import org.apache.jackrabbit.oak.spi.Filter;
+import org.apache.jackrabbit.oak.spi.QueryIndex;
import org.apache.lucene.store.Directory;
import org.junit.Test;
public class LuceneEditorTest {
- // @Test
+ @Test
public void testLucene() throws Exception {
MicroKernel mk = new MicroKernelImpl();
KernelNodeStore store = new KernelNodeStore(
mk, new LuceneEditor("jcr:system", "oak:lucene"));
Root root = new RootImpl(store, "");
Tree tree = root.getTree("/");
- System.out.println(store.getRoot());
tree.setProperty("foo", MemoryValueFactory.INSTANCE.createValue("bar"));
root.commit(DefaultConflictHandler.OURS);
- Directory directory = new OakDirectory(
- store, store.getRoot(), "jcr:system", "oak:lucene");
- System.out.println(store.getRoot());
- IndexReader reader = IndexReader.open(directory);
- try {
- assertEquals(1, reader.numDocs());
- } finally {
- reader.close();
- }
+ QueryIndex index = new LuceneIndex(store, "jcr:system", "oak:lucene");
+ FilterImpl filter = new FilterImpl(null);
+ filter.restrictPath("/", Filter.PathRestriction.EXACT);
+ filter.restrictProperty(
+ "foo",
+ Operator.EQUAL,
+ MemoryValueFactory.INSTANCE.createValue("bar"));
+ Cursor cursor = index.query(filter, null);
+ assertTrue(cursor.next());
+ assertEquals("/", cursor.currentPath());
+ assertFalse(cursor.next());
}
}