Skip to content

Commit

Permalink
Add endsWith to our index abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
systay committed Mar 2, 2016
1 parent 63fdd8e commit 7c874ef
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 86 deletions.
Expand Up @@ -260,6 +260,12 @@ public PrimitiveLongIterator containsString( String exactTerm )
throw new UnsupportedOperationException();
}

@Override
public PrimitiveLongIterator endsWith( String suffix )
{
throw new UnsupportedOperationException();
}

@Override
public long countIndexedNodes( long nodeId, Object propertyValue )
{
Expand Down
Expand Up @@ -159,7 +159,7 @@ class NodeIndexContainsScanAcceptanceTest extends ExecutionEngineFunSuite with N
result should (use("NodeIndexContainsScan") and evaluateTo(List.empty))
}

test("throws appropiate type error") {
test("throws appropriate type error") {
createLabeledNode(Map("name" -> "London"), "Location")
createLabeledNode(Map("name" -> "LONDON"), "Location")
graph.inTx {
Expand Down
Expand Up @@ -69,6 +69,12 @@ public PrimitiveLongIterator containsString( String exactTerm )
return delegate.containsString( exactTerm );
}

@Override
public PrimitiveLongIterator endsWith( String suffix )
{
return delegate.endsWith( suffix );
}

@Override
public long countIndexedNodes( long nodeId, Object propertyValue )
{
Expand Down
Expand Up @@ -82,6 +82,14 @@ public interface IndexReader extends Resource
*/
PrimitiveLongIterator containsString( String exactTerm );

/**
* Searches this index for string values ending with the suffix search string.
*
* @param suffix the string to search for in the index
* @return ids of matching nodes.
*/
PrimitiveLongIterator endsWith( String suffix );

/**
* @param nodeId node if to match.
* @param propertyValue property value to match.
Expand Down Expand Up @@ -130,6 +138,12 @@ public PrimitiveLongIterator containsString( String exactTerm )
return PrimitiveLongCollections.emptyIterator();
}

@Override
public PrimitiveLongIterator endsWith(String suffix)
{
return PrimitiveLongCollections.emptyIterator();
}

// Used for checking index correctness
@Override
public long countIndexedNodes( long nodeId, Object propertyValue )
Expand Down
Expand Up @@ -140,80 +140,45 @@ public void testIndexSeekByPrefixOnNonStrings() throws Exception

protected List<Long> getAllNodesWithProperty( String propertyValue ) throws IOException
{
try ( IndexReader reader = accessor.newReader() )
{
List<Long> list = new LinkedList<>();
for ( PrimitiveLongIterator iterator = reader.seek( propertyValue ); iterator.hasNext(); )
{
list.add( iterator.next() );
}
Collections.sort( list );
return list;
}
return metaGet( reader -> reader.seek( propertyValue ));
}

protected List<Long> getAllNodesFromInclusiveIndexSeekByNumber( Number lower, Number upper ) throws IOException
{
try ( IndexReader reader = accessor.newReader() )
{
List<Long> list = new LinkedList<>();
for ( PrimitiveLongIterator iterator = reader.rangeSeekByNumberInclusive( lower, upper ); iterator.hasNext(); )
{
list.add( iterator.next() );
}
Collections.sort( list );
return list;
}
return metaGet( reader -> reader.rangeSeekByNumberInclusive( lower, upper ));
}

protected List<Long> getAllNodesFromIndexSeekByString( String lower, boolean includeLower, String upper, boolean includeUpper ) throws IOException
{
try ( IndexReader reader = accessor.newReader() )
{
List<Long> list = new LinkedList<>();
for ( PrimitiveLongIterator iterator = reader.rangeSeekByString( lower, includeLower, upper, includeUpper ); iterator.hasNext(); )
{
list.add( iterator.next() );
}
Collections.sort( list );
return list;
}
return metaGet( reader -> reader.rangeSeekByString( lower, includeLower, upper, includeUpper ));
}

protected List<Long> getAllNodesFromIndexSeekByPrefix( String prefix ) throws IOException
{
try ( IndexReader reader = accessor.newReader() )
{
List<Long> list = new LinkedList<>();
for ( PrimitiveLongIterator iterator = reader.rangeSeekByPrefix( prefix ); iterator.hasNext(); )
{
list.add( iterator.next() );
}
Collections.sort( list );
return list;
}
return metaGet( reader -> reader.rangeSeekByPrefix( prefix));
}

protected List<Long> getAllNodesFromIndexSeekByContains( String term ) throws IOException
protected List<Long> getAllNodesFromIndexScanByContains( String term ) throws IOException
{
try ( IndexReader reader = accessor.newReader() )
{
List<Long> list = new LinkedList<>();
for ( PrimitiveLongIterator iterator = reader.containsString( term ); iterator.hasNext(); )
{
list.add( iterator.next() );
}
Collections.sort( list );
return list;
}
return metaGet( reader -> reader.containsString( term ) );
}

protected List<Long> getAllNodesFromIndexScanEndsWith( String term ) throws IOException
{
return metaGet( reader -> reader.endsWith( term ) );
}

protected List<Long> getAllNodes() throws IOException
{
return metaGet( IndexReader::scan );
}

private List<Long> metaGet( ReaderInteraction interaction )
{
try ( IndexReader reader = accessor.newReader() )
{
List<Long> list = new LinkedList<>();
for ( PrimitiveLongIterator iterator = reader.scan(); iterator.hasNext(); )
for ( PrimitiveLongIterator iterator = interaction.results( reader ); iterator.hasNext(); )
{
list.add( iterator.next() );
}
Expand All @@ -222,6 +187,12 @@ protected List<Long> getAllNodes() throws IOException
}
}

private interface ReaderInteraction
{
PrimitiveLongIterator results( IndexReader reader );
}


protected void updateAndCommit( List<NodePropertyUpdate> updates )
throws IOException, IndexEntryConflictException
{
Expand Down
Expand Up @@ -133,8 +133,25 @@ public void testIndexFullSearchWithDuplicates() throws Exception
NodePropertyUpdate.add( 4L, PROPERTY_KEY_ID, "apa", new long[]{1000} ),
NodePropertyUpdate.add( 5L, PROPERTY_KEY_ID, "apalong", new long[]{1000} ) ) );

assertThat( getAllNodesFromIndexSeekByContains( "a" ), equalTo( asList( 1L, 3L, 4L, 5L ) ) );
assertThat( getAllNodesFromIndexSeekByContains( "apa" ), equalTo( asList( 3L, 4L, 5L ) ) );
assertThat( getAllNodesFromIndexSeekByContains( "apa*" ), equalTo( Collections.emptyList() ) );
assertThat( getAllNodesFromIndexScanByContains( "a" ), equalTo( asList( 1L, 3L, 4L, 5L ) ) );
assertThat( getAllNodesFromIndexScanByContains( "apa" ), equalTo( asList( 3L, 4L, 5L ) ) );
assertThat( getAllNodesFromIndexScanByContains( "apa*" ), equalTo( Collections.emptyList() ) );
}

@Test
public void testIndexEndsWithWithDuplicated() throws Exception
{
updateAndCommit( asList(
NodePropertyUpdate.add( 1L, PROPERTY_KEY_ID, "a", new long[]{1000} ),
NodePropertyUpdate.add( 2L, PROPERTY_KEY_ID, "A", new long[]{1000} ),
NodePropertyUpdate.add( 3L, PROPERTY_KEY_ID, "apa", new long[]{1000} ),
NodePropertyUpdate.add( 4L, PROPERTY_KEY_ID, "apa", new long[]{1000} ),
NodePropertyUpdate.add( 5L, PROPERTY_KEY_ID, "longapa", new long[]{1000} ),
NodePropertyUpdate.add( 6L, PROPERTY_KEY_ID, "apalong", new long[]{1000} ) ) );

assertThat( getAllNodesFromIndexScanEndsWith( "a" ), equalTo( asList( 1L, 3L, 4L, 5L ) ) );
assertThat( getAllNodesFromIndexScanEndsWith( "apa" ), equalTo( asList( 3L, 4L, 5L ) ) );
assertThat( getAllNodesFromIndexScanEndsWith( "apa*" ), equalTo( Collections.emptyList() ) );
assertThat( getAllNodesFromIndexScanEndsWith( "" ), equalTo( asList( 1L, 2L, 3L, 4L, 5L, 6L ) ) );
}
}
Expand Up @@ -140,44 +140,26 @@ public synchronized PrimitiveLongIterator rangeSeekByString( String lower, boole
@Override
public synchronized PrimitiveLongIterator rangeSeekByPrefix( String prefix )
{
Set<Long> nodeIds = new HashSet<>();
for ( Map.Entry<Object,Set<Long>> entry : data.entrySet() )
{
Object key = entry.getKey();
if ( key instanceof String )
{
if ( key.toString().startsWith( prefix ) )
{
nodeIds.addAll( entry.getValue() );
}
}
}
return toPrimitiveIterator( nodeIds.iterator() );
return stringSearch( ( String entry ) -> entry.startsWith( prefix ) );
}

@Override
public synchronized PrimitiveLongIterator scan()
public synchronized PrimitiveLongIterator containsString( String exactTerm )
{
Iterable<Long> all = Iterables.flattenIterable( data.values() );
return toPrimitiveIterator( all.iterator() );
return stringSearch( ( String entry ) -> entry.contains( exactTerm ) );
}

@Override
public synchronized PrimitiveLongIterator containsString( String exactTerm )
public PrimitiveLongIterator endsWith( String suffix )
{
Set<Long> nodeIds = new HashSet<>();
for ( Map.Entry<Object,Set<Long>> entry : data.entrySet() )
{
Object key = entry.getKey();
if ( key instanceof String )
{
if ( key.toString().contains( exactTerm ) )
{
nodeIds.addAll( entry.getValue() );
}
}
}
return toPrimitiveIterator( nodeIds.iterator() );
return stringSearch( ( String entry ) -> entry.endsWith( suffix ) );
}

@Override
public synchronized PrimitiveLongIterator scan()
{
Iterable<Long> all = Iterables.flattenIterable( data.values() );
return toPrimitiveIterator( all.iterator() );
}

@Override
Expand Down Expand Up @@ -266,4 +248,27 @@ public synchronized IndexSampler createSampler()
{
return new HashBasedIndexSampler( data );
}

private interface StringFilter
{
boolean test( String s );
}

private PrimitiveLongIterator stringSearch( StringFilter filter )
{
Set<Long> nodeIds = new HashSet<>();
for ( Map.Entry<Object,Set<Long>> entry : data.entrySet() )
{
Object key = entry.getKey();
if ( key instanceof String )
{
if ( filter.test( (String) key ) )
{
nodeIds.addAll( entry.getValue() );
}
}
}
return toPrimitiveIterator( nodeIds.iterator() );
}

}
Expand Up @@ -169,6 +169,14 @@ public static Query newRangeSeekByPrefixQuery( String prefix )
return new ConstantScoreQuery( prefixQuery );
}

public static Query newSuffixStringQuery( String suffix )
{
String searchTerm = QueryParser.escape( suffix );
Term term = new Term( ValueEncoding.String.key(), "*" + searchTerm );

return new WildcardQuery( term );
}

public static Term newTermForChangeOrRemove( long nodeId )
{
return new Term( NODE_ID_KEY, "" + nodeId );
Expand Down
Expand Up @@ -99,6 +99,12 @@ public PrimitiveLongIterator containsString( String exactTerm )
return partitionedOperation( reader -> reader. containsString( exactTerm ) );
}

@Override
public PrimitiveLongIterator endsWith( String suffix )
{
return partitionedOperation( reader -> reader.endsWith( suffix ) );
}

@Override
public long countIndexedNodes( long nodeId, Object propertyValue )
{
Expand Down
Expand Up @@ -116,6 +116,12 @@ public PrimitiveLongIterator containsString( String exactTerm )
return query( LuceneDocumentStructure.newWildCardStringQuery( exactTerm ) );
}

@Override
public PrimitiveLongIterator endsWith( String suffix )
{
return query( LuceneDocumentStructure.newSuffixStringQuery( suffix ) );
}

@Override
public long countIndexedNodes( long nodeId, Object propertyValue )
{
Expand Down

0 comments on commit 7c874ef

Please sign in to comment.