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 @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 @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() 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. * 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. * @param terms The terms to query for.
* @return An iterator over the matching entityIDs, ordered by lucene scoring of the match. * @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. * 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. * @param terms The terms to query for.
* @return An iterator over the matching entityIDs, ordered by lucene scoring of the match. * @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 @Override
void close(); void close();
Expand Down
Expand Up @@ -60,17 +60,17 @@ class SimpleFulltextReader implements ReadOnlyFulltext
} }


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


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


@Override @Override
Expand Down Expand Up @@ -98,10 +98,17 @@ public FulltextIndexConfiguration getConfigurationDocument() throws IOException
return new FulltextIndexConfiguration( indexSearcher.doc( docs.scoreDocs[0].doc ) ); 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 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; Query query;
try try
{ {
Expand Down
Expand Up @@ -76,27 +76,37 @@ public Stream<StatusOutput> bloomFulltextStatus() throws Exception


@Description( "Queries the bloom index for nodes" ) @Description( "Queries the bloom index for nodes" )
@Procedure( name = "db.fulltext.bloomFulltextNodes", mode = READ ) @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 ) ) 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" ) @Description( "Queries the bloom index for relationships" )
@Procedure( name = "db.fulltext.bloomFulltextRelationships", mode = READ ) @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 ) ) 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 ); Iterator<EntityOutput> iterator = PrimitiveLongCollections.map( EntityOutput::new, primitiveLongIterator );
return StreamSupport.stream( Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED ), false ); 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, "and" );
assertExactQueryFindsNothing( reader, "in" ); assertExactQueryFindsNothing( reader, "in" );
assertExactQueryFindsNothing( reader, "the" ); assertExactQueryFindsNothing( reader, "the" );
assertExactQueryFindsIds( reader, "en", id ); assertExactQueryFindsIds( reader, "en", false, id );
assertExactQueryFindsIds( reader, "och", id ); assertExactQueryFindsIds( reader, "och", false, id );
assertExactQueryFindsIds( reader, "ett", 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 ) ) try ( ReadOnlyFulltext reader = provider.getReader( BLOOM_NODES, NODES ) )
{ {
assertExactQueryFindsIds( reader, "and", id ); assertExactQueryFindsIds( reader, "and", false, id );
assertExactQueryFindsIds( reader, "in", id ); assertExactQueryFindsIds( reader, "in", false, id );
assertExactQueryFindsIds( reader, "the", id ); assertExactQueryFindsIds( reader, "the", false, id );
assertExactQueryFindsNothing( reader, "en" ); assertExactQueryFindsNothing( reader, "en" );
assertExactQueryFindsNothing( reader, "och" ); assertExactQueryFindsNothing( reader, "och" );
assertExactQueryFindsNothing( reader, "ett" ); assertExactQueryFindsNothing( reader, "ett" );
Expand Down Expand Up @@ -119,9 +119,9 @@ public void shouldReindexNodesWhenAnalyzerIsChanged() throws Exception
assertExactQueryFindsNothing( reader, "and" ); assertExactQueryFindsNothing( reader, "and" );
assertExactQueryFindsNothing( reader, "in" ); assertExactQueryFindsNothing( reader, "in" );
assertExactQueryFindsNothing( reader, "the" ); assertExactQueryFindsNothing( reader, "the" );
assertExactQueryFindsIds( reader, "en", secondID ); assertExactQueryFindsIds( reader, "en", false, secondID );
assertExactQueryFindsIds( reader, "och", secondID ); assertExactQueryFindsIds( reader, "och", false, secondID );
assertExactQueryFindsIds( reader, "ett", 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 ) ) try ( ReadOnlyFulltext reader = provider.getReader( BLOOM_NODES, NODES ) )
{ {
assertExactQueryFindsIds( reader, "and", firstID ); assertExactQueryFindsIds( reader, "and", false, firstID );
assertExactQueryFindsIds( reader, "in", firstID ); assertExactQueryFindsIds( reader, "in", false, firstID );
assertExactQueryFindsIds( reader, "the", firstID ); assertExactQueryFindsIds( reader, "the", false, firstID );
assertExactQueryFindsNothing( reader, "en" ); assertExactQueryFindsNothing( reader, "en" );
assertExactQueryFindsNothing( reader, "och" ); assertExactQueryFindsNothing( reader, "och" );
assertExactQueryFindsNothing( reader, "ett" ); assertExactQueryFindsNothing( reader, "ett" );
Expand Down
Expand Up @@ -26,6 +26,7 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.Clock; import java.time.Clock;
import java.util.Arrays;


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


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


public class LuceneFulltextTestSupport 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 ) 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 ); 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 ); 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 ) protected void assertQueryResultsMatch( PrimitiveLongIterator result, long[] ids )
{ {
PrimitiveLongSet set = PrimitiveLongCollections.setOf( ids ); PrimitiveLongSet set = PrimitiveLongCollections.setOf( ids );
while ( result.hasNext() ) 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 ) protected void setNodeProp( long nodeId, String value )
Expand Down

0 comments on commit 8460094

Please sign in to comment.