Skip to content

Commit

Permalink
DBstructure support for composite indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
ragadeeshu committed Mar 20, 2017
1 parent 8ddd30b commit a5ff6e6
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 43 deletions.
Expand Up @@ -28,7 +28,7 @@ import org.neo4j.helpers.collection.Visitable
import org.neo4j.kernel.impl.util.dbstructure.{DbStructureCollector, DbStructureLookup, DbStructureVisitor}

import scala.collection.JavaConverters._
import scala.collection.mutable
import scala.collection.{JavaConverters, mutable}

object DbStructureLogicalPlanningConfiguration {

Expand Down Expand Up @@ -63,8 +63,8 @@ object DbStructureLogicalPlanningConfiguration {
}
}

private def indexSet(indices: util.Iterator[Pair[String, String]]): Set[(String, Seq[String])] =
indices.asScala.map { pair => pair.first() -> Seq(pair.other()) }.toSet
private def indexSet(indices: util.Iterator[Pair[String, Array[String]]]): Set[(String, Seq[String])] =
indices.asScala.map { pair => pair.first() -> pair.other().to[Seq] }.toSet

private def resolveTokens[T](iterator: util.Iterator[Pair[Integer, String]])(f: Int => T): mutable.Map[String, T] = {
val builder = mutable.Map.newBuilder[String, T]
Expand Down
Expand Up @@ -123,16 +123,15 @@ else if ( arg instanceof NodeExistenceConstraintDescriptor )
{
NodeExistenceConstraintDescriptor constraint = (NodeExistenceConstraintDescriptor) arg;
int labelId = constraint.schema().getLabelId();
builder.append( format( "new NodePropertyExistenceConstraint( SchemaDescriptorFactory.forLabel( %d, %s ) )",
builder.append( format( "ConstraintDescriptorFactory.existsForLabel( %d, %s )",
labelId, asString( constraint.schema().getPropertyIds() ) ) );
}
else if ( arg instanceof RelExistenceConstraintDescriptor )
{
RelationTypeSchemaDescriptor descriptor = ((RelExistenceConstraintDescriptor) arg).schema();
int relTypeId = descriptor.getRelTypeId();
builder.append(
format( "new RelationshipPropertyExistenceConstraint( SchemaDescriptorFactory.forLabel( %d, %s ) )",
relTypeId, asString( descriptor.getPropertyIds() ) ) );
builder.append( format( "ConstraintDescriptorFactory.existsForReltype( %d, %s )", relTypeId,
asString( descriptor.getPropertyIds() ) ) );
}
else
{
Expand All @@ -144,6 +143,6 @@ else if ( arg instanceof RelExistenceConstraintDescriptor )
private String asString( int[] propertyIds )
{
List<String> strings = Arrays.stream( propertyIds ).mapToObj( i -> "" + i ).collect( Collectors.toList() );
return String.join( ",", strings );
return String.join( ", ", strings );
}
}
Expand Up @@ -73,41 +73,42 @@ public Iterator<Pair<Integer, String>> relationshipTypes()
}

@Override
public Iterator<Pair<String, String>> knownIndices()
public Iterator<Pair<String,String[]>> knownIndices()
{
return regularIndices.iterator();
}

@Override
public Iterator<Pair<String, String>> knownUniqueIndices()
public Iterator<Pair<String,String[]>> knownUniqueIndices()
{
return uniqueIndices.iterator();
}

@Override
public Iterator<Pair<String, String>> knownUniqueConstraints()
public Iterator<Pair<String,String[]>> knownUniqueConstraints()
{
//TODO: Add support for composite indexes
return Iterators.map( uniquenessConstraint -> {
String label = labels.byIdOrFail( uniquenessConstraint.schema().getLabelId() );
String propertyKey = propertyKeys.byIdOrFail( uniquenessConstraint.schema().getPropertyId() );
return Pair.of( label, propertyKey );
String[] propertyKeyNames = propertyKeys
.byIdOrFail( uniquenessConstraint.schema().getPropertyIds() );
return Pair.of( label, propertyKeyNames );
}, uniquenessConstraints.iterator() );
}

@Override
public Iterator<Pair<String,String>> knownNodePropertyExistenceConstraints()
public Iterator<Pair<String,String[]>> knownNodePropertyExistenceConstraints()
{
//TODO: Add support for composite indexes
return Iterators.map( uniquenessConstraint -> {
String label = labels.byIdOrFail( uniquenessConstraint.schema().getLabelId() );
String propertyKey = propertyKeys.byIdOrFail( uniquenessConstraint.schema().getPropertyId() );
return Pair.of( label, propertyKey );
String[] propertyKeyNames = propertyKeys
.byIdOrFail( uniquenessConstraint.schema().getPropertyIds() );
return Pair.of( label, propertyKeyNames );
}, nodePropertyExistenceConstraints.iterator() );
}

@Override
public Iterator<Pair<String,String>> knownRelationshipPropertyExistenceConstraints()
public Iterator<Pair<String,String[]>> knownRelationshipPropertyExistenceConstraints()
{
return Iterators.emptyIterator();
}
Expand All @@ -128,20 +129,18 @@ public long cardinalityByLabelsAndRelationshipType( int fromLabelId, int relType
}

@Override
public double indexSelectivity( int labelId, int propertyKeyId )
public double indexSelectivity( int labelId, int... propertyKeyIds )
{
//TODO: Support composite indexes
LabelSchemaDescriptor descriptor = SchemaDescriptorFactory.forLabel( labelId, propertyKeyId );
LabelSchemaDescriptor descriptor = SchemaDescriptorFactory.forLabel( labelId, propertyKeyIds );
IndexStatistics result1 = regularIndices.getIndex( descriptor );
IndexStatistics result2 = result1 == null ? uniqueIndices.getIndex( descriptor ) : result1;
return result2 == null ? Double.NaN : result2.uniqueValuesPercentage;
}

@Override
public double indexPropertyExistsSelectivity( int labelId, int propertyKeyId )
public double indexPropertyExistsSelectivity( int labelId, int... propertyKeyIds )
{
//TODO: Support composite indexes
LabelSchemaDescriptor descriptor = SchemaDescriptorFactory.forLabel( labelId, propertyKeyId );
LabelSchemaDescriptor descriptor = SchemaDescriptorFactory.forLabel( labelId, propertyKeyIds );
IndexStatistics result1 = regularIndices.getIndex( descriptor );
IndexStatistics result2 = result1 == null ? uniqueIndices.getIndex( descriptor ) : result1;
return result2 == null ? Double.NaN : result2.size;
Expand Down Expand Up @@ -313,7 +312,7 @@ private IndexStatistics(double uniqueValuesPercentage, long size)
}
}

private class IndexDescriptorMap implements Iterable<Pair<String, String>>
private class IndexDescriptorMap implements Iterable<Pair<String,String[]>>
{
private final String indexType;
private final Map<LabelSchemaDescriptor, IndexStatistics> indexMap = new HashMap<>();
Expand Down Expand Up @@ -341,10 +340,10 @@ public IndexStatistics getIndex( LabelSchemaDescriptor descriptor )
return indexMap.get( descriptor );
}

public Iterator<Pair<String, String>> iterator()
public Iterator<Pair<String,String[]>> iterator()
{
final Iterator<LabelSchemaDescriptor> iterator = indexMap.keySet().iterator();
return new Iterator<Pair<String, String>>()
return new Iterator<Pair<String,String[]>>()
{
@Override
public boolean hasNext()
Expand All @@ -353,12 +352,12 @@ public boolean hasNext()
}

@Override
public Pair<String, String> next()
public Pair<String,String[]> next()
{
//TODO: Add support for composite indexes
LabelSchemaDescriptor next = iterator.next();
String label = labels.byIdOrFail( next.getLabelId() );
String propertyKey = propertyKeys.byIdOrFail( next.getPropertyIds()[0] );
String[] propertyKey = propertyKeys.byIdOrFail( next.getPropertyIds() );
return Pair.of( label, propertyKey );
}

Expand Down
Expand Up @@ -29,14 +29,14 @@ public interface DbStructureLookup
Iterator<Pair<Integer, String>> properties();
Iterator<Pair<Integer, String>> relationshipTypes();

Iterator<Pair<String, String>> knownIndices();
Iterator<Pair<String, String>> knownUniqueIndices();
Iterator<Pair<String, String>> knownUniqueConstraints();
Iterator<Pair<String, String>> knownNodePropertyExistenceConstraints();
Iterator<Pair<String, String>> knownRelationshipPropertyExistenceConstraints();
Iterator<Pair<String, String[]>> knownIndices();
Iterator<Pair<String, String[]>> knownUniqueIndices();
Iterator<Pair<String, String[]>> knownUniqueConstraints();
Iterator<Pair<String, String[]>> knownNodePropertyExistenceConstraints();
Iterator<Pair<String, String[]>> knownRelationshipPropertyExistenceConstraints();

long nodesWithLabelCardinality( int labelId );
long cardinalityByLabelsAndRelationshipType( int fromLabelId, int relTypeId, int toLabelId );
double indexSelectivity( int labelId, int propertyKeyId );
double indexPropertyExistsSelectivity( int labelId, int propertyKeyId );
double indexSelectivity( int labelId, int... propertyKeyIds );
double indexPropertyExistsSelectivity( int labelId, int... propertyKeyIds );
}
Expand Up @@ -72,8 +72,16 @@ public void shouldFormatIndexDescriptors()
@Test
public void shouldFormatUniquenessConstraints()
{
assertEquals( "ConstraintDescriptorFactory.uniqueForLabel( 23, 42 )", formatArgument(
ConstraintDescriptorFactory.uniqueForSchema( SchemaDescriptorFactory.forLabel( 23, 42 ) ) ) );
assertEquals( "ConstraintDescriptorFactory.uniqueForLabel( 23, 42 )",
formatArgument(
ConstraintDescriptorFactory.uniqueForLabel( 23, 42 ) ) );
}

@Test
public void shouldFormatCompositeUniquenessConstraints()
{
assertEquals( "ConstraintDescriptorFactory.uniqueForLabel( 23, 42, 43 )",
formatArgument( ConstraintDescriptorFactory.uniqueForLabel( 23, 42, 43 ) ) );
}

private String formatArgument( Object arg )
Expand Down
Expand Up @@ -22,10 +22,12 @@
import org.junit.Test;

import org.neo4j.helpers.collection.Iterators;
import org.neo4j.helpers.collection.Pair;
import org.neo4j.kernel.api.schema_new.constaints.ConstraintDescriptorFactory;
import org.neo4j.kernel.api.schema_new.index.NewIndexDescriptorFactory;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.neo4j.helpers.collection.Pair.of;

Expand All @@ -43,7 +45,7 @@ public void collectsDbStructure()
collector.visitRelationshipType( 1, "LIVES_IN" );
collector.visitRelationshipType( 2, "FRIEND" );
collector.visitUniqueIndex( NewIndexDescriptorFactory.forLabel( 1, 1 ), ":Person(name)", 1.0d, 1L );
collector.visitUniqueConstraint( ConstraintDescriptorFactory.uniqueForLabel( 2, 1 ), ":Person(name)" );
collector.visitUniqueConstraint( ConstraintDescriptorFactory.uniqueForLabel( 2, 1 ), ":City(name)" );
collector.visitIndex( NewIndexDescriptorFactory.forLabel( 2, 2 ), ":City(income)", 0.2d, 1L );
collector.visitAllNodesCount( 50 );
collector.visitNodeCount( 1, "Person", 20 );
Expand All @@ -58,9 +60,14 @@ public void collectsDbStructure()
assertEquals( asList( of( 1, "name" ), of( 2, "income" ) ), Iterators.asList( lookup.properties() ) );
assertEquals( asList( of( 1, "LIVES_IN" ), of( 2, "FRIEND" ) ), Iterators.asList( lookup.relationshipTypes() ) );

assertEquals( asList( of( "City", "name" ) ), Iterators.asList( lookup.knownUniqueConstraints() ) );
assertEquals( asList( of( "Person", "name" ) ), Iterators.asList( lookup.knownUniqueIndices() ) );
assertEquals( asList( of( "City", "income" ) ), Iterators.asList( lookup.knownIndices() ) );
assertEquals( asList( "Person" ),
Iterators.asList( Iterators.map( Pair::first, lookup.knownUniqueIndices() ) ) );
assertArrayEquals( new String[]{"name"}, lookup.knownUniqueIndices().next().other() );
assertEquals( asList( "City" ),
Iterators.asList( Iterators.map( Pair::first, lookup.knownUniqueConstraints() ) ) );
assertArrayEquals( new String[]{"name"}, lookup.knownUniqueConstraints().next().other() );
assertEquals( asList( "City" ), Iterators.asList( Iterators.map( Pair::first, lookup.knownIndices() ) ) );
assertArrayEquals( new String[]{"income"}, lookup.knownIndices().next().other() );

assertEquals( 50, lookup.nodesWithLabelCardinality( -1 ) );
assertEquals( 20, lookup.nodesWithLabelCardinality( 1 ) );
Expand All @@ -69,4 +76,55 @@ public void collectsDbStructure()
assertEquals( 1.0d, lookup.indexSelectivity( 1, 1 ), 0.01d );
assertEquals( 0.2d, lookup.indexSelectivity( 2, 2 ), 0.01d );
}

@Test
public void collectsCompositeDbStructure()
{
// GIVEN
DbStructureCollector collector = new DbStructureCollector();
collector.visitLabel( 1, "Person" );
collector.visitLabel( 2, "City" );
collector.visitPropertyKey( 1, "name" );
collector.visitPropertyKey( 2, "income" );
collector.visitPropertyKey( 3, "lastName" );
collector.visitPropertyKey( 4, "tax" );
collector.visitPropertyKey( 5, "area" );
collector.visitRelationshipType( 1, "LIVES_IN" );
collector.visitRelationshipType( 2, "FRIEND" );
collector
.visitUniqueIndex( NewIndexDescriptorFactory.forLabel( 1, 1, 3 ), ":Person(name, lastName)", 1.0d, 1L );
collector.visitUniqueConstraint( ConstraintDescriptorFactory.uniqueForLabel( 2, 1, 5 ), ":City(name, area)" );
collector.visitIndex( NewIndexDescriptorFactory.forLabel( 2, 2, 4 ), ":City(income, tax)", 0.2d, 1L );
collector.visitAllNodesCount( 50 );
collector.visitNodeCount( 1, "Person", 20 );
collector.visitNodeCount( 2, "City", 30 );
collector.visitRelCount( 1, 2, -1, "(:Person)-[:FRIEND]->()", 500 );

// WHEN
DbStructureLookup lookup = collector.lookup();

// THEN
assertEquals( asList( of( 1, "Person" ), of( 2, "City" ) ), Iterators.asList( lookup.labels() ) );
assertEquals(
asList( of( 1, "name" ), of( 2, "income" ), of( 3, "lastName" ), of( 4, "tax" ), of( 5, "area" ) ),
Iterators.asList( lookup.properties() ) );
assertEquals( asList( of( 1, "LIVES_IN" ), of( 2, "FRIEND" ) ),
Iterators.asList( lookup.relationshipTypes() ) );

assertEquals( asList( "Person" ),
Iterators.asList( Iterators.map( Pair::first, lookup.knownUniqueIndices() ) ) );
assertArrayEquals( new String[]{"name", "lastName"}, lookup.knownUniqueIndices().next().other() );
assertEquals( asList( "City" ),
Iterators.asList( Iterators.map( Pair::first, lookup.knownUniqueConstraints() ) ) );
assertArrayEquals( new String[]{"name", "area"}, lookup.knownUniqueConstraints().next().other() );
assertEquals( asList( "City" ), Iterators.asList( Iterators.map( Pair::first, lookup.knownIndices() ) ) );
assertArrayEquals( new String[]{"income", "tax"}, lookup.knownIndices().next().other() );

assertEquals( 50, lookup.nodesWithLabelCardinality( -1 ) );
assertEquals( 20, lookup.nodesWithLabelCardinality( 1 ) );
assertEquals( 30, lookup.nodesWithLabelCardinality( 2 ) );
assertEquals( 500, lookup.cardinalityByLabelsAndRelationshipType( 1, 2, -1 ) );
assertEquals( 1.0d, lookup.indexSelectivity( 1, 1, 3 ), 0.01d );
assertEquals( 0.2d, lookup.indexSelectivity( 2, 2, 4 ), 0.01d );
}
}
Expand Up @@ -127,11 +127,13 @@ private void exerciseVisitor( Function<Object, DbStructureVisitor> visitor )
visitor.apply( null ).visitLabel( 0, "Person" );
visitor.apply( null ).visitLabel( 1, "Party" );
visitor.apply( null ).visitPropertyKey( 0, "name" );
visitor.apply( null ).visitPropertyKey( 2, "lastName" );
visitor.apply( null ).visitPropertyKey( 1, "age" );
visitor.apply( null ).visitRelationshipType( 0, "ACCEPTS" );
visitor.apply( null ).visitRelationshipType( 1, "REJECTS" );
visitor.apply( null ).visitIndex( NewIndexDescriptorFactory.forLabel( 0, 1 ), ":Person(age)", 0.5d, 1L );
visitor.apply( null ).visitUniqueIndex( NewIndexDescriptorFactory.forLabel( 0, 0 ), ":Person(name)", 0.5d, 1L );
visitor.apply( null )
.visitUniqueIndex( NewIndexDescriptorFactory.forLabel( 0, 0, 2 ), ":Person(name, lastName)", 0.5d, 1L );
visitor.apply( null )
.visitUniqueConstraint( ConstraintDescriptorFactory.uniqueForLabel( 1, 0 ), ":Party(name)" );
visitor.apply( null ).visitAllNodesCount( 55 );
Expand Down

0 comments on commit a5ff6e6

Please sign in to comment.