Prev |  | Next

## 14.13. Automatic Indexing

Neo4j provides a single index for nodes and one for relationships in each database that automatically follow property values as they are added, deleted and changed on database primitives. This functionality is called auto indexing and is controlled both from the database configuration Map and through its own API.

| Caution
This is an experimental feature. Expect changes in the API and do not rely on it for production data handling.

### 14.13.1. Configuration

By default Auto Indexing is off for both Nodes and Relationships. To enable it on database startup set the configuration options `Config.NODE_AUTO_INDEXING` and `Config.RELATIONSHIP_AUTO_INDEXING` to the string "`true`".

If you just enable auto indexing as above, then still no property will be auto indexed. To define which property names you want the auto indexer to monitor as a configuration parameter, set the `Config.{NODE,RELATIONSHIP}_KEYS_INDEXABLE` option to a String that is a comma separated concatenation of the property names you want auto indexed.

    /*
     * Creating the configuration, adding nodeProp1 and nodeProp2 as
     * auto indexed properties for Nodes and relProp1 and relProp2 as
     * auto indexed properties for Relationships. Only those will be
     * indexed. We also have to enable auto indexing for both these
     * primitives explicitly.
     */
    Map<String, String> config = new HashMap<String, String>();
    config.put( Config.NODE_KEYS_INDEXABLE, "nodeProp1, nodeProp2" );
    config.put( Config.RELATIONSHIP_KEYS_INDEXABLE, "relProp1, relProp2" );
    config.put( Config.NODE_AUTO_INDEXING, "true" );
    config.put( Config.RELATIONSHIP_AUTO_INDEXING, "true" );

    EmbeddedGraphDatabase graphDb = new EmbeddedGraphDatabase(
            getStoreDir( "testConfig" ), config );

    Transaction tx = graphDb.beginTx();
    Node node1 = null, node2 = null;
    Relationship rel = null;
    try
    {
        // Create the primitives
        node1 = graphDb.createNode();
        node2 = graphDb.createNode();
        rel = node1.createRelationshipTo( node2,
                DynamicRelationshipType.withName( "DYNAMIC" ) );

        // Add indexable and non-indexable properties
        node1.setProperty( "nodeProp1", "nodeProp1Value" );
        node2.setProperty( "nodeProp2", "nodeProp2Value" );
        node1.setProperty( "nonIndexed", "nodeProp2NonIndexedValue" );
        rel.setProperty( "relProp1", "relProp1Value" );
        rel.setProperty( "relPropNonIndexed", "relPropValueNonIndexed" );

        // Make things persistent
        tx.success();
    }
    catch ( Exception e )
    {
        tx.failure();
    }
    finally
    {
        tx.finish();
    }

### 14.13.2. Search

The usefulness of the auto indexing functionality comes of course from the ability to actually query the index and retrieve results. To that end, you can acquire a `ReadableIndex` object from the `AutoIndexer` that exposes all the query and get methods of a full `Index` with exactly the same functionality. Continuing from the previous example, accessing the index is done like this:

    // Get the Node auto index
    ReadableIndex<Node> autoNodeIndex = graphDb.index().getNodeAutoIndexer().getAutoIndex();
    // node1 and node2 both had auto indexed properties, get them
    assertEquals( node1,
            autoNodeIndex.get( "nodeProp1", "nodeProp1Value" ).getSingle() );
    assertEquals( node2,
            autoNodeIndex.get( "nodeProp2", "nodeProp2Value" ).getSingle() );
    // node2 also had a property that should be ignored.
    assertFalse( autoNodeIndex.get( "nonIndexed",
            "nodeProp2NonIndexedValue" ).hasNext() );

    // Get the relationship auto index
    ReadableIndex<Relationship> autoRelIndex = graphDb.index().getRelationshipAutoIndexer().getAutoIndex();
    // One property was set for auto indexing
    assertEquals( rel,
            autoRelIndex.get( "relProp1", "relProp1Value" ).getSingle() );
    // The rest should be ignored
    assertFalse( autoRelIndex.get( "relPropNonIndexed",
            "relPropValueNonIndexed" ).hasNext() );

### 14.13.3. Runtime Configuration

The same options that are available during database creation via the configuration can also be set during runtime via the `AutoIndexer` API.

Gaining access to the `AutoIndexer` API and adding two `Node` and one +Relationship properties to auto index is done like so:

    // Start without any configuration
    EmbeddedGraphDatabase graphDb = new EmbeddedGraphDatabase(
            getStoreDir( "testAPI" ) );

    // Get the Node AutoIndexer, set nodeProp1 and nodeProp2 as auto
    // indexed.
    AutoIndexer<Node> nodeAutoIndexer = graphDb.index().getNodeAutoIndexer();
    nodeAutoIndexer.startAutoIndexingProperty( "nodeProp1" );
    nodeAutoIndexer.startAutoIndexingProperty( "nodeProp2" );

    // Get the Relationship AutoIndexer
    AutoIndexer<Relationship> relAutoIndexer = graphDb.index().getRelationshipAutoIndexer();
    relAutoIndexer.startAutoIndexingProperty( "relProp1" );

    // None of the AutoIndexers are enabled so far. Do that now
    nodeAutoIndexer.setEnabled( true );
    relAutoIndexer.setEnabled( true );

Parameters to the AutoIndexers passed through the Configuration and settings made through the API are cumulative. So you can set some beforehand known settings, do runtime checks to augment the initial configuration and then enable the desired auto indexers - the final configuration is the same regardless of the method used to reach it.

### 14.13.4. Updating the Automatic Index

Updates to the auto indexed properties happen of course automatically as you update them. Removal of properties from the auto index happens for two reasons. One is that you actually removed the property. The other is that you stopped autoindexing on a property. When the latter happens, any primitive you touch and it has that property, it is removed from the auto index, regardless of any operations on the property. When you start or stop auto indexing on a property, no auto update operation happens currently. If you need to change the set of auto indexed properties and have them re-indexed, you currently have to do this by hand. An example will illustrate the above better:

    /*
     * Creating the configuration
     */
    Map<String, String> config = new HashMap<String, String>();
    config.put( Config.NODE_KEYS_INDEXABLE, "nodeProp1, nodeProp2" );
    config.put( Config.NODE_AUTO_INDEXING, "true" );

    EmbeddedGraphDatabase graphDb = new EmbeddedGraphDatabase(
            getStoreDir( "mutations" ), config );

    Transaction tx = graphDb.beginTx();
    Node node1 = null, node2 = null, node3 = null, node4 = null;
    try
    {
        // Create the primitives
        node1 = graphDb.createNode();
        node2 = graphDb.createNode();
        node3 = graphDb.createNode();
        node4 = graphDb.createNode();

        // Add indexable and non-indexable properties
        node1.setProperty( "nodeProp1", "nodeProp1Value" );
        node2.setProperty( "nodeProp2", "nodeProp2Value" );
        node3.setProperty( "nodeProp1", "nodeProp3Value" );
        node4.setProperty( "nodeProp2", "nodeProp4Value" );

        // Make things persistent
        tx.success();
    }
    catch ( Exception e )
    {
        tx.failure();
    }
    finally
    {
        tx.finish();
    }

    /*
     *  Here both nodes are indexed. To demonstrate removal, we stop
     *  autoindexing nodeProp1.
     */
    AutoIndexer<Node> nodeAutoIndexer = graphDb.index().getNodeAutoIndexer();
    nodeAutoIndexer.stopAutoIndexingProperty( "nodeProp1" );

    tx = graphDb.beginTx();
    try
    {
        /*
         * nodeProp1 is no longer auto indexed. It will be
         * removed regardless. Note that node3 will remain.
         */
        node1.setProperty( "nodeProp1", "nodeProp1Value2" );
        /*
         * node2 will be auto updated
         */
        node2.setProperty( "nodeProp2", "nodeProp2Value2" );
        /*
         * remove node4 property nodeProp2 from index.
         */
        node4.removeProperty( "nodeProp2" );
        // Make things persistent
        tx.success();
    }
    catch ( Exception e )
    {
        tx.failure();
    }
    finally
    {
        tx.finish();
    }

    // Verify
    ReadableIndex<Node> nodeAutoIndex = nodeAutoIndexer.getAutoIndex();
    // node1 is completely gone
    assertFalse( nodeAutoIndex.get( "nodeProp1", "nodeProp1Value" ).hasNext() );
    assertFalse( nodeAutoIndex.get( "nodeProp1", "nodeProp1Value2" ).hasNext() );
    // node2 is updated
    assertFalse( nodeAutoIndex.get( "nodeProp2", "nodeProp2Value" ).hasNext() );
    assertEquals( node2,
            nodeAutoIndex.get( "nodeProp2", "nodeProp2Value2" ).getSingle() );
    /*
     * node3 is still there, despite its nodeProp1 property not being monitored
     * any more because it was not touched, in contrast with node1.
     */
    assertEquals( node3,
            nodeAutoIndex.get( "nodeProp1", "nodeProp3Value" ).getSingle() );
    // Finally, node4 is removed because the property was removed.
    assertFalse( nodeAutoIndex.get( "nodeProp2", "nodeProp4Value" ).hasNext() );

| Caution
If you start the database with auto indexing enabled but different auto indexed properties than the last run, then already auto-indexed entities will be deleted as you work with them. Make sure that the monitored set is what you want before enabling the functionality.

Copyright © 2011 Neo Technology

Prev | Up | Next
| Home |