Skip to content

Commit

Permalink
Insight index support multiple properties per node
Browse files Browse the repository at this point in the history
  • Loading branch information
ragadeeshu committed Sep 12, 2017
1 parent 0aca7b3 commit 1fc8258
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 40 deletions.
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.neo4j.kernel.api.impl.index; package org.neo4j.kernel.api.impl.index;


import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.PostingsFormat;
import org.apache.lucene.codecs.blocktreeords.BlockTreeOrdsPostingsFormat; import org.apache.lucene.codecs.blocktreeords.BlockTreeOrdsPostingsFormat;
import org.apache.lucene.codecs.lucene54.Lucene54Codec; import org.apache.lucene.codecs.lucene54.Lucene54Codec;
Expand Down Expand Up @@ -71,7 +72,13 @@ private IndexWriterConfigs()


public static IndexWriterConfig standard() public static IndexWriterConfig standard()
{ {
IndexWriterConfig writerConfig = new IndexWriterConfig( LuceneDataSource.KEYWORD_ANALYZER ); Analyzer analyzer = LuceneDataSource.KEYWORD_ANALYZER;
return getIndexWriterConfigWithAnalyzer( analyzer );
}

private static IndexWriterConfig getIndexWriterConfigWithAnalyzer( Analyzer analyzer )
{
IndexWriterConfig writerConfig = new IndexWriterConfig( analyzer );


writerConfig.setMaxBufferedDocs( MAX_BUFFERED_DOCS ); writerConfig.setMaxBufferedDocs( MAX_BUFFERED_DOCS );
writerConfig.setMaxBufferedDeleteTerms( MAX_BUFFERED_DELETE_TERMS ); writerConfig.setMaxBufferedDeleteTerms( MAX_BUFFERED_DELETE_TERMS );
Expand Down Expand Up @@ -108,4 +115,12 @@ public static IndexWriterConfig population()
writerConfig.setRAMBufferSizeMB( POPULATION_RAM_BUFFER_SIZE_MB ); writerConfig.setRAMBufferSizeMB( POPULATION_RAM_BUFFER_SIZE_MB );
return writerConfig; return writerConfig;
} }

public static IndexWriterConfig population( Analyzer analyzer )
{
IndexWriterConfig writerConfig = getIndexWriterConfigWithAnalyzer( analyzer );
writerConfig.setMaxBufferedDocs( POPULATION_MAX_BUFFERED_DOCS );
writerConfig.setRAMBufferSizeMB( POPULATION_RAM_BUFFER_SIZE_MB );
return writerConfig;
}
} }
Expand Up @@ -19,18 +19,13 @@
*/ */
package org.neo4j.kernel.api.impl.insight; package org.neo4j.kernel.api.impl.insight;


import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.en.EnglishAnalyzer;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField; import org.apache.lucene.document.TextField;


import org.neo4j.values.storable.TextValue; import org.neo4j.values.storable.TextValue;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.Values; import org.neo4j.values.storable.Values;


import static org.apache.lucene.document.Field.Store.NO;

/** /**
* Enumeration representing all possible property types with corresponding encodings and query structures for Lucene * Enumeration representing all possible property types with corresponding encodings and query structures for Lucene
* schema indexes. * schema indexes.
Expand Down Expand Up @@ -156,8 +151,7 @@ Field encodeField( String name, Value value )
{ {
java.lang.String stringValue = ((TextValue) value).stringValue(); java.lang.String stringValue = ((TextValue) value).stringValue();


TokenStream tokenStream = englishAnalyzer.tokenStream( name, stringValue ); TextField field = new TextField( name, stringValue, Field.Store.NO );
TextField field = new TextField( name, tokenStream );
return field; return field;
} }


Expand All @@ -175,7 +169,6 @@ Field encodeField( String name, Value value )
// } // }
}; };


private static EnglishAnalyzer englishAnalyzer = new EnglishAnalyzer();
private static final InsightFieldEncoding[] AllEncodings = values(); private static final InsightFieldEncoding[] AllEncodings = values();


abstract String key(); abstract String key();
Expand Down
Expand Up @@ -19,11 +19,14 @@
*/ */
package org.neo4j.kernel.api.impl.insight; package org.neo4j.kernel.api.impl.insight;


import org.apache.lucene.analysis.en.EnglishAnalyzer;
import org.apache.lucene.index.IndexWriterConfig;

import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays;


import org.neo4j.function.Factory;
import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.kernel.api.impl.index.IndexWriterConfigs; import org.neo4j.kernel.api.impl.index.IndexWriterConfigs;
import org.neo4j.kernel.api.impl.index.builder.LuceneIndexStorageBuilder; import org.neo4j.kernel.api.impl.index.builder.LuceneIndexStorageBuilder;
Expand All @@ -35,18 +38,16 @@ public class InsightIndex implements AutoCloseable
{ {
private final InsightLuceneIndex nodeIndex; private final InsightLuceneIndex nodeIndex;


public InsightIndex( FileSystemAbstraction fileSystem, File file, int[] properties ) throws IOException public InsightIndex( FileSystemAbstraction fileSystem, File file, String... properties ) throws IOException
{ {
LuceneIndexStorageBuilder storageBuilder = LuceneIndexStorageBuilder.create(); LuceneIndexStorageBuilder storageBuilder = LuceneIndexStorageBuilder.create();
storageBuilder.withFileSystem( fileSystem ).withIndexIdentifier( "insightNodes" ) storageBuilder.withFileSystem( fileSystem ).withIndexIdentifier( "insightNodes" )
.withDirectoryFactory( directoryFactory( false, fileSystem ) ) .withDirectoryFactory( directoryFactory( false, fileSystem ) )
.withIndexRootFolder( Paths.get( file.getAbsolutePath(),"insightindex" ).toFile() ); .withIndexRootFolder( Paths.get( file.getAbsolutePath(),"insightindex" ).toFile() );


WritableIndexPartitionFactory partitionFactory = new WritableIndexPartitionFactory( Factory<IndexWriterConfig> population = () -> IndexWriterConfigs.population( new EnglishAnalyzer() );
IndexWriterConfigs::population ); WritableIndexPartitionFactory partitionFactory = new WritableIndexPartitionFactory( population );
String[] propertyIdsAsStrings = Arrays.stream( properties ).sorted().mapToObj( String::valueOf ) nodeIndex = new InsightLuceneIndex( storageBuilder.build(), partitionFactory, properties );
.toArray( String[]::new );
nodeIndex = new InsightLuceneIndex( storageBuilder.build(), partitionFactory, propertyIdsAsStrings );
nodeIndex.open(); nodeIndex.open();
} }


Expand Down
Expand Up @@ -22,13 +22,12 @@
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;


import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.event.PropertyEntry;
import org.neo4j.graphdb.event.TransactionData; import org.neo4j.graphdb.event.TransactionData;
import org.neo4j.graphdb.event.TransactionEventHandler; import org.neo4j.graphdb.event.TransactionEventHandler;
import org.neo4j.kernel.api.properties.PropertyKeyValue;
import org.neo4j.values.storable.Values;


public class InsightIndexTransactionEventUpdater implements TransactionEventHandler<Object> public class InsightIndexTransactionEventUpdater implements TransactionEventHandler<Object>
{ {
Expand All @@ -42,24 +41,26 @@ public class InsightIndexTransactionEventUpdater implements TransactionEventHand
@Override @Override
public Object beforeCommit( TransactionData data ) throws Exception public Object beforeCommit( TransactionData data ) throws Exception
{ {
return null; Map<Long,Map<String,Object>> map = new HashMap<Long,Map<String,Object>>();
data.createdNodes().forEach( node -> map.put( node.getId(), node.getAllProperties() ) );
return map;
} }


@Override @Override
public void afterCommit( TransactionData data, Object state ) public void afterCommit( TransactionData data, Object state )
{ {
writeNodeData( data.assignedNodeProperties() ); writeNodeData( data.createdNodes(), (Map<Long,Map<String,Object>>) state );
deleteNodeData( data.deletedNodes() ); deleteNodeData( data.deletedNodes() );
} }


private void writeNodeData( Iterable<PropertyEntry<Node>> propertyEntries ) private void writeNodeData( Iterable<Node> propertyEntries, Map<Long,Map<String,Object>> state )
{ {
for ( PropertyEntry<Node> propertyEntry : propertyEntries ) for ( Node node : propertyEntries )
{ {
// propertyEntry.previouslyCommitedValue()
Document document = LuceneInsightDocumentStructure.documentRepresentingProperties( propertyEntry.entity().getId(), Map<String,Object> allProperties = state.get( node.getId() );
//TODO THIS IS BAD
new PropertyKeyValue( Integer.parseInt( "1" ), Values.of( propertyEntry.value() ) ) ); Document document = LuceneInsightDocumentStructure.documentRepresentingProperties( node.getId(), allProperties );
try try
{ {
writableDatabaseInsightIndex.getIndexWriter().addDocument( document ); writableDatabaseInsightIndex.getIndexWriter().addDocument( document );
Expand Down
Expand Up @@ -27,9 +27,10 @@
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;


import java.util.Iterator; import java.util.Iterator;
import java.util.Map;


import org.neo4j.kernel.api.properties.PropertyKeyValue;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.Values;


import static org.apache.lucene.document.Field.Store.YES; import static org.apache.lucene.document.Field.Store.YES;


Expand All @@ -50,7 +51,7 @@ private static DocWithId reuseDocument( long nodeId )
return doc; return doc;
} }


public static Document documentRepresentingProperties( long nodeId, PropertyKeyValue... values ) public static Document documentRepresentingProperties( long nodeId, Map<String,Object> values )
{ {
DocWithId document = reuseDocument( nodeId ); DocWithId document = reuseDocument( nodeId );
document.setValues( values ); document.setValues( values );
Expand All @@ -62,10 +63,10 @@ public static long getNodeId( Document from )
return Long.parseLong( from.get( NODE_ID_KEY ) ); return Long.parseLong( from.get( NODE_ID_KEY ) );
} }


static Field encodeValueField( int propertyNumber, Value value ) static Field encodeValueField( String propertyKey, Value value )
{ {
InsightFieldEncoding encoding = InsightFieldEncoding.forValue( value ); InsightFieldEncoding encoding = InsightFieldEncoding.forValue( value );
return encoding.encodeField( Integer.toString( propertyNumber ), value ); return encoding.encodeField( propertyKey, value );
} }


private static class DocWithId private static class DocWithId
Expand All @@ -91,11 +92,11 @@ private void setId( long id )
idValueField.setLongValue( id ); idValueField.setLongValue( id );
} }


private void setValues( PropertyKeyValue... values ) private void setValues( Map<String,Object> values )
{ {
for ( int i = 0; i < values.length; i++ ) for ( Map.Entry<String,Object> entry : values.entrySet() )
{ {
Field field = encodeValueField( values[i].propertyKeyId(), values[i].value() ); Field field = encodeValueField( entry.getKey(), Values.of( entry.getValue() ) );
document.add( field ); document.add( field );
} }
} }
Expand Down
Expand Up @@ -61,7 +61,11 @@ public PrimitiveLongIterator query( String... query )
BooleanQuery.Builder builder = new BooleanQuery.Builder(); BooleanQuery.Builder builder = new BooleanQuery.Builder();
for ( String property : properties ) for ( String property : properties )
{ {
builder.add( new PhraseQuery( property, query ), BooleanClause.Occur.SHOULD ); builder.add( new PhraseQuery( 2, property, query ), BooleanClause.Occur.SHOULD );
for ( String s : query )
{
builder.add( new PhraseQuery( 2, property, s ), BooleanClause.Occur.SHOULD );
}
} }
return query( builder.build() ); return query( builder.build() );
} }
Expand Down
Expand Up @@ -23,8 +23,7 @@
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;


import java.io.IOException; import org.neo4j.collection.primitive.PrimitiveLongIterator;

import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.Transaction;
Expand All @@ -33,7 +32,6 @@
import org.neo4j.test.rule.EmbeddedDatabaseRule; import org.neo4j.test.rule.EmbeddedDatabaseRule;
import org.neo4j.test.rule.TestDirectory; import org.neo4j.test.rule.TestDirectory;
import org.neo4j.test.rule.fs.DefaultFileSystemRule; import org.neo4j.test.rule.fs.DefaultFileSystemRule;
import org.neo4j.test.rule.fs.EphemeralFileSystemRule;
import org.neo4j.test.rule.fs.FileSystemRule; import org.neo4j.test.rule.fs.FileSystemRule;


import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
Expand All @@ -54,7 +52,8 @@ public class InsightLuceneIndexUpdaterTest
public void shouldFindNodeWithString() throws Exception public void shouldFindNodeWithString() throws Exception
{ {
GraphDatabaseAPI db = dbRule.getGraphDatabaseAPI(); GraphDatabaseAPI db = dbRule.getGraphDatabaseAPI();
try (InsightIndex insightIndex = new InsightIndex(fileSystemRule, testDirectory.graphDbDir(), new int[]{1})) { try ( InsightIndex insightIndex = new InsightIndex( fileSystemRule, testDirectory.graphDbDir(), "prop" ) )
{
db.registerTransactionEventHandler(insightIndex.getUpdater()); db.registerTransactionEventHandler(insightIndex.getUpdater());


long firstID; long firstID;
Expand Down Expand Up @@ -86,7 +85,8 @@ public void shouldFindNodeWithString() throws Exception
public void shouldNotFindRemovedNodes() throws Exception public void shouldNotFindRemovedNodes() throws Exception
{ {
GraphDatabaseAPI db = dbRule.getGraphDatabaseAPI(); GraphDatabaseAPI db = dbRule.getGraphDatabaseAPI();
try (InsightIndex insightIndex = new InsightIndex(fileSystemRule, testDirectory.graphDbDir(), new int[]{1})) { try ( InsightIndex insightIndex = new InsightIndex( fileSystemRule, testDirectory.graphDbDir(), "prop" ) )
{
db.registerTransactionEventHandler(insightIndex.getUpdater()); db.registerTransactionEventHandler(insightIndex.getUpdater());


long firstID; long firstID;
Expand Down Expand Up @@ -120,4 +120,42 @@ public void shouldNotFindRemovedNodes() throws Exception
} }
} }
} }

@Test
public void shouldOrderResults() throws Exception
{
GraphDatabaseAPI db = dbRule.getGraphDatabaseAPI();
try ( InsightIndex insightIndex = new InsightIndex( fileSystemRule, testDirectory.graphDbDir(), "prop", "prop2" ) )
{
db.registerTransactionEventHandler( insightIndex.getUpdater() );

long firstID;
long secondID;
long thirdID;
try ( Transaction tx = db.beginTx() )
{
Node node = db.createNode( LABEL );
firstID = node.getId();
node.setProperty( "prop", "Tomtar tomtar oftsat i tomteutstyrsel." );
Node node2 = db.createNode( LABEL );
secondID = node2.getId();
node2.setProperty( "prop", "tomtar tomtar tomtar tomtar tomtar." );
node2.setProperty( "prop2", "tomtar tomtar tomtar tomtar tomtar tomtar karl" );
Node node3 = db.createNode( LABEL );
thirdID = node3.getId();
node3.setProperty( "prop", "Tomtar som tomtar ser upp till tomtar som inte tomtar." );

tx.success();
}

try ( InsightIndexReader reader = insightIndex.getReader() )
{

PrimitiveLongIterator iterator = reader.query( "tomtar", "karl" );
assertEquals( secondID, iterator.next() );
assertEquals( firstID, iterator.next() );
assertEquals( thirdID, iterator.next() );
}
}
}
} }

0 comments on commit 1fc8258

Please sign in to comment.