diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextFactory.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextFactory.java index d855d3dfafc0c..10ab2d4d60024 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextFactory.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextFactory.java @@ -31,6 +31,7 @@ import org.neo4j.kernel.api.impl.index.IndexWriterConfigs; import org.neo4j.kernel.api.impl.index.builder.LuceneIndexStorageBuilder; import org.neo4j.kernel.api.impl.index.partition.WritableIndexPartitionFactory; +import org.neo4j.kernel.api.impl.index.storage.PartitionedIndexStorage; /** * Used for creating {@link LuceneFulltext} and registering those to a {@link FulltextProvider}. @@ -39,44 +40,64 @@ public class FulltextFactory { public static final String INDEX_DIR = "fulltext"; private final FileSystemAbstraction fileSystem; + private final FulltextProvider provider; private final WritableIndexPartitionFactory partitionFactory; private final File indexDir; private final Analyzer analyzer; /** * Creates a factory for the specified location and analyzer. + * * @param fileSystem The filesystem to use. * @param storeDir Store directory of the database. - * @param analyzer The Lucene analyzer to use for the {@link LuceneFulltext} created by this factory. + * @param analyzerClassName The Lucene analyzer to use for the {@link LuceneFulltext} created by this factory. + * @param provider The {@link FulltextProvider} to register the indexes with. * @throws IOException */ - public FulltextFactory( FileSystemAbstraction fileSystem, File storeDir, Analyzer analyzer ) throws IOException + public FulltextFactory( FileSystemAbstraction fileSystem, File storeDir, String analyzerClassName, + FulltextProvider provider ) throws IOException { - this.analyzer = analyzer; + this.analyzer = getAnalyzer( analyzerClassName ); this.fileSystem = fileSystem; + this.provider = provider; Factory indexWriterConfigFactory = () -> IndexWriterConfigs.standard( analyzer ); partitionFactory = new WritableIndexPartitionFactory( indexWriterConfigFactory ); indexDir = new File( storeDir, INDEX_DIR ); } + private Analyzer getAnalyzer( String analyzerClassName ) + { + Analyzer analyzer; + try + { + Class configuredAnalyzer = Class.forName( analyzerClassName ); + analyzer = (Analyzer) configuredAnalyzer.newInstance(); + } + catch ( Exception e ) + { + throw new RuntimeException( "Could not create the configured analyzer", e ); + } + return analyzer; + } + /** * Creates an instance of {@link LuceneFulltext} and registers it with the supplied {@link FulltextProvider}. + * * @param identifier The identifier of the new fulltext index * @param type The type of the new fulltext index * @param properties The properties to index - * @param provider The provider to register with * @throws IOException */ - public void createFulltextIndex( String identifier, FulltextProvider.FulltextIndexType type, List properties, FulltextProvider provider ) + public void createFulltextIndex( String identifier, FulltextProvider.FulltextIndexType type, + List properties ) throws IOException { - // First delete any existing index, since we don't know if whatever it might contain actually matches our - // current configuration: File indexRootFolder = new File( indexDir, identifier ); - fileSystem.deleteRecursively( indexRootFolder ); - LuceneIndexStorageBuilder storageBuilder = LuceneIndexStorageBuilder.create(); storageBuilder.withFileSystem( fileSystem ).withIndexFolder( indexRootFolder ); - provider.register( new LuceneFulltext( storageBuilder.build(), partitionFactory, properties, analyzer, identifier, type ) ); + PartitionedIndexStorage storage = storageBuilder.build(); + LuceneFulltext index = new LuceneFulltext( storage, partitionFactory, properties, analyzer, identifier, type ); + + provider.register( index ); } } diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextIndexConfiguration.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextIndexConfiguration.java new file mode 100644 index 0000000000000..6f92ae2f4c339 --- /dev/null +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextIndexConfiguration.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.api.impl.fulltext; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.StoredField; +import org.apache.lucene.document.StringField; +import org.apache.lucene.index.Term; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.apache.lucene.document.Field.Store.NO; +import static org.apache.lucene.document.Field.Store.YES; +import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.FIELD_CONFIG_ANALYZER; +import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.FIELD_CONFIG_PROPERTIES; +import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.FIELD_METADATA_DOC; + +public class FulltextIndexConfiguration +{ + public static Term TERM = new Term( FIELD_METADATA_DOC ); + + private final Set properties; + private final String analyzerClassName; + + public FulltextIndexConfiguration( Document doc ) + { + properties = new HashSet( Arrays.asList( doc.getValues( FIELD_CONFIG_PROPERTIES ) ) ); + analyzerClassName = doc.get( FIELD_CONFIG_ANALYZER ); + } + + public FulltextIndexConfiguration( Analyzer analyzer, Set properties ) + { + this.properties = properties; + this.analyzerClassName = analyzer.getClass().getCanonicalName(); + } + + public boolean matches( String analyzerClassName, Set properties ) + { + return this.analyzerClassName.equals( analyzerClassName ) && this.properties.equals( properties ); + } + + public Document asDocument() + { + Document doc = new Document(); + doc.add( new StringField( FIELD_METADATA_DOC, "", NO ) ); + doc.add( new StoredField( FIELD_CONFIG_ANALYZER, analyzerClassName ) ); + for ( String property : properties ) + { + doc.add( new StoredField( FIELD_CONFIG_PROPERTIES, property ) ); + } + return doc; + } +} diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextProvider.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextProvider.java index baacb6b937dcd..b17f19d168b62 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextProvider.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextProvider.java @@ -36,7 +36,12 @@ */ public class FulltextProvider implements AutoCloseable { - public static final String LUCENE_FULLTEXT_ADDON_INTERNAL_ID = "__lucene__fulltext__addon__internal__id__"; + public static final String LUCENE_FULLTEXT_ADDON_PREFIX = "__lucene__fulltext__addon__"; + public static final String FIELD_ENTITY_ID = LUCENE_FULLTEXT_ADDON_PREFIX + "internal__id__"; + public static final String FIELD_METADATA_DOC = LUCENE_FULLTEXT_ADDON_PREFIX + "metadata__doc__field__"; + public static final String FIELD_CONFIG_ANALYZER = LUCENE_FULLTEXT_ADDON_PREFIX + "analyzer"; + public static final String FIELD_CONFIG_PROPERTIES = LUCENE_FULLTEXT_ADDON_PREFIX + "properties"; + private final GraphDatabaseService db; private final Log log; private final FulltextTransactionEventUpdater fulltextTransactionEventUpdater; @@ -75,15 +80,36 @@ public void init() throws IOException { for ( WritableFulltext index : writableNodeIndices ) { - applier.populateNodes( index, db ); + index.open(); + if ( !matchesConfiguration( index ) ) + { + index.drop(); + index.open(); + applier.populateNodes( index, db ); + } } for ( WritableFulltext index : writableRelationshipIndices ) { - applier.populateRelationships( index, db ); + index.open(); + if ( !matchesConfiguration( index ) ) + { + index.drop(); + index.open(); + applier.populateRelationships( index, db ); + } } db.registerTransactionEventHandler( fulltextTransactionEventUpdater ); } + private boolean matchesConfiguration( WritableFulltext index ) throws IOException + { + try ( ReadOnlyFulltext indexReader = index.getIndexReader() ) + { + FulltextIndexConfiguration config = indexReader.getConfigurationDocument(); + return config != null && config.matches( index.getAnalyzerName(), index.getProperties() ); + } + } + /** * Wait for the asynchronous background population, if one is on-going, to complete. * @@ -130,7 +156,6 @@ public void close() void register( LuceneFulltext fulltextIndex ) throws IOException { - fulltextIndex.open(); if ( fulltextIndex.getType() == FulltextIndexType.NODES ) { nodeIndices.put( fulltextIndex.getIdentifier(), fulltextIndex ); diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextUpdateApplier.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextUpdateApplier.java index fd69f5f075788..9dc35c2af5a96 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextUpdateApplier.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/FulltextUpdateApplier.java @@ -81,7 +81,7 @@ AsyncFulltextIndexOperation updatePropertyData( PartitionedIndexWriter indexWriter = index.getIndexWriter(); for ( Map.Entry> stateEntry : state.entrySet() ) { - Set indexedProperties = index.properties(); + Set indexedProperties = index.getProperties(); if ( !Collections.disjoint( indexedProperties, stateEntry.getValue().keySet() ) ) { long entityId = stateEntry.getKey(); @@ -120,7 +120,7 @@ AsyncFulltextIndexOperation removePropertyData( { for ( PropertyEntry propertyEntry : propertyEntries ) { - if ( index.properties().contains( propertyEntry.key() ) ) + if ( index.getProperties().contains( propertyEntry.key() ) ) { long entityId = propertyEntry.entity().getId(); Map allProperties = state.get( entityId ); @@ -163,7 +163,7 @@ private AsyncFulltextIndexOperation enqueuePopulateIndex( FulltextIndexUpdate population = () -> { PartitionedIndexWriter indexWriter = index.getIndexWriter(); - String[] indexedPropertyKeys = index.properties().toArray( new String[0] ); + String[] indexedPropertyKeys = index.getProperties().toArray( new String[0] ); ArrayList> documents = new ArrayList<>(); try ( Transaction ignore = db.beginTx( 1, TimeUnit.DAYS ) ) { diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltext.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltext.java index 35f1bf2447610..101ecdb6b104d 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltext.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltext.java @@ -118,4 +118,18 @@ private PartitionedFulltextReader createPartitionedReader( List searchers = acquireSearchers( partitions ); return new PartitionedFulltextReader( searchers, properties.toArray( new String[0] ), analyzer ); } + + @Override + public void close() throws IOException + { + PartitionedIndexWriter writer = getIndexWriter( new WritableFulltext( this ) ); + FulltextIndexConfiguration config = new FulltextIndexConfiguration( analyzer, properties ); + writer.updateDocument( FulltextIndexConfiguration.TERM, config.asDocument() ); + super.close(); + } + + public String getAnalyzerName() + { + return analyzer.getClass().getCanonicalName(); + } } diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextDocumentStructure.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextDocumentStructure.java index 947354d894aa6..2c53516c4d630 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextDocumentStructure.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextDocumentStructure.java @@ -70,8 +70,8 @@ private static class DocWithId private DocWithId() { - idField = new StringField( FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID, "", NO ); - idValueField = new NumericDocValuesField( FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID, 0L ); + idField = new StringField( FulltextProvider.FIELD_ENTITY_ID, "", NO ); + idValueField = new NumericDocValuesField( FulltextProvider.FIELD_ENTITY_ID, 0L ); document = new Document(); document.add( idField ); document.add( idValueField ); @@ -100,7 +100,7 @@ private void removeAllValueFields() { IndexableField field = it.next(); String fieldName = field.name(); - if ( !fieldName.equals( FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID ) ) + if ( !fieldName.equals( FulltextProvider.FIELD_ENTITY_ID ) ) { it.remove(); } @@ -111,7 +111,6 @@ private void removeAllValueFields() static Term newTermForChangeOrRemove( long id ) { - return new Term( FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID, "" + id ); + return new Term( FulltextProvider.FIELD_ENTITY_ID, "" + id ); } - } diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/PartitionedFulltextReader.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/PartitionedFulltextReader.java index 6bd5949652d2f..d988c7297a731 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/PartitionedFulltextReader.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/PartitionedFulltextReader.java @@ -90,6 +90,20 @@ public void close() } } + @Override + public FulltextIndexConfiguration getConfigurationDocument() throws IOException + { + for ( ReadOnlyFulltext indexReader : indexReaders ) + { + FulltextIndexConfiguration config = indexReader.getConfigurationDocument(); + if ( config != null ) + { + return config; + } + } + return null; + } + private PrimitiveLongIterator partitionedOperation( Function readerFunction ) { return PrimitiveLongCollections.concat( indexReaders.parallelStream().map( readerFunction ).collect( Collectors.toList() ) ); diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/ReadOnlyFulltext.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/ReadOnlyFulltext.java index 70142fd31b939..7881c50c36c39 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/ReadOnlyFulltext.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/ReadOnlyFulltext.java @@ -19,6 +19,8 @@ */ package org.neo4j.kernel.api.impl.fulltext; +import java.io.IOException; + import org.neo4j.collection.primitive.PrimitiveLongIterator; public interface ReadOnlyFulltext extends AutoCloseable @@ -38,4 +40,9 @@ public interface ReadOnlyFulltext extends AutoCloseable * @return An iterator over the matching entityIDs, ordered by lucene scoring of the match. */ PrimitiveLongIterator fuzzyQuery( String... terms ); + + @Override + void close(); + + FulltextIndexConfiguration getConfigurationDocument() throws IOException; } diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/SimpleFulltextReader.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/SimpleFulltextReader.java index 78ba6e96494fb..26e44ab190dab 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/SimpleFulltextReader.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/SimpleFulltextReader.java @@ -26,6 +26,8 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.TopDocs; import java.io.IOException; @@ -37,7 +39,7 @@ import static java.util.Arrays.stream; import static java.util.stream.Collectors.joining; -import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID; +import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.FIELD_ENTITY_ID; /** * Lucene index reader that is able to read/sample a single partition of a partitioned Lucene index. @@ -84,6 +86,18 @@ public void close() } } + @Override + public FulltextIndexConfiguration getConfigurationDocument() throws IOException + { + IndexSearcher indexSearcher = getIndexSearcher(); + TopDocs docs = indexSearcher.search( new TermQuery( FulltextIndexConfiguration.TERM ), 1 ); + if ( docs.scoreDocs.length < 1 ) + { + return null; + } + return new FulltextIndexConfiguration( indexSearcher.doc( docs.scoreDocs[0].doc ) ); + } + private PrimitiveLongIterator innerQuery( String queryString ) { MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser( properties, analyzer ); @@ -107,7 +121,7 @@ private PrimitiveLongIterator indexQuery( Query query ) { DocValuesCollector docValuesCollector = new DocValuesCollector( true ); getIndexSearcher().search( query, docValuesCollector ); - return docValuesCollector.getSortedValuesIterator( LUCENE_FULLTEXT_ADDON_INTERNAL_ID, Sort.RELEVANCE ); + return docValuesCollector.getSortedValuesIterator( FIELD_ENTITY_ID, Sort.RELEVANCE ); } catch ( IOException e ) { diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/WritableFulltext.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/WritableFulltext.java index fd0203e0c8d61..25f5fbec923f7 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/WritableFulltext.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/WritableFulltext.java @@ -41,8 +41,18 @@ PartitionedIndexWriter getIndexWriter() return indexWriter; } - Set properties() + Set getProperties() { return luceneIndex.getProperties(); } + + public ReadOnlyFulltext getIndexReader() throws IOException + { + return luceneIndex.getIndexReader(); + } + + public String getAnalyzerName() + { + return luceneIndex.getAnalyzerName(); + } } diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomKernelExtension.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomKernelExtension.java index 177ef429db345..5ac4bf7e7779d 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomKernelExtension.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomKernelExtension.java @@ -19,8 +19,6 @@ */ package org.neo4j.kernel.api.impl.fulltext.integrations.bloom; -import org.apache.lucene.analysis.Analyzer; - import java.io.File; import java.io.IOException; import java.util.List; @@ -72,14 +70,14 @@ public void init() throws IOException, KernelException { if ( config.get( LoadableBloomFulltextConfig.bloom_enabled ) ) { - List properties = getProperties(); - Analyzer analyzer = getAnalyzer(); + List properties = getProperties( ); + String analyzer = config.get( LoadableBloomFulltextConfig.bloom_analyzer); Log log = logService.getInternalLog( FulltextProvider.class ); provider = new FulltextProvider( db, log, availabilityGuard, scheduler ); - FulltextFactory fulltextFactory = new FulltextFactory( fileSystemAbstraction, storeDir, analyzer ); - fulltextFactory.createFulltextIndex( BLOOM_NODES, FulltextProvider.FulltextIndexType.NODES, properties, provider ); - fulltextFactory.createFulltextIndex( BLOOM_RELATIONSHIPS, FulltextProvider.FulltextIndexType.RELATIONSHIPS, properties, provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fileSystemAbstraction, storeDir, analyzer, provider ); + fulltextFactory.createFulltextIndex( BLOOM_NODES, FulltextProvider.FulltextIndexType.NODES, properties ); + fulltextFactory.createFulltextIndex( BLOOM_RELATIONSHIPS, FulltextProvider.FulltextIndexType.RELATIONSHIPS, properties ); provider.init(); procedures.registerComponent( FulltextProvider.class, context -> provider, true ); @@ -97,21 +95,6 @@ private List getProperties() return properties; } - private Analyzer getAnalyzer() - { - Analyzer analyzer; - try - { - Class configuredAnalayzer = Class.forName( config.get( LoadableBloomFulltextConfig.bloom_analyzer ) ); - analyzer = (Analyzer) configuredAnalayzer.newInstance(); - } - catch ( Exception e ) - { - throw new RuntimeException( "Could not create the configured analyzer", e ); - } - return analyzer; - } - @Override public void shutdown() throws Exception { diff --git a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/LoadableBloomFulltextConfig.java b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/LoadableBloomFulltextConfig.java index 1d60fcc668390..b27fd47557c61 100644 --- a/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/LoadableBloomFulltextConfig.java +++ b/enterprise/fulltext-addon/src/main/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/LoadableBloomFulltextConfig.java @@ -29,7 +29,7 @@ import org.neo4j.graphdb.config.Setting; import org.neo4j.kernel.configuration.Settings; -import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID; +import static org.neo4j.kernel.api.impl.fulltext.FulltextProvider.LUCENE_FULLTEXT_ADDON_PREFIX; import static org.neo4j.kernel.configuration.Settings.BOOLEAN; import static org.neo4j.kernel.configuration.Settings.FALSE; import static org.neo4j.kernel.configuration.Settings.STRING; @@ -45,9 +45,10 @@ public class LoadableBloomFulltextConfig implements LoadableConfig { - public static final String UNSUPPORTED_PROPERY_KEY_REGEX = "^(?!" + LUCENE_FULLTEXT_ADDON_INTERNAL_ID + ").+$"; + public static final String UNSUPPORTED_PROPERTY_KEY_REGEX = "^(?!" + LUCENE_FULLTEXT_ADDON_PREFIX + ").+$"; public static final BiFunction,Function,List> ILLEGAL_VALUE_CONSTRAINT = - illegalValueMessage( "Must not contain '" + LUCENE_FULLTEXT_ADDON_INTERNAL_ID + "'", matchesAny( UNSUPPORTED_PROPERY_KEY_REGEX ) ); + illegalValueMessage( "Must not contain '" + LUCENE_FULLTEXT_ADDON_PREFIX + "'", matchesAny( + UNSUPPORTED_PROPERTY_KEY_REGEX ) ); @Description( "Enable the fulltext addon for bloom." ) @Internal diff --git a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/FulltextAnalyzerTest.java b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/FulltextAnalyzerTest.java index 783815395bc38..790a6e113d4a0 100644 --- a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/FulltextAnalyzerTest.java +++ b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/FulltextAnalyzerTest.java @@ -30,13 +30,16 @@ public class FulltextAnalyzerTest extends LuceneFulltextTestSupport { + private static final String ENGLISH = EnglishAnalyzer.class.getCanonicalName(); + private static final String SWEDISH = SwedishAnalyzer.class.getCanonicalName(); + @Test public void shouldBeAbleToSpecifyEnglishAnalyzer() throws Exception { - FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, new EnglishAnalyzer() ); try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "bloomNodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ENGLISH, provider ); + fulltextFactory.createFulltextIndex( "bloomNodes", NODES, singletonList( "prop" ) ); provider.init(); long id; @@ -63,10 +66,10 @@ public void shouldBeAbleToSpecifyEnglishAnalyzer() throws Exception @Test public void shouldBeAbleToSpecifySwedishAnalyzer() throws Exception { - FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, new SwedishAnalyzer() ); try ( FulltextProvider provider = createProvider(); ) { - fulltextFactory.createFulltextIndex( "bloomNodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, SWEDISH, provider ); + fulltextFactory.createFulltextIndex( "bloomNodes", NODES, singletonList( "prop" ) ); provider.init(); long id; diff --git a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextTestSupport.java b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextTestSupport.java index 32bd55b004130..0740980303987 100644 --- a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextTestSupport.java +++ b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextTestSupport.java @@ -24,6 +24,7 @@ import org.junit.Rule; import java.io.File; +import java.io.IOException; import java.time.Clock; import org.neo4j.collection.primitive.PrimitiveLongCollections; @@ -46,7 +47,7 @@ public class LuceneFulltextTestSupport { - protected static final StandardAnalyzer ANALYZER = new StandardAnalyzer(); + protected static final String ANALYZER = StandardAnalyzer.class.getCanonicalName(); protected static final Log LOG = NullLog.getInstance(); @Rule @@ -68,12 +69,13 @@ public void setUp() throws Exception scheduler = dbRule.resolveDependency( JobScheduler.class ); fs = dbRule.resolveDependency( FileSystemAbstraction.class ); storeDir = dbRule.getStoreDir(); - fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER ); } - protected FulltextProvider createProvider() + protected FulltextProvider createProvider() throws IOException { - return new FulltextProvider( db, LOG, availabilityGuard, scheduler ); + FulltextProvider provider = new FulltextProvider( db, LOG, availabilityGuard, scheduler ); + fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + return provider; } protected long createNodeIndexableByPropertyValue( Object propertyValue ) diff --git a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextUpdaterTest.java b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextUpdaterTest.java index 5b3caea136ab8..175475aa801fd 100644 --- a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextUpdaterTest.java +++ b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/LuceneFulltextUpdaterTest.java @@ -19,6 +19,7 @@ */ package org.neo4j.kernel.api.impl.fulltext; +import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.junit.Test; import java.util.Arrays; @@ -32,12 +33,14 @@ public class LuceneFulltextUpdaterTest extends LuceneFulltextTestSupport { + public static final String ANALYZER = StandardAnalyzer.class.getCanonicalName(); @Test public void shouldFindNodeWithString() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -67,7 +70,8 @@ public void shouldFindNodeWithNumber() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -93,7 +97,8 @@ public void shouldFindNodeWithBoolean() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -119,7 +124,8 @@ public void shouldFindNodeWithArrays() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -148,7 +154,8 @@ public void shouldRepresentPropertyChanges() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -188,7 +195,8 @@ public void shouldNotFindRemovedNodes() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -226,7 +234,8 @@ public void shouldNotFindRemovedProperties() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, Arrays.asList( "prop", "prop2" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, Arrays.asList( "prop", "prop2" ) ); provider.init(); long firstID; @@ -278,7 +287,8 @@ public void shouldOnlyIndexIndexedProperties() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -307,7 +317,8 @@ public void shouldSearchAcrossMultipleProperties() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, Arrays.asList( "prop", "prop2" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, Arrays.asList( "prop", "prop2" ) ); provider.init(); long firstID; @@ -338,7 +349,8 @@ public void shouldOrderResultsBasedOnRelevance() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, Arrays.asList( "first", "last" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, Arrays.asList( "first", "last" ) ); provider.init(); long firstID; @@ -375,8 +387,9 @@ public void shouldDifferentiateNodesAndRelationships() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); - fulltextFactory.createFulltextIndex( "relationships", RELATIONSHIPS, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); + fulltextFactory.createFulltextIndex( "relationships", RELATIONSHIPS, singletonList( "prop" ) ); provider.init(); long firstNodeID; @@ -417,7 +430,8 @@ public void fuzzyQueryShouldBeFuzzy() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -451,7 +465,8 @@ public void fuzzyQueryShouldReturnExactMatchesFirst() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); long firstID; @@ -480,8 +495,9 @@ public void shouldNotReturnNonMatches() throws Exception { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); - fulltextFactory.createFulltextIndex( "relationships", RELATIONSHIPS, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); + fulltextFactory.createFulltextIndex( "relationships", RELATIONSHIPS, singletonList( "prop" ) ); provider.init(); try ( Transaction tx = db.beginTx() ) @@ -534,8 +550,9 @@ public void shouldPopulateIndexWithExistingNodesAndRelationships() throws Except try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); - fulltextFactory.createFulltextIndex( "relationships", RELATIONSHIPS, singletonList( "prop" ), provider ); + FulltextFactory fulltextFactory = new FulltextFactory( fs, storeDir, ANALYZER, provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); + fulltextFactory.createFulltextIndex( "relationships", RELATIONSHIPS, singletonList( "prop" ) ); provider.init(); provider.awaitPopulation(); @@ -561,7 +578,7 @@ public void shouldReturnMatchesThatContainLuceneSyntaxCharacters() throws Except { try ( FulltextProvider provider = createProvider() ) { - fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ), provider ); + fulltextFactory.createFulltextIndex( "nodes", NODES, singletonList( "prop" ) ); provider.init(); String[] luceneSyntaxElements = {"+", "-", "&&", "||", "!", "(", ")", "{", "}", "[", "]", "^", "\"", "~", "*", "?", ":", "\\"}; diff --git a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomIT.java b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomIT.java index 051ba0c08cabd..f728c4bdeb224 100644 --- a/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomIT.java +++ b/enterprise/fulltext-addon/src/test/java/org/neo4j/kernel/api/impl/fulltext/integrations/bloom/BloomIT.java @@ -315,7 +315,7 @@ public void shouldNotBeAbleToStartWithoutConfiguringProperties() throws Exceptio public void shouldNotBeAbleToStartWithIllegalPropertyKey() throws Exception { expectedException.expect( InvalidSettingException.class ); - builder.setConfig( LoadableBloomFulltextConfig.bloom_indexed_properties, "prop, " + FulltextProvider.LUCENE_FULLTEXT_ADDON_INTERNAL_ID + ", hello" ); + builder.setConfig( LoadableBloomFulltextConfig.bloom_indexed_properties, "prop, " + FulltextProvider.FIELD_ENTITY_ID + ", hello" ); db = builder.newGraphDatabase(); }