blob: 69c0a6f8db90bf63b29665afdc086d37ae4d04af [file] [log] [blame]
/*
* 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.index.lucene;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.common.collect.ImmutableList;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.commons.CIHelper;
import org.apache.jackrabbit.oak.plugins.blob.datastore.CachingFileDataStore;
import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreBlobStore;
import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils;
import org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider;
import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
import org.apache.jackrabbit.oak.plugins.index.lucene.FieldFactory;
import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker;
import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants;
import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexDefinition;
import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexNode;
import org.apache.jackrabbit.oak.plugins.index.lucene.directory.OakDirectory;
import org.apache.jackrabbit.oak.plugins.index.lucene.writer.MultiplexersLucene;
import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
import org.apache.jackrabbit.oak.plugins.index.search.FieldNames;
import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
import org.apache.jackrabbit.oak.plugins.index.search.IndexFormatVersion;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.commit.EditorHook;
import org.apache.jackrabbit.oak.spi.mount.Mount;
import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
import org.apache.jackrabbit.oak.spi.mount.Mounts;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
import org.apache.jackrabbit.test.ISO8601;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static com.google.common.collect.ImmutableSet.of;
import static javax.jcr.PropertyType.TYPENAME_STRING;
import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.VERSION;
import static org.apache.jackrabbit.oak.plugins.index.lucene.TestUtil.newLuceneIndexDefinitionV2;
import static org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.newLuceneIndexDefinition;
import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.INCLUDE_PROPERTY_NAMES;
import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
@RunWith(Parameterized.class)
public class LuceneIndexEditorTest {
private EditorHook HOOK;
private NodeState root = INITIAL_CONTENT;
private NodeBuilder builder = root.builder();
private IndexTracker tracker = new IndexTracker();
private LuceneIndexNode indexNode;
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
@Parameterized.Parameter
public boolean useBlobStore;
@Parameterized.Parameters(name = "{index}: useBlobStore ({0})")
public static List<Boolean[]> fixtures() {
return ImmutableList.of(new Boolean[] {true}, new Boolean[] {false});
}
@Before
public void setup() throws Exception {
if (useBlobStore) {
LuceneIndexEditorProvider provider = new LuceneIndexEditorProvider();
CachingFileDataStore ds = DataStoreUtils
.createCachingFDS(temporaryFolder.newFolder().getAbsolutePath(),
temporaryFolder.newFolder().getAbsolutePath());
provider.setBlobStore(new DataStoreBlobStore(ds));
HOOK = new EditorHook(new IndexUpdateProvider(provider));
} else {
HOOK = new EditorHook(new IndexUpdateProvider(new LuceneIndexEditorProvider()));
}
}
@Test
public void testLuceneWithFullText() throws Exception {
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder idxnb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
LuceneIndexDefinition defn = new LuceneIndexDefinition(root, idxnb.getNodeState(), "/foo");
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
builder.child("test").setProperty("price", 100);
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
//system fields starts with ':' so need to be escaped
assertEquals("/test", query(escape(FieldNames.createAnalyzedFieldName("foo"))+":fox", defn));
assertNull("Non string properties not indexed by default",
getPath(NumericRangeQuery.newLongRange("price", 100L, 100L, true, true)));
}
@Test
public void noChangeIfNonIndexedDelete() throws Exception{
NodeState before = builder.getNodeState();
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene", of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"), STRINGS));
builder.child("test").setProperty("foo", "bar");
builder.child("test").child("a");
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertEquals("/test", getPath(new TermQuery(new Term("foo", "bar"))));
NodeState luceneIdxState1 = NodeStateUtils.getNode(indexed, "/oak:index/lucene");
before = indexed;
builder = indexed.builder();
builder.getChildNode("test").getChildNode("a").remove();
after = builder.getNodeState();
indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
NodeState luceneIdxState2 = NodeStateUtils.getNode(indexed, "/oak:index/lucene");
assertEquals(luceneIdxState1, luceneIdxState2);
}
private String escape(String name) {
return name.replace(":", "\\:");
}
@Test
public void testLuceneWithNonFullText() throws Exception {
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo", "price", "weight", "bool", "creationTime"), STRINGS));
LuceneIndexDefinition defn = new LuceneIndexDefinition(root, nb.getNodeState(), "/foo");
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
builder.child("test").setProperty("bar", "kite is flying");
builder.child("test").setProperty("price", 100);
builder.child("test").setProperty("weight", 10.0);
builder.child("test").setProperty("bool", true);
builder.child("test").setProperty("truth", true);
builder.child("test").setProperty("creationTime", createCal("05/06/2014"));
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertNull("Fulltext search should not work", query("foo:fox",defn));
assertEquals("/test", getPath(new TermQuery(new Term("foo", "fox is jumping"))));
assertNull("bar must NOT be indexed", getPath(new TermQuery(new Term("bar", "kite is flying"))));
//Long
assertEquals("/test", getPath(NumericRangeQuery.newDoubleRange("weight", 8D, 12D, true, true)));
//Double
assertEquals("/test", getPath(NumericRangeQuery.newLongRange("price", 100L, 100L, true, true)));
//Boolean
assertEquals("/test", getPath(new TermQuery(new Term("bool", "true"))));
assertNull("truth must NOT be indexed", getPath(new TermQuery(new Term("truth", "true"))));
//Date
assertEquals("/test", getPath(NumericRangeQuery.newLongRange("creationTime",
dateToTime("05/05/2014"), dateToTime("05/07/2014"), true, true)));
}
@Test
public void noOfDocsIndexedNonFullText() throws Exception {
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"), STRINGS));
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
builder.child("test2").setProperty("bar", "kite is flying");
builder.child("test3").setProperty("foo", "wind is blowing");
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertEquals(2, getSearcher().getIndexReader().numDocs());
}
@Test
public void saveDirectoryListing() throws Exception {
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
nb.setProperty(LuceneIndexConstants.SAVE_DIR_LISTING, true);
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"), STRINGS));
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
NodeState dir = indexed.getChildNode("oak:index").getChildNode("lucene").getChildNode(":data");
assertTrue(dir.hasProperty(OakDirectory.PROP_DIR_LISTING));
}
/**
* 1. Index property foo in /test
* 2. Then modify some other property in /test
*
* This should not cause the index to be updated
*/
@Test
public void nonIncludedPropertyChange() throws Exception {
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"),
STRINGS));
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
builder.child("test2").setProperty("foo", "bird is chirping");
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertEquals(2, getSearcher().getIndexReader().numDocs());
assertEquals("/test", getPath(new TermQuery(new Term("foo", "fox is jumping"))));
releaseIndexNode();
before = indexed;
builder = before.builder();
builder.child("test").setProperty("bar", "kite is flying");
after = builder.getNodeState();
indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertEquals(2, getSearcher().getIndexReader().numDocs());
assertEquals("change in non included property should not cause " +
"index update",0, getSearcher().getIndexReader().numDeletedDocs());
}
@Test
public void testLuceneWithRelativeProperty() throws Exception {
// OAK-6833
assumeFalse(CIHelper.windows());
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo", "jcr:content/mime",
"jcr:content/metadata/type"), STRINGS));
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
builder.child("test").child("jcr:content").setProperty("mime", "text");
builder.child("test").child("jcr:content").child("metadata").setProperty("type", "image");
builder.child("jcr:content").setProperty("count", "text");
builder.child("jcr:content").child("boom").child("metadata").setProperty("type", "image");
NodeState after = builder.getNodeState();
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertEquals(1, getSearcher().getIndexReader().numDocs());
assertEquals("/test", getPath(new TermQuery(new Term("foo", "fox is jumping"))));
assertEquals("/test", getPath(new TermQuery(new Term("jcr:content/mime", "text"))));
assertEquals("/test", getPath(new TermQuery(new Term("jcr:content/metadata/type", "image"))));
assertNull("bar must NOT be indexed", getPath(new TermQuery(new Term("count", "text"))));
releaseIndexNode();
before = indexed;
builder = before.builder();
builder.child("test").child("jcr:content").setProperty("mime", "pdf");
after = builder.getNodeState();
indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertEquals("/test", getPath(new TermQuery(new Term("jcr:content/mime", "pdf"))));
releaseIndexNode();
before = indexed;
builder = before.builder();
builder.child("test").child("jcr:content").remove();
after = builder.getNodeState();
indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
assertNull("removes must be persisted too, 1st level",
getPath(new TermQuery(new Term("jcr:content/mime", "pdf"))));
assertNull("removes must be persisted too, 2nd level",
getPath(new TermQuery(new Term("jcr:content/metadata/type",
"image"))));
}
@Test
public void indexVersionSwitchOnReindex() throws Exception{
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinition(index, "lucene",
of(TYPENAME_STRING));
//1. Trigger a index so that next index step does not see it as a fresh index
NodeState indexed = HOOK.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
builder = indexed.builder();
//By default logic would use current version. To simulate upgrade we forcefully set
//version to V1
builder.child(INDEX_DEFINITIONS_NAME).child("lucene").setProperty(IndexDefinition.INDEX_VERSION,
IndexFormatVersion.V1.getVersion());
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
NodeState after = builder.getNodeState();
indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
assertEquals(IndexFormatVersion.V1, new IndexDefinition(root,
indexed.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("lucene"), "/foo").getVersion());
//3. Trigger a reindex and version should switch to current
builder = indexed.builder();
before = indexed;
builder.child(INDEX_DEFINITIONS_NAME).child("lucene").setProperty(IndexConstants.REINDEX_PROPERTY_NAME, true);
after = builder.getNodeState();
indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
assertEquals(IndexFormatVersion.getDefault(), new IndexDefinition(root,
indexed.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("lucene"), "/foo").getVersion());
}
@Test
public void autoFormatUpdate() throws Exception{
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
of(TYPENAME_STRING));
//1. Trigger a index so that next index step does not see it as a fresh index
NodeState indexed = HOOK.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
IndexDefinition defn = new IndexDefinition(root, indexed.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("lucene"), "/foo");
assertFalse(defn.isOfOldFormat());
}
@Test
public void copyOnWriteAndLocks() throws Exception {
assumeFalse(CIHelper.windows());
ExecutorService executorService = Executors.newFixedThreadPool(2);
IndexCopier copier = new IndexCopier(executorService, temporaryFolder.getRoot());
FailOnDemandEditorProvider failingProvider = new FailOnDemandEditorProvider();
EditorHook hook = new EditorHook(
new IndexUpdateProvider(
new CompositeIndexEditorProvider(
failingProvider,
new LuceneIndexEditorProvider(copier))));
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene", of(TYPENAME_STRING));
IndexUtils.createIndexDefinition(index, "failingIndex", false, false, of("foo"), null);
//1. Get initial set indexed. So that next cycle is normal indexing
NodeState indexed = hook.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
builder = indexed.builder();
NodeState before = indexed;
builder.child("test").setProperty("a", "fox is jumping");
NodeState after = builder.getNodeState();
//2. Ensure that Lucene gets triggered but close is not called
failingProvider.setShouldFail(true);
try {
hook.processCommit(before, after, CommitInfo.EMPTY);
fail();
} catch (CommitFailedException ignore){
}
//3. Disable the troubling editor
failingProvider.setShouldFail(false);
//4. Now commit should process fine
hook.processCommit(before, after, CommitInfo.EMPTY);
executorService.shutdown();
}
@Test
public void multiplexingWriter() throws Exception{
newLucenePropertyIndex("lucene", "foo");
MountInfoProvider mip = Mounts.newBuilder()
.mount("foo", "/libs", "/apps").build();
EditorHook hook = new EditorHook(
new IndexUpdateProvider(
new LuceneIndexEditorProvider(null, new ExtractedTextCache(0, 0), null, mip)));
NodeState indexed = hook.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
builder = indexed.builder();
NodeState before = indexed;
builder.child("content").child("en").setProperty("foo", "bar");
builder.child("libs").child("install").setProperty("foo", "bar");
NodeState after = builder.getNodeState();
indexed = hook.processCommit(before, after, CommitInfo.EMPTY);
builder = indexed.builder();
assertEquals(1, numDocs(mip.getMountByName("foo")));
assertEquals(1, numDocs(mip.getDefaultMount()));
}
private int numDocs(Mount m) throws IOException {
String indexDirName = MultiplexersLucene.getIndexDirName(m);
NodeBuilder defnBuilder = builder.child(INDEX_DEFINITIONS_NAME).child("lucene");
Directory d = new OakDirectory(defnBuilder, indexDirName, new LuceneIndexDefinition(root, defnBuilder.getNodeState(), "/foo"), true);
IndexReader r = DirectoryReader.open(d);
return r.numDocs();
}
//@Test
public void checkLuceneIndexFileUpdates() throws Exception{
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinition(index, "lucene",
of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo" , "bar", "baz"), STRINGS));
//nb.removeProperty(REINDEX_PROPERTY_NAME);
NodeState before = builder.getNodeState();
builder.child("test").setProperty("foo", "fox is jumping");
//InfoStream.setDefault(new PrintStreamInfoStream(System.out));
before = commitAndDump(before, builder.getNodeState());
builder = before.builder();
builder.child("test2").setProperty("bar", "ship is sinking");
before = commitAndDump(before, builder.getNodeState());
builder = before.builder();
builder.child("test3").setProperty("baz", "horn is blowing");
before = commitAndDump(before, builder.getNodeState());
builder = before.builder();
builder.child("test2").remove();
before = commitAndDump(before, builder.getNodeState());
builder = before.builder();
builder.child("test2").setProperty("bar", "ship is back again");
before = commitAndDump(before, builder.getNodeState());
}
@After
public void releaseIndexNode(){
if(indexNode != null){
indexNode.release();
}
indexNode = null;
}
private NodeState newLucenePropertyIndex(String indexName, String propName){
NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
NodeBuilder nb = newLuceneIndexDefinitionV2(index, indexName,
of(TYPENAME_STRING));
nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of(propName), STRINGS));
return builder.getNodeState();
}
private String query(String query, LuceneIndexDefinition defn) throws IOException, ParseException {
QueryParser queryParser = new QueryParser(VERSION, "", defn.getAnalyzer());
return getPath(queryParser.parse(query));
}
private String getPath(Query query) throws IOException {
TopDocs td = getSearcher().search(query, 100);
if (td.totalHits > 0){
if(td.totalHits > 1){
fail("More than 1 result found for query " + query);
}
return getSearcher().getIndexReader().document(td.scoreDocs[0].doc).get(FieldNames.PATH);
}
return null;
}
private IndexSearcher getSearcher(){
if(indexNode == null){
indexNode = tracker.acquireIndexNode("/oak:index/lucene");
}
return indexNode.getSearcher();
}
private NodeState commitAndDump(NodeState before, NodeState after) throws CommitFailedException, IOException {
NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
tracker.update(indexed);
dumpIndexDir();
return indexed;
}
private void dumpIndexDir() throws IOException {
Directory dir = ((DirectoryReader)getSearcher().getIndexReader()).directory();
System.out.println("================");
String[] fileNames = dir.listAll();
Arrays.sort(fileNames);
for (String file : fileNames){
System.out.printf("%s - %d %n", file, dir.fileLength(file));
}
releaseIndexNode();
}
public static Calendar createCal(String dt) throws java.text.ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(dt));
return cal;
}
static long dateToTime(String dt) throws java.text.ParseException {
return FieldFactory.dateToLong(ISO8601.format(createCal(dt)));
}
private static class FailOnDemandEditorProvider implements IndexEditorProvider {
private boolean shouldFail;
@Override
public Editor getIndexEditor(@NotNull String type, @NotNull NodeBuilder definition,
@NotNull NodeState root,
@NotNull IndexUpdateCallback callback) throws CommitFailedException {
if (PropertyIndexEditorProvider.TYPE.equals(type)) {
return new FailOnDemandEditor();
}
return null;
}
public void setShouldFail(boolean shouldFail) {
this.shouldFail = shouldFail;
}
private class FailOnDemandEditor extends DefaultEditor implements IndexEditor {
@Override
public void leave(NodeState before, NodeState after)
throws CommitFailedException {
throwExceptionIfTold();
super.leave(before, after);
}
void throwExceptionIfTold() throws CommitFailedException {
if (shouldFail) {
throw new CommitFailedException("commit",1 , null);
}
}
}
}
}