Skip to content

Commit

Permalink
Add more options for querying the bloom addon
Browse files Browse the repository at this point in the history
  • Loading branch information
ragadeeshu committed Sep 29, 2017
1 parent 61fdc4f commit 8460094
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 98 deletions.
Expand Up @@ -55,27 +55,27 @@ private PartitionedFulltextReader( List<ReadOnlyFulltext> readers )
}

@Override
public PrimitiveLongIterator query( String... terms )
public PrimitiveLongIterator query( boolean matchAll, String... terms )
{
return partitionedOperation( reader -> innerQuery( reader, terms ) );
return partitionedOperation( reader -> innerQuery( reader, matchAll, terms ) );
}

@Override
public PrimitiveLongIterator fuzzyQuery( String... terms )
public PrimitiveLongIterator fuzzyQuery( boolean matchAll, String... terms )
{
return partitionedOperation( reader -> innerFuzzyQuery( reader, terms ) );
return partitionedOperation( reader -> innerFuzzyQuery( reader, matchAll, terms ) );
}

private PrimitiveLongIterator innerQuery( ReadOnlyFulltext reader, String... query )
private PrimitiveLongIterator innerQuery( ReadOnlyFulltext reader, boolean matchAll, String... query )
{

return reader.query( query );
return reader.query( matchAll, query );
}

private PrimitiveLongIterator innerFuzzyQuery( ReadOnlyFulltext reader, String... query )
private PrimitiveLongIterator innerFuzzyQuery( ReadOnlyFulltext reader, boolean matchAll, String... query )
{

return reader.fuzzyQuery( query );
return reader.fuzzyQuery( matchAll, query );
}

public void close()
Expand Down
Expand Up @@ -28,18 +28,22 @@ public interface ReadOnlyFulltext extends AutoCloseable
/**
* Searches the fulltext index for any exact match of any of the given terms against any token in any of the indexed properties.
*
*
* @param matchAll If true, only resluts that match all the given terms will be returned
* @param terms The terms to query for.
* @return An iterator over the matching entityIDs, ordered by lucene scoring of the match.
*/
PrimitiveLongIterator query( String... terms );
PrimitiveLongIterator query( boolean matchAll, String... terms );

/**
* Searches the fulltext index for any fuzzy match of any of the given terms against any token in any of the indexed properties.
*
*
* @param matchAll If true, only resluts that match all the given terms will be returned
* @param terms The terms to query for.
* @return An iterator over the matching entityIDs, ordered by lucene scoring of the match.
*/
PrimitiveLongIterator fuzzyQuery( String... terms );
PrimitiveLongIterator fuzzyQuery( boolean matchAll, String... terms );

@Override
void close();
Expand Down
Expand Up @@ -60,17 +60,17 @@ class SimpleFulltextReader implements ReadOnlyFulltext
}

@Override
public PrimitiveLongIterator query( String... terms )
public PrimitiveLongIterator query( boolean matchAll, String... terms )
{
String query = stream( terms ).map( QueryParser::escape ).collect( joining( " " ) );
return innerQuery( query );
return innerQuery( query, matchAll );
}

@Override
public PrimitiveLongIterator fuzzyQuery( String... terms )
public PrimitiveLongIterator fuzzyQuery( boolean matchAll, String... terms )
{
String query = stream( terms ).map( QueryParser::escape ).collect( joining( "~ ", "", "~" ) );
return innerQuery( query );
return innerQuery( query, matchAll );
}

@Override
Expand Down Expand Up @@ -98,10 +98,17 @@ public FulltextIndexConfiguration getConfigurationDocument() throws IOException
return new FulltextIndexConfiguration( indexSearcher.doc( docs.scoreDocs[0].doc ) );
}

private PrimitiveLongIterator innerQuery( String queryString )
private PrimitiveLongIterator innerQuery( String queryString, boolean matchAll )
{
MultiFieldQueryParser multiFieldQueryParser = new MultiFieldQueryParser( properties, analyzer );
multiFieldQueryParser.setDefaultOperator( QueryParser.Operator.OR );
if ( matchAll )
{
multiFieldQueryParser.setDefaultOperator( QueryParser.Operator.AND );
}
else
{
multiFieldQueryParser.setDefaultOperator( QueryParser.Operator.OR );
}
Query query;
try
{
Expand Down
Expand Up @@ -76,27 +76,37 @@ public Stream<StatusOutput> bloomFulltextStatus() throws Exception

@Description( "Queries the bloom index for nodes" )
@Procedure( name = "db.fulltext.bloomFulltextNodes", mode = READ )
public Stream<EntityOutput> bloomFulltextNodes( @Name( "terms" ) List<String> terms ) throws Exception
public Stream<EntityOutput> bloomFulltextNodes( @Name( "terms" ) List<String> terms, @Name( "fuzzy" ) boolean fuzzy,
@Name( "Require that all terms are matched" ) boolean matchAll ) throws Exception
{
try ( ReadOnlyFulltext indexReader = provider.getReader( BLOOM_NODES, NODES ) )
{
return queryAsStream( terms, indexReader );
return queryAsStream( terms, indexReader, fuzzy, matchAll );
}
}

@Description( "Queries the bloom index for relationships" )
@Procedure( name = "db.fulltext.bloomFulltextRelationships", mode = READ )
public Stream<EntityOutput> bloomFulltextRelationships( @Name( "terms" ) List<String> terms ) throws Exception
public Stream<EntityOutput> bloomFulltextRelationships( @Name( "terms" ) List<String> terms, @Name( "fuzzy" ) boolean fuzzy,
@Name( "Require that all terms are matched" ) boolean matchAll ) throws Exception
{
try ( ReadOnlyFulltext indexReader = provider.getReader( BLOOM_RELATIONSHIPS, RELATIONSHIPS ) )
{
return queryAsStream( terms, indexReader );
return queryAsStream( terms, indexReader, fuzzy, matchAll );
}
}

private Stream<EntityOutput> queryAsStream( List<String> terms, ReadOnlyFulltext indexReader )
private Stream<EntityOutput> queryAsStream( List<String> terms, ReadOnlyFulltext indexReader, boolean fuzzy, boolean matchAll )
{
PrimitiveLongIterator primitiveLongIterator = indexReader.fuzzyQuery( terms.toArray( new String[0] ) );
PrimitiveLongIterator primitiveLongIterator;
if ( fuzzy )
{
primitiveLongIterator = indexReader.fuzzyQuery( matchAll, terms.toArray( new String[0] ) );
}
else
{
primitiveLongIterator = indexReader.query( matchAll, terms.toArray( new String[0] ) );
}
Iterator<EntityOutput> iterator = PrimitiveLongCollections.map( EntityOutput::new, primitiveLongIterator );
return StreamSupport.stream( Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED ), false );
}
Expand Down
Expand Up @@ -57,9 +57,9 @@ public void shouldBeAbleToSpecifyEnglishAnalyzer() throws Exception
assertExactQueryFindsNothing( reader, "and" );
assertExactQueryFindsNothing( reader, "in" );
assertExactQueryFindsNothing( reader, "the" );
assertExactQueryFindsIds( reader, "en", id );
assertExactQueryFindsIds( reader, "och", id );
assertExactQueryFindsIds( reader, "ett", id );
assertExactQueryFindsIds( reader, "en", false, id );
assertExactQueryFindsIds( reader, "och", false, id );
assertExactQueryFindsIds( reader, "ett", false, id );
}
}
}
Expand All @@ -84,9 +84,9 @@ public void shouldBeAbleToSpecifySwedishAnalyzer() throws Exception

try ( ReadOnlyFulltext reader = provider.getReader( BLOOM_NODES, NODES ) )
{
assertExactQueryFindsIds( reader, "and", id );
assertExactQueryFindsIds( reader, "in", id );
assertExactQueryFindsIds( reader, "the", id );
assertExactQueryFindsIds( reader, "and", false, id );
assertExactQueryFindsIds( reader, "in", false, id );
assertExactQueryFindsIds( reader, "the", false, id );
assertExactQueryFindsNothing( reader, "en" );
assertExactQueryFindsNothing( reader, "och" );
assertExactQueryFindsNothing( reader, "ett" );
Expand Down Expand Up @@ -119,9 +119,9 @@ public void shouldReindexNodesWhenAnalyzerIsChanged() throws Exception
assertExactQueryFindsNothing( reader, "and" );
assertExactQueryFindsNothing( reader, "in" );
assertExactQueryFindsNothing( reader, "the" );
assertExactQueryFindsIds( reader, "en", secondID );
assertExactQueryFindsIds( reader, "och", secondID );
assertExactQueryFindsIds( reader, "ett", secondID );
assertExactQueryFindsIds( reader, "en", false, secondID );
assertExactQueryFindsIds( reader, "och", false, secondID );
assertExactQueryFindsIds( reader, "ett", false, secondID );
}
}

Expand All @@ -134,9 +134,9 @@ public void shouldReindexNodesWhenAnalyzerIsChanged() throws Exception

try ( ReadOnlyFulltext reader = provider.getReader( BLOOM_NODES, NODES ) )
{
assertExactQueryFindsIds( reader, "and", firstID );
assertExactQueryFindsIds( reader, "in", firstID );
assertExactQueryFindsIds( reader, "the", firstID );
assertExactQueryFindsIds( reader, "and", false, firstID );
assertExactQueryFindsIds( reader, "in", false, firstID );
assertExactQueryFindsIds( reader, "the", false, firstID );
assertExactQueryFindsNothing( reader, "en" );
assertExactQueryFindsNothing( reader, "och" );
assertExactQueryFindsNothing( reader, "ett" );
Expand Down
Expand Up @@ -26,6 +26,7 @@
import java.io.File;
import java.io.IOException;
import java.time.Clock;
import java.util.Arrays;

import org.neo4j.collection.primitive.PrimitiveLongCollections;
import org.neo4j.collection.primitive.PrimitiveLongIterator;
Expand All @@ -44,6 +45,7 @@
import org.neo4j.test.rule.DatabaseRule;
import org.neo4j.test.rule.EmbeddedDatabaseRule;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class LuceneFulltextTestSupport
Expand Down Expand Up @@ -110,34 +112,64 @@ protected long createRelationshipWithProperty( long firstNodeId, long secondNode

protected void assertExactQueryFindsNothing( ReadOnlyFulltext reader, String query )
{
assertExactQueryFindsIds( reader, query );
assertExactQueryFindsIds( reader, query, false );
}

protected void assertExactQueryFindsIds( ReadOnlyFulltext reader, String[] query, long... ids )
protected void assertExactQueryFindsIds( ReadOnlyFulltext reader, String[] query, boolean matchAll, long... ids )
{
PrimitiveLongIterator result = reader.query( query );
PrimitiveLongIterator result = reader.query( matchAll, query );
assertQueryResultsMatch( result, ids );
}

protected void assertExactQueryFindsIds( ReadOnlyFulltext reader, String query, long... ids )
protected void assertExactQueryFindsIdsInOrder( ReadOnlyFulltext reader, String[] query, boolean matchAll, long... ids )
{
assertExactQueryFindsIds( reader, new String[]{query}, ids );
PrimitiveLongIterator result = reader.query( matchAll, query );
assertQueryResultsMatchInOrder( result, ids );
}

protected void assertFuzzyQueryFindsIds( ReadOnlyFulltext reader, String query, long... ids )
protected void assertExactQueryFindsIds( ReadOnlyFulltext reader, String query, boolean matchAll, long... ids )
{
PrimitiveLongIterator result = reader.fuzzyQuery( query );
assertExactQueryFindsIds( reader, new String[]{query}, matchAll, ids );
}

protected void assertFuzzyQueryFindsIds( ReadOnlyFulltext reader, String query, boolean matchAll, long... ids )
{
assertFuzzyQueryFindsIds( reader, new String[]{query}, matchAll, ids );
}

protected void assertFuzzyQueryFindsIds( ReadOnlyFulltext reader, String[] query, boolean matchAll, long... ids )
{
PrimitiveLongIterator result = reader.fuzzyQuery( matchAll, query );
assertQueryResultsMatch( result, ids );
}

protected void assertFuzzyQueryFindsIdsInOrder( ReadOnlyFulltext reader, String query, boolean matchAll, long... ids )
{
PrimitiveLongIterator result = reader.fuzzyQuery( matchAll, query );
assertQueryResultsMatchInOrder( result, ids );
}

protected void assertQueryResultsMatch( PrimitiveLongIterator result, long[] ids )
{
PrimitiveLongSet set = PrimitiveLongCollections.setOf( ids );
while ( result.hasNext() )
{
assertTrue( set.remove( result.next() ) );
long next = result.next();
assertTrue( String.format( "Result returned node id %d, expected one of %s", next, Arrays.toString( ids ) ), set.remove( next ) );
}
assertTrue( "Number of results differ from expected", set.isEmpty() );
}

protected void assertQueryResultsMatchInOrder( PrimitiveLongIterator result, long[] ids )
{
int num = 0;
while ( result.hasNext() )
{
long next = result.next();
assertEquals( String.format( "Result returned node id %d, expected %d", next, ids[num] ), ids[num], next );
num++;
}
assertTrue( set.isEmpty() );
assertEquals( "Number of results differ from expected", ids.length, num );
}

protected void setNodeProp( long nodeId, String value )
Expand Down

0 comments on commit 8460094

Please sign in to comment.