Skip to content

Commit

Permalink
Adds IndexCapability#limitations
Browse files Browse the repository at this point in the history
Where additional flags can be raised about limitations
in a particular index implementation. Such flags can be used
to create e.g. notifications.
  • Loading branch information
tinwelint authored and sherfert committed May 15, 2018
1 parent efaa849 commit 650835c
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 3 deletions.
Expand Up @@ -249,6 +249,8 @@ enum Statement implements Status
"The database was unable to plan a hinted join." ),
NoApplicableIndexWarning( ClientNotification,
"Adding a schema index may speed up this query." ),
SuboptimalIndexForWildcardQuery( ClientNotification,
"Index cannot execute wildcard query efficiently" ),
UnboundedVariableLengthPatternWarning( ClientNotification,
"The provided pattern is unbounded, consider adding an upper limit to the number of node hops." ),
ExhaustiveShortestPathWarning( ClientNotification,
Expand Down
Expand Up @@ -32,6 +32,7 @@ public interface IndexCapability
{
IndexOrder[] ORDER_ASC = {IndexOrder.ASCENDING};
IndexOrder[] ORDER_NONE = new IndexOrder[0];
IndexLimitation[] LIMITIATION_NONE = new IndexLimitation[0];

/**
* What possible orderings is this index capable to provide for a query on given combination of {@link ValueCategory}.
Expand Down Expand Up @@ -59,6 +60,15 @@ public interface IndexCapability
*/
IndexValueCapability valueCapability( ValueCategory... valueCategories );

/**
* @return an array of limitations that this index has. It could be anything that planning could look at and
* either try to avoid or issue warning for.
*/
default IndexLimitation[] limitations()
{
return LIMITIATION_NONE;
}

default boolean singleWildcard( ValueCategory[] valueCategories )
{
return valueCategories.length == 1 && valueCategories[0] == ValueCategory.UNKNOWN;
Expand Down
@@ -0,0 +1,28 @@
/*
* 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.internal.kernel.api;

public enum IndexLimitation
{
/**
* Highlights that CONTAINS and ENDS WITH isn't supported efficiently.
*/
SLOW_CONTAINS;
}
Expand Up @@ -193,7 +193,11 @@ public enum NotificationCode
EXPERIMENTAL_FEATURE(
SeverityLevel.WARNING,
Status.Statement.ExperimentalFeature,
"You are using an experimental feature" );
"You are using an experimental feature" ),
SUBOPTIMAL_INDEX_FOR_WILDCARD_QUERY(
SeverityLevel.INFORMATION,
Status.Statement.SuboptimalIndexForWildcardQuery,
"Index cannot execute wildcard query efficiently" );

private final Status status;
private final String description;
Expand Down
Expand Up @@ -26,6 +26,7 @@
import org.neo4j.index.internal.gbptree.Layout;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.internal.kernel.api.IndexCapability;
import org.neo4j.internal.kernel.api.IndexLimitation;
import org.neo4j.internal.kernel.api.IndexOrder;
import org.neo4j.internal.kernel.api.IndexValueCapability;
import org.neo4j.io.fs.FileSystemAbstraction;
Expand Down Expand Up @@ -90,6 +91,8 @@ public IndexCapability getCapability( SchemaIndexDescriptor schemaIndexDescripto
*/
private static class StringIndexCapability implements IndexCapability
{
private final IndexLimitation[] limitations = {IndexLimitation.SLOW_CONTAINS};

@Override
public IndexOrder[] orderCapability( ValueCategory... valueCategories )
{
Expand All @@ -114,6 +117,12 @@ public IndexValueCapability valueCapability( ValueCategory... valueCategories )
return IndexValueCapability.NO;
}

@Override
public IndexLimitation[] limitations()
{
return limitations;
}

private boolean support( ValueCategory[] valueCategories )
{
return valueCategories.length == 1 && valueCategories[0] == ValueCategory.TEXT;
Expand Down
Expand Up @@ -24,6 +24,7 @@
import java.util.Set;

import org.neo4j.internal.kernel.api.IndexCapability;
import org.neo4j.internal.kernel.api.IndexLimitation;
import org.neo4j.internal.kernel.api.IndexOrder;
import org.neo4j.internal.kernel.api.IndexValueCapability;
import org.neo4j.values.storable.ValueCategory;
Expand All @@ -35,10 +36,12 @@
public class UnionIndexCapability implements IndexCapability
{
private final IndexCapability[] capabilities;
private final IndexLimitation[] limitationsUnion;

public UnionIndexCapability( IndexCapability... capabilities )
{
this.capabilities = capabilities;
this.limitationsUnion = limitationsUnion( capabilities );
}

@Override
Expand Down Expand Up @@ -66,4 +69,20 @@ public IndexValueCapability valueCapability( ValueCategory... valueCategories )
}
return currentBest;
}

@Override
public IndexLimitation[] limitations()
{
return limitationsUnion;
}

private IndexLimitation[] limitationsUnion( IndexCapability[] capabilities )
{
HashSet<IndexLimitation> union = new HashSet<>();
for ( IndexCapability capability : capabilities )
{
union.addAll( Arrays.asList( capability.limitations() ) );
}
return union.toArray( new IndexLimitation[union.size()] );
}
}
Expand Up @@ -21,8 +21,11 @@

import org.junit.Test;

import java.util.Collections;

import org.neo4j.helpers.ArrayUtil;
import org.neo4j.internal.kernel.api.IndexCapability;
import org.neo4j.internal.kernel.api.IndexLimitation;
import org.neo4j.internal.kernel.api.IndexOrder;
import org.neo4j.internal.kernel.api.IndexValueCapability;
import org.neo4j.values.storable.ValueCategory;
Expand All @@ -32,6 +35,8 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.neo4j.helpers.ArrayUtil.array;
import static org.neo4j.helpers.collection.Iterators.asSet;

public class UnionIndexCapabilityTest
{
Expand Down Expand Up @@ -117,6 +122,47 @@ public void shouldCreateUnionOfValueCapability()
assertValueCapability( union, IndexValueCapability.YES );
}

@Test
public void shouldCreateUnionOfIndexLimitations()
{
UnionIndexCapability union;

// given
union = unionOfIndexLimitations( IndexCapability.LIMITIATION_NONE, IndexCapability.LIMITIATION_NONE );

// then
assertEquals( Collections.emptySet(), asSet( union.limitations() ) );

// given
union = unionOfIndexLimitations( IndexCapability.LIMITIATION_NONE, array( IndexLimitation.SLOW_CONTAINS ) );

// then
assertEquals( asSet( IndexLimitation.SLOW_CONTAINS ), asSet( union.limitations() ) );

// given
union = unionOfIndexLimitations( array( IndexLimitation.SLOW_CONTAINS ), array( IndexLimitation.SLOW_CONTAINS ) );

// then
assertEquals( asSet( IndexLimitation.SLOW_CONTAINS ), asSet( union.limitations() ) );
}

private UnionIndexCapability unionOfIndexLimitations( IndexLimitation[]... limitiations )
{
IndexCapability[] capabilities = new IndexCapability[limitiations.length];
for ( int i = 0; i < limitiations.length; i++ )
{
capabilities[i] = capabilityWithIndexLimitations( limitiations[i] );
}
return new UnionIndexCapability( capabilities );
}

private IndexCapability capabilityWithIndexLimitations( IndexLimitation[] limitations )
{
IndexCapability mock = mockedIndexCapability();
when( mock.limitations() ).thenReturn( limitations );
return mock;
}

private UnionIndexCapability unionOfValueCapabilities( IndexValueCapability... valueCapabilities )
{
IndexCapability[] capabilities = new IndexCapability[valueCapabilities.length];
Expand All @@ -139,14 +185,21 @@ private UnionIndexCapability unionOfOrderCapabilities( IndexOrder[]... indexOrde

private IndexCapability capabilityWithValue( IndexValueCapability valueCapability )
{
IndexCapability mock = mock( IndexCapability.class );
IndexCapability mock = mockedIndexCapability();
when( mock.valueCapability( any() ) ).thenReturn( valueCapability );
return mock;
}

private IndexCapability capabilityWithOrder( IndexOrder[] indexOrder )
private IndexCapability mockedIndexCapability()
{
IndexCapability mock = mock( IndexCapability.class );
when( mock.limitations() ).thenReturn( IndexCapability.LIMITIATION_NONE );
return mock;
}

private IndexCapability capabilityWithOrder( IndexOrder[] indexOrder )
{
IndexCapability mock = mockedIndexCapability();
when( mock.orderCapability( any() ) ).thenReturn( indexOrder );
return mock;
}
Expand Down

0 comments on commit 650835c

Please sign in to comment.