Skip to content

Commit

Permalink
Support for Spatial and Temporal in IndexProvider Lucene-1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
burqen committed Mar 22, 2018
1 parent 3a9bbc9 commit c96c29f
Show file tree
Hide file tree
Showing 14 changed files with 192 additions and 87 deletions.
Expand Up @@ -333,7 +333,6 @@ public void shouldPerformNumericRangeSearch() throws Exception
read.nodeIndexSeek( index, node, IndexOrder.NONE, IndexQuery.range( prop, 5, true, 12, false ) ); read.nodeIndexSeek( index, node, IndexOrder.NONE, IndexQuery.range( prop, 5, true, 12, false ) );


// then // then

assertFoundNodesAndValue( node, uniqueIds, numberCapability, num5, num6 ); assertFoundNodesAndValue( node, uniqueIds, numberCapability, num5, num6 );


// when // when
Expand Down
Expand Up @@ -47,7 +47,7 @@ abstract class NativeSchemaIndexReader<KEY extends NativeSchemaKey, VALUE extend
final Layout<KEY,VALUE> layout; final Layout<KEY,VALUE> layout;
private final IndexSamplingConfig samplingConfig; private final IndexSamplingConfig samplingConfig;


protected final Set<RawCursor<Hit<KEY,VALUE>,IOException>> openSeekers; final Set<RawCursor<Hit<KEY,VALUE>,IOException>> openSeekers;
protected final SchemaIndexDescriptor descriptor; protected final SchemaIndexDescriptor descriptor;


NativeSchemaIndexReader( GBPTree<KEY,VALUE> tree, Layout<KEY,VALUE> layout, NativeSchemaIndexReader( GBPTree<KEY,VALUE> tree, Layout<KEY,VALUE> layout,
Expand Down Expand Up @@ -133,8 +133,8 @@ public PrimitiveLongResourceIterator query( IndexQuery... predicates )


private PrimitiveLongResourceIterator getHitIterator( RawCursor<Hit<KEY,VALUE>,IOException> seeker, boolean needFilter, IndexQuery[] predicates ) private PrimitiveLongResourceIterator getHitIterator( RawCursor<Hit<KEY,VALUE>,IOException> seeker, boolean needFilter, IndexQuery[] predicates )
{ {
return needFilter ? new FilteringNativeHitIterator<KEY,VALUE>( seeker, openSeekers, predicates ) return needFilter ? new FilteringNativeHitIterator<>( seeker, openSeekers, predicates )
: new NativeHitIterator<KEY,VALUE>( seeker, openSeekers ); : new NativeHitIterator<>( seeker, openSeekers );
} }


@Override @Override
Expand Down
Expand Up @@ -26,8 +26,6 @@
import org.neo4j.graphdb.Resource; import org.neo4j.graphdb.Resource;
import org.neo4j.internal.kernel.api.IndexOrder; import org.neo4j.internal.kernel.api.IndexOrder;
import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.internal.kernel.api.IndexQuery;
import org.neo4j.internal.kernel.api.IndexQuery.ExactPredicate;
import org.neo4j.internal.kernel.api.IndexQuery.RangePredicate;
import org.neo4j.kernel.api.exceptions.index.IndexNotApplicableKernelException; import org.neo4j.kernel.api.exceptions.index.IndexNotApplicableKernelException;
import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor;
import org.neo4j.kernel.impl.api.schema.BridgingIndexProgressor; import org.neo4j.kernel.impl.api.schema.BridgingIndexProgressor;
Expand All @@ -36,7 +34,6 @@
import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.storageengine.api.schema.IndexSampler; import org.neo4j.storageengine.api.schema.IndexSampler;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.ValueGroup;


import static java.lang.String.format; import static java.lang.String.format;


Expand Down Expand Up @@ -113,24 +110,13 @@ public void query( IndexProgressor.NodeValueClient cursor, IndexOrder indexOrder
@Override @Override
public boolean hasFullValuePrecision( IndexQuery... predicates ) public boolean hasFullValuePrecision( IndexQuery... predicates )
{ {
if ( predicates.length > 1 ) IndexReader instance = selector.select( instances, predicates );
{ if ( instance == null )
return false;
}

IndexQuery predicate = predicates[0];
if ( predicate instanceof ExactPredicate )
{
Value value = ((ExactPredicate) predicate).value();
return selector.select( instances, value ).hasFullValuePrecision( predicates );
}

if ( predicate instanceof RangePredicate && predicate.valueGroup() == ValueGroup.NUMBER )
{ {
return instances[NUMBER].hasFullValuePrecision( predicates ); // null means ExistsPredicate and we don't care about
// full value precision for that, therefor true.
return true;
} }
// TODO: support temporal range queries return instance.hasFullValuePrecision( predicates );

return false;
} }
} }
Expand Up @@ -22,8 +22,11 @@
import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.internal.kernel.api.IndexQuery;
import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.Values;


import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.LUCENE; import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.LUCENE;
import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.SPATIAL;
import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.TEMPORAL;


/** /**
* Selector for index provider "lucene-1.x". * Selector for index provider "lucene-1.x".
Expand All @@ -34,18 +37,68 @@ public class FusionSelector00 implements FusionIndexProvider.Selector
@Override @Override
public void validateSatisfied( Object[] instances ) public void validateSatisfied( Object[] instances )
{ {
FusionIndexBase.validateSelectorInstances( instances, LUCENE ); FusionIndexBase.validateSelectorInstances( instances, LUCENE, SPATIAL, TEMPORAL );
} }


@Override @Override
public int selectSlot( Value... values ) public int selectSlot( Value... values )
{ {
if ( values.length > 1 )
{
// Multiple values must be handled by lucene
return LUCENE;
}

Value singleValue = values[0];
if ( Values.isGeometryValue( singleValue ) )
{
// It's a geometry, the spatial index can handle this
return SPATIAL;
}

if ( Values.isTemporalValue( singleValue ) )
{
return TEMPORAL;
}

return LUCENE; return LUCENE;
} }


@Override @Override
public IndexReader select( IndexReader[] instances, IndexQuery... predicates ) public IndexReader select( IndexReader[] instances, IndexQuery... predicates )
{ {
if ( predicates.length > 1 )
{
return instances[LUCENE];
}
IndexQuery predicate = predicates[0];

if ( predicate instanceof IndexQuery.ExactPredicate )
{
IndexQuery.ExactPredicate exactPredicate = (IndexQuery.ExactPredicate) predicate;
return select( instances, exactPredicate.value() );
}

if ( predicate instanceof IndexQuery.RangePredicate )
{
switch ( predicate.valueGroup() )
{
case GEOMETRY:
return instances[SPATIAL];
case DATE:
case LOCAL_DATE_TIME:
case ZONED_DATE_TIME:
case LOCAL_TIME:
case ZONED_TIME:
case DURATION:
return instances[TEMPORAL];
default: // fall through
}
}
if ( predicate instanceof IndexQuery.ExistsPredicate )
{
return null;
}
return instances[LUCENE]; return instances[LUCENE];
} }
} }
Expand Up @@ -32,7 +32,7 @@ enum FusionVersion
@Override @Override
int[] aliveSlots() int[] aliveSlots()
{ {
return new int[]{LUCENE}; return new int[]{LUCENE, SPATIAL, TEMPORAL};
} }


@Override @Override
Expand Down
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.neo4j.kernel.api.impl.index.storage; package org.neo4j.kernel.api.impl.index.storage;


import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext; import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexInput;
Expand Down Expand Up @@ -241,7 +242,7 @@ private List<File> listFolders( File rootFolder )
File[] files = fileSystem.listFiles( rootFolder ); File[] files = fileSystem.listFiles( rootFolder );
return files == null ? Collections.emptyList() return files == null ? Collections.emptyList()
: Stream.of( files ) : Stream.of( files )
.filter( fileSystem::isDirectory ) .filter( f -> fileSystem.isDirectory( f ) && StringUtils.isNumeric( f.getName() ) )
.sorted( FILE_COMPARATOR ) .sorted( FILE_COMPARATOR )
.collect( toList() ); .collect( toList() );


Expand Down
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2002-2018 "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 <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.api.impl.schema;

import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.api.impl.index.storage.DirectoryFactory;
import org.neo4j.kernel.api.index.IndexDirectoryStructure;
import org.neo4j.kernel.api.index.IndexProvider;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory;
import org.neo4j.kernel.impl.factory.OperationalMode;
import org.neo4j.kernel.impl.index.schema.NumberIndexProvider;
import org.neo4j.kernel.impl.index.schema.TemporalIndexProvider;
import org.neo4j.kernel.impl.index.schema.fusion.SpatialFusionIndexProvider;

import static org.neo4j.kernel.api.impl.index.LuceneKernelExtensions.directoryFactory;

class IndexProviderFactoryUtil
{
static boolean isReadOnly( Config config, OperationalMode operationalMode )
{
return config.get( GraphDatabaseSettings.read_only ) && (OperationalMode.single == operationalMode);
}

static NumberIndexProvider numberProvider( PageCache pageCache, FileSystemAbstraction fs, IndexProvider.Monitor monitor,
RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, IndexDirectoryStructure.Factory childDirectoryStructure, boolean readOnly )
{
return new NumberIndexProvider( pageCache, fs, childDirectoryStructure, monitor, recoveryCleanupWorkCollector, readOnly );
}

static SpatialFusionIndexProvider spatialProvider( PageCache pageCache, FileSystemAbstraction fs, IndexProvider.Monitor monitor,
RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, boolean readOnly, IndexDirectoryStructure.Factory directoryStructure,
Config config )
{
return new SpatialFusionIndexProvider( pageCache, fs, directoryStructure, monitor, recoveryCleanupWorkCollector, readOnly, config );
}

static TemporalIndexProvider temporalProvider( PageCache pageCache, FileSystemAbstraction fs, IndexProvider.Monitor monitor,
RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, boolean readOnly, IndexDirectoryStructure.Factory directoryStructure )
{
return new TemporalIndexProvider( pageCache, fs, directoryStructure, monitor, recoveryCleanupWorkCollector, readOnly );
}

static LuceneIndexProvider luceneProvider( FileSystemAbstraction fileSystemAbstraction,
IndexDirectoryStructure.Factory directoryStructure, IndexProvider.Monitor monitor, Config config,
OperationalMode operationalMode )
{
boolean ephemeral = config.get( GraphDatabaseFacadeFactory.Configuration.ephemeral );
DirectoryFactory directoryFactory = directoryFactory( ephemeral, fileSystemAbstraction );
return new LuceneIndexProvider( fileSystemAbstraction, directoryFactory, directoryStructure, monitor, config, operationalMode );
}
}
Expand Up @@ -22,25 +22,27 @@
import java.io.File; import java.io.File;


import org.neo4j.helpers.Service; import org.neo4j.helpers.Service;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.kernel.api.impl.index.storage.DirectoryFactory; import org.neo4j.io.pagecache.PageCache;
import org.neo4j.kernel.api.index.IndexDirectoryStructure; import org.neo4j.kernel.api.index.IndexDirectoryStructure;
import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.kernel.api.index.IndexProvider;
import org.neo4j.kernel.api.index.LoggingMonitor; import org.neo4j.kernel.api.index.LoggingMonitor;
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.extension.KernelExtensionFactory; import org.neo4j.kernel.extension.KernelExtensionFactory;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory;
import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.factory.OperationalMode;
import org.neo4j.kernel.impl.index.schema.TemporalIndexProvider;
import org.neo4j.kernel.impl.index.schema.fusion.FusionIndexProvider; import org.neo4j.kernel.impl.index.schema.fusion.FusionIndexProvider;
import org.neo4j.kernel.impl.index.schema.fusion.FusionSelector00; import org.neo4j.kernel.impl.index.schema.fusion.FusionSelector00;
import org.neo4j.kernel.impl.index.schema.fusion.SpatialFusionIndexProvider;
import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.logging.LogService;
import org.neo4j.kernel.impl.spi.KernelContext; import org.neo4j.kernel.impl.spi.KernelContext;
import org.neo4j.kernel.monitoring.Monitors; import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.logging.Log; import org.neo4j.logging.Log;


import static org.neo4j.kernel.api.impl.index.LuceneKernelExtensions.directoryFactory;
import static org.neo4j.kernel.api.index.IndexDirectoryStructure.directoriesByProvider; import static org.neo4j.kernel.api.index.IndexDirectoryStructure.directoriesByProvider;
import static org.neo4j.kernel.api.index.IndexDirectoryStructure.directoriesByProviderKey; import static org.neo4j.kernel.api.index.IndexDirectoryStructure.directoriesByProviderKey;
import static org.neo4j.kernel.api.index.IndexDirectoryStructure.directoriesBySubProvider;
import static org.neo4j.kernel.api.index.IndexProvider.EMPTY; import static org.neo4j.kernel.api.index.IndexProvider.EMPTY;


@Service.Implementation( KernelExtensionFactory.class ) @Service.Implementation( KernelExtensionFactory.class )
Expand All @@ -54,6 +56,10 @@ public class LuceneIndexProviderFactory extends


public interface Dependencies public interface Dependencies
{ {
PageCache pageCache();

RecoveryCleanupWorkCollector recoveryCleanupWorkCollector();

Config getConfig(); Config getConfig();


Monitors monitors(); Monitors monitors();
Expand All @@ -71,39 +77,35 @@ public LuceneIndexProviderFactory()
@Override @Override
public IndexProvider newInstance( KernelContext context, Dependencies dependencies ) public IndexProvider newInstance( KernelContext context, Dependencies dependencies )
{ {
FileSystemAbstraction fileSystemAbstraction = dependencies.fileSystem(); PageCache pageCache = dependencies.pageCache();
File storeDir = context.storeDir(); File storeDir = context.storeDir();
Config config = dependencies.getConfig(); FileSystemAbstraction fs = dependencies.fileSystem();
Log log = dependencies.getLogService().getInternalLogProvider().getLog( LuceneIndexProvider.class );
Monitors monitors = dependencies.monitors(); Monitors monitors = dependencies.monitors();
Log log = dependencies.getLogService().getInternalLogProvider().getLog( LuceneIndexProvider.class );
monitors.addMonitorListener( new LoggingMonitor( log ), KEY ); monitors.addMonitorListener( new LoggingMonitor( log ), KEY );
IndexProvider.Monitor monitor = monitors.newMonitor( IndexProvider.Monitor.class, KEY ); IndexProvider.Monitor monitor = monitors.newMonitor( IndexProvider.Monitor.class, KEY );
Config config = dependencies.getConfig();
OperationalMode operationalMode = context.databaseInfo().operationalMode; OperationalMode operationalMode = context.databaseInfo().operationalMode;

RecoveryCleanupWorkCollector recoveryCleanupWorkCollector = dependencies.recoveryCleanupWorkCollector();
LuceneIndexProvider luceneProvider = createLuceneProvider( fileSystemAbstraction, storeDir, monitor, config, operationalMode ); return newInstance( pageCache, storeDir, fs, monitor, config, operationalMode, recoveryCleanupWorkCollector );

return new FusionIndexProvider( EMPTY, EMPTY, EMPTY, EMPTY, luceneProvider, new FusionSelector00(),
PROVIDER_DESCRIPTOR, LuceneIndexProvider.PRIORITY, directoriesByProvider( storeDir ), fileSystemAbstraction );
}

public static LuceneIndexProvider createLuceneProvider( FileSystemAbstraction fileSystemAbstraction, File storeDir,
IndexProvider.Monitor monitor, Config config, OperationalMode operationalMode )
{
return createLuceneProvider( fileSystemAbstraction, directoryStructureForLuceneProvider( storeDir ), monitor, config, operationalMode );
} }


static LuceneIndexProvider createLuceneProvider( FileSystemAbstraction fileSystemAbstraction, public static FusionIndexProvider newInstance( PageCache pageCache, File storeDir, FileSystemAbstraction fs,
IndexDirectoryStructure.Factory directoryStructure, IndexProvider.Monitor monitor, Config config, IndexProvider.Monitor monitor, Config config, OperationalMode operationalMode,
OperationalMode operationalMode ) RecoveryCleanupWorkCollector recoveryCleanupWorkCollector )
{ {
boolean ephemeral = config.get( GraphDatabaseFacadeFactory.Configuration.ephemeral ); boolean readOnly = IndexProviderFactoryUtil.isReadOnly( config, operationalMode );
DirectoryFactory directoryFactory = directoryFactory( ephemeral, fileSystemAbstraction ); IndexDirectoryStructure.Factory baseDirStructure = directoriesByProviderKey( storeDir );
return new LuceneIndexProvider( fileSystemAbstraction, directoryFactory, directoryStructure, monitor, config, IndexDirectoryStructure.Factory childDirectoryStructure = directoriesBySubProvider( baseDirStructure.forProvider( PROVIDER_DESCRIPTOR ) );
operationalMode );
LuceneIndexProvider lucene = IndexProviderFactoryUtil.luceneProvider( fs, baseDirStructure, monitor, config, operationalMode );
TemporalIndexProvider temporal =
IndexProviderFactoryUtil.temporalProvider( pageCache, fs, monitor, recoveryCleanupWorkCollector, readOnly, childDirectoryStructure );
SpatialFusionIndexProvider spatial =
IndexProviderFactoryUtil.spatialProvider( pageCache, fs, monitor, recoveryCleanupWorkCollector, readOnly, childDirectoryStructure, config );

return new FusionIndexProvider( EMPTY, EMPTY, spatial, temporal, lucene, new FusionSelector00(),
PROVIDER_DESCRIPTOR, LuceneIndexProvider.PRIORITY, directoriesByProvider( storeDir ), fs );
} }


private static IndexDirectoryStructure.Factory directoryStructureForLuceneProvider( File storeDir )
{
return directoriesByProviderKey( storeDir );
}
} }

0 comments on commit c96c29f

Please sign in to comment.