Neo4j Index Notes
Motivation
GraphDatabasesBook: Robinson I., Webber J., Eifrem E. Graph Databases. 2013.
这本该是入门概念性质的书,但是没有讲清楚最重要的索引。我相信绝大部分人不会去看600页+的Neo4j手册的。
Neo4jInActionBook: Vukotic A., Watt N. et al. Neo4j in Action. 2015.
这本就不同了,虽然“旧”了点(其实是Neo4j变化太快,有些API不支持了),将索引讲的很清楚。
我很懒,真的很懒。就以可以工作的代码(测试开发用)来说明吧。
Talk is cheap, show me the code.
代码托管见SpringDataBasedNoSQLTutorials.
0 测试环境配置
Maven
<dependencies>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-neo4j</artifactId>
        <version>3.3.2.RELEASE</version>
    </dependency>
    <!-- with production Neo4j Server -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-neo4j-rest</artifactId>
        <version>3.3.2.RELEASE</version>
    </dependency>
    <!-- validation -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.3.Final</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>2.2.4</version>
    </dependency>
    <!-- log -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>Configuration
package com.spike.springdata.neo4j;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import com.spike.springdata.neo4j.anno.Neo4jInActionBook;
@Configuration
@EnableNeo4jRepositories
public class Neo4jAppDevConfig extends Neo4jConfiguration {
    /**
     * local file directory of embedded database of Neo4j
     */
    public static final String Embedded_DB_DIR = "springdataneo4j.db";
    /**
     * Must use {@link #setBasePackage(String...)}!!!
     */
    public Neo4jAppDevConfig() {
        setBasePackage("com.spike.springdata.neo4j");
    }
    @Neo4jInActionBook(chapter = { "5" })
    @Bean
    public GraphDatabaseService graphDatabaseService() {
        // GraphDatabaseService result = new
        // GraphDatabaseFactory().newEmbeddedDatabase(Embedded_DB_DIR);
        // see manual-v2.2.3 37.12. Automatic Indexing
        GraphDatabaseService result = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(Embedded_DB_DIR)
                .setConfig(GraphDatabaseSettings.node_auto_indexing, "true")
                .setConfig(GraphDatabaseSettings.relationship_auto_indexing, "true")
                .setConfig(GraphDatabaseSettings.node_keys_indexable, "name, dateOfBirth")
                .setConfig(GraphDatabaseSettings.relationship_keys_indexable, "type, name").newGraphDatabase();
        return result;
    }
}1 手工创建索引
package com.spike.springdata.neo4j.nativeAPI;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.IndexManager;
import com.spike.springdata.neo4j.Neo4jAppDevConfig;
import com.spike.springdata.neo4j.Neo4jAppUtils;
import com.spike.springdata.neo4j.anno.Neo4jInActionBook;
/**
 * DemonStration of Neo4j manual indexing using APIs
 *
 * @author zhoujiagen<br/>
 *         Aug 15, 2015 11:15:32 PM
 */
@Neo4jInActionBook(chapter = { "5" })
public class Neo4jManualIndexingDemonstration {
    private static final Logger logger = Logger.getLogger(Neo4jManualIndexingDemonstration.class);
    /**
     * it's not a good practice!
     */
    private static final String NEWLINE = System.getProperty("line.separator");
    private static final String names[] = { "Joanne Smith", "Kate Smith", "John Johnson" };
    private static final String emails[] = { "jsmith@example.org", "ksmith@exmaple.org", "jjohnson@exmaple.org" };
    private static final Integer ages[] = { 34, 35, 35 };
    private static Long[] person_ids = new Long[3];
    private static final String NODE_INDEX_NAME = "users";
    public static void main(String[] args) {
        Neo4jAppUtils.clean(Neo4jAppDevConfig.Embedded_DB_DIR);
        // create graph database service
        GraphDatabaseService gds = new GraphDatabaseFactory().newEmbeddedDatabase(Neo4jAppDevConfig.Embedded_DB_DIR);
        populateGraphData(gds);
        List<Node> persons = getNodesByIds(gds, person_ids);
        createNodeIndex(gds, NODE_INDEX_NAME, persons.get(0), PropEnum.EMAIL.name(), emails[0]);
        searchWithNodeIndex(gds, NODE_INDEX_NAME, PropEnum.EMAIL.name(), emails[0]);
        createNodeIndex(gds, NODE_INDEX_NAME, persons.get(0), PropEnum.AGE.name(), ages[0]);
        createNodeIndex(gds, NODE_INDEX_NAME, persons.get(1), PropEnum.AGE.name(), ages[1]);
        createNodeIndex(gds, NODE_INDEX_NAME, persons.get(2), PropEnum.AGE.name(), ages[2]);
        searchWithIndexReturnMultipleResults(gds, PropEnum.AGE.name(), ages[1]);
        // dealing with changed indexed entry
        String newEmail = "jsmith_new@example.org";
        changeIndexValue(gds, NodeIndexEnum.USERS.name(), PropEnum.EMAIL.name(), emails[0], newEmail);
        searchWithNodeIndex(gds, NODE_INDEX_NAME, PropEnum.EMAIL.name(), emails[0]);
        searchWithNodeIndex(gds, NODE_INDEX_NAME, PropEnum.EMAIL.name(), newEmail);
    }
    static void populateGraphData(GraphDatabaseService gds) {
        try (Transaction tx = gds.beginTx();) {
            Node person1 = gds.createNode();
            person_ids[0] = person1.getId();
            person1.setProperty(PropEnum.NAME.name(), names[0]);
            person1.setProperty(PropEnum.EMAIL.name(), emails[0]);
            person1.setProperty(PropEnum.AGE.name(), ages[0]);
            Node person2 = gds.createNode();
            person_ids[1] = person2.getId();
            person2.setProperty(PropEnum.NAME.name(), names[1]);
            person2.setProperty(PropEnum.EMAIL.name(), emails[1]);
            person2.setProperty(PropEnum.AGE.name(), ages[1]);
            Node person3 = gds.createNode();
            person_ids[2] = person3.getId();
            person3.setProperty(PropEnum.NAME.name(), names[2]);
            person3.setProperty(PropEnum.EMAIL.name(), emails[2]);
            person3.setProperty(PropEnum.AGE.name(), ages[2]);
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happeded when populate graph data, refer", e);
        }
    }
    static Node getNodeById(GraphDatabaseService gds, Long nodeId) {
        Node result = null;
        try (Transaction tx = gds.beginTx();) {
            result = gds.getNodeById(nodeId);
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happeded when get node by its id, refer", e);
        }
        return result;
    }
    static List<Node> getNodesByIds(GraphDatabaseService gds, Long... nodeIds) {
        List<Node> result = new ArrayList<Node>();
        try (Transaction tx = gds.beginTx();) {
            for (Long nodeId : nodeIds) {
                result.add(gds.getNodeById(nodeId));
            }
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happeded when get nodes by their ids, refer", e);
        }
        return result;
    }
    static void createNodeIndex(GraphDatabaseService gds, String indexName, Node node, String indexKey,
            Object indexValue) {
        try (Transaction tx = gds.beginTx();) {
            // obtain a reference to IndexManager
            IndexManager indexManager = gds.index();
            // find or create an named index
            Index<Node> index = indexManager.forNodes(indexName);
            // 3 parameters: the indexed node, the index key, the indexed value
            index.add(node, indexKey, indexValue);
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happeded when create index, refer", e);
        }
    }
    static void searchWithNodeIndex(GraphDatabaseService gds, String indexName, String indexKey, String indexValue) {
        logger.info(NEWLINE + "searchWithIndex(" + indexKey + "," + indexValue + ")");
        try (Transaction tx = gds.beginTx();) {
            Index<Node> index = gds.index().forNodes(indexName);
            // search with index
            IndexHits<Node> indexHits = index.get(indexKey, indexValue);
            Node resultNode = indexHits.getSingle();// single match
            if (resultNode != null) {
                logger.info(NEWLINE + renderNode(resultNode));
            }
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happeded when search with index, refer", e);
        }
    }
    static void searchWithIndexReturnMultipleResults(GraphDatabaseService gds, String indexKey, Integer indexValue) {
        try (Transaction tx = gds.beginTx();) {
            Index<Node> index = gds.index().forNodes(indexKey);
            // search with index
            IndexHits<Node> indexHits = index.get(indexKey, indexValue);
            for (Node node : indexHits) {
                logger.info(NEWLINE + renderNode(node));
            }
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happeded when search with index, and multiple results expected, refer", e);
        }
    }
    static void changeIndexValue(GraphDatabaseService gds, String indexName, String indexKey, String sourceIndexValue,
            String targetIndexValue) {
        try (Transaction tx = gds.beginTx();) {
            Index<Node> index = gds.index().forNodes(indexName);
            IndexHits<Node> hits = index.get(indexKey, sourceIndexValue);
            Node targetNode = hits.getSingle();
            if (targetNode != null) {
                // remove source indexed entry
                index.remove(targetNode, indexKey, sourceIndexValue);
                // create the new indexed entry
                index.add(targetNode, indexKey, targetIndexValue);
            }
        } catch (Exception e) {
            logger.error("Strange things happeded when changing index values, refer", e);
        }
    }
    /**
     * How lovely is Scala's `sealed`
     */
    static final PropEnum[] ALL_PropEnum = { PropEnum.NAME, PropEnum.EMAIL, PropEnum.AGE };
    static String renderNode(Node node) {
        StringBuilder sb = new StringBuilder();
        for (PropEnum propEnum : ALL_PropEnum) {
            sb.append(propEnum.name() + ": " + node.getProperty(propEnum.name()) + ",");
        }
        String result = sb.toString();
        return result.substring(0, result.length() - 1);
    }
    private static enum PropEnum {
        NAME, EMAIL, AGE
    }
    /**
     * the indexes used for nodes
     */
    private static enum NodeIndexEnum {
        USERS
    }
}2 自动创建索引
    @Bean
    public GraphDatabaseService graphDatabaseService() {
        // GraphDatabaseService result = new
        // GraphDatabaseFactory().newEmbeddedDatabase(Embedded_DB_DIR);
        // see manual-v2.2.3 37.12. Automatic Indexing
        GraphDatabaseService result = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(Embedded_DB_DIR)
                .setConfig(GraphDatabaseSettings.node_auto_indexing, "true")
                .setConfig(GraphDatabaseSettings.relationship_auto_indexing, "true")
                .setConfig(GraphDatabaseSettings.node_keys_indexable, "name, dateOfBirth")
                .setConfig(GraphDatabaseSettings.relationship_keys_indexable, "type, name").newGraphDatabase();
        return result;
    }3 schema创建索引
Graph database不是声称无schema的吗?那是骗鬼的!
package com.spike.springdata.neo4j.nativeAPI;
import org.apache.log4j.Logger;
import org.neo4j.graphdb.DynamicLabel;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.ResourceIterable;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.helpers.collection.IteratorUtil;
import com.spike.springdata.neo4j.Neo4jAppDevConfig;
import com.spike.springdata.neo4j.Neo4jAppUtils;
import com.spike.springdata.neo4j.anno.Neo4jInActionBook;
/**
 * Demonstration of Neo4j Schema Indexing<br/>
 * a feature was introduced in 2.0+
 *
 * @author zhoujiagen<br/>
 *         Aug 17, 2015 11:07:27 PM
 */
@Neo4jInActionBook(chapter = { "5" })
public class Neo4jSchemaIndexingDemonstration {
    private static final Logger logger = Logger.getLogger(Neo4jSchemaIndexingDemonstration.class);
    /**
     * it's not a good practice!
     */
    private static final String NEWLINE = System.getProperty("line.separator");
    static final Label movieLabel = DynamicLabel.label(LabelEnum.MOVIE.name());
    static final Label userLabel = DynamicLabel.label(LabelEnum.USER.name());
    static Node movie, user;
    static final String name = "Michael Collins";
    public static void main(String[] args) {
        Neo4jAppUtils.clean(Neo4jAppDevConfig.Embedded_DB_DIR);
        Label movieLabel = DynamicLabel.label(LabelEnum.MOVIE.name());
        Label userLabel = DynamicLabel.label(LabelEnum.USER.name());
        // create graph database service
        GraphDatabaseService gds = new GraphDatabaseFactory().newEmbeddedDatabase(Neo4jAppDevConfig.Embedded_DB_DIR);
        createSchemaWithIndex(gds);
        populateGraphDataWithLabel(gds);
        searchWithIndex(gds, movieLabel, PropEnum.NAME.name(), name);
        searchWithIndex(gds, userLabel, PropEnum.NAME.name(), name);
    }
    static void searchWithIndex(GraphDatabaseService gds, Label label, String indexKey, String indexValue) {
        try (Transaction tx = gds.beginTx();) {
            ResourceIterable<Node> result = gds.findNodesByLabelAndProperty(label, indexKey, indexValue);
            logger.info(NEWLINE + "result's size=" + IteratorUtil.count(result));
            logger.info(NEWLINE + "movie[" + movie.getId() + "], user[" + user.getId() + "], and result's id="
                    + result.iterator().next().getId());
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happend when search with indexes, refer", e);
        }
    }
    static void populateGraphDataWithLabel(GraphDatabaseService gds) {
        try (Transaction tx = gds.beginTx();) {
            /**
             * note {@link GraphDatabaseService#createNode(Label... labels)}<br/>
             * so we can create a node with multiple labels, this example is
             * omitted
             */
            movie = gds.createNode(movieLabel);
            movie.setProperty(PropEnum.NAME.name(), name);
            user = gds.createNode(userLabel);
            user.setProperty(PropEnum.NAME.name(), name);
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happend when populateing data with labels, refer", e);
        }
    }
    static void createSchemaWithIndex(GraphDatabaseService gds) {
        // create schema
        try (Transaction tx = gds.beginTx();) {
            // define indexes
            gds.schema().indexFor(movieLabel).on(PropEnum.NAME.name()).create();
            gds.schema().indexFor(userLabel).on(PropEnum.NAME.name()).create();
            tx.success();
        } catch (Exception e) {
            logger.error("Strange things happend when creating schema, refer", e);
        }
    }
    private static enum LabelEnum {
        MOVIE, USER
    }
    private static enum PropEnum {
        NAME
    }
}Neo4j Index Notes的更多相关文章
- Neo4j:Index索引
		Indexing in Neo4j: An Overview by Stefan Armbruster · Jan. 06, 14 · Java Zone Neo4j是一个图数据库,在做图的检索时,用 ... 
- Solution for automatic update of Chinese word segmentation full-text index in NEO4J
		Solution for automatic update of Chinese word segmentation full-text index in NEO4J 1. Sample data 2 ... 
- 基于neo4j图数据库,实现人口关系大图的基本思路及实现方案。
		近期由于工作需要,需要做一个人口关系大图的存储及检索方案,我们主要的数据对象有:人口(年龄,身份证号码,性别..) :学校信息(学校地址,学校名称,学校级别,学校下边的年级班级..):就职信息(公司名 ... 
- Neo4j中實現自定義中文全文索引
		資料庫檢索效率時,一般首要優化途徑是從索引入手,然後根據需求再考慮更復雜的負載均衡.讀寫分離和分散式水平/垂直分庫/表等手段:索引通過資訊冗餘來提高檢索效率,其以空間換時間並會降低資料寫入的效率,因此 ... 
- NEO4J中文分词全文索引自动更新解决方案
		NEO4J中文分词全文索引自动更新解决方案 一.样例数据 二.英文与中文全文索引差别 1.创建NEO4J默认索引 2.删除索引 3.创建支持中文分词的索引 三.APOC自带英文全文索引过程(可自动更新 ... 
- NEO4J亿级数据全文索引构建优化
		NEO4J亿级数据全文索引构建优化 一.数据量规模(亿级) 二.构建索引的方式 三.构建索引发生的异常 四.全文索引代码优化 1.Java.lang.OutOfMemoryError 2.访问数据库时 ... 
- Neo4j中实现自定义中文全文索引
		数据库检索效率时,一般首要优化途径是从索引入手,然后根据需求再考虑更复杂的负载均衡.读写分离和分布式水平/垂直分库/表等手段:索引通过信息冗余来提高检索效率,其以空间换时间并会降低数据写入的效率:因此 ... 
- Java基础学习总结--对象容器
		目录: ArrayList 顺序泛型容器 HashSet 集合容器 HashMap<Key,Value>容器 要用Java实现记事本的功能.首先列出记事本所需功能: 可以添加记录(字符串) ... 
- MVC中Controller控制器相关技术
		第6章Controller相关技术 Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务器端的交互,并 且负责协调Model与View之间的数椐传递,是ASP.NET MV ... 
随机推荐
- Java 中的 static 使用之静态方法
			与静态变量一样,我们也可以使用 static 修饰方法,称为静态方法或类方法.其实之前我们一直写的 main 方法就是静态方法.静态方法的使用如: 运行结果: 需要注意: 1. 静态方法中可以直接调用 ... 
- 解决打开CHM文件后,右侧空白
			在网上下了一个chm的文件,打开后只有目录,右侧不显示内容. 不知道是文件有问题,还是系统有问题. <ignore_js_op> 右键点击文件–属性 看到 最下面有一个提示 说是这个文件是 ... 
- (十)Linux 网络编程之ioctl函数
			1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ... 
- win7 桌面上的网络邻居不见了
			win7 桌面上的网络邻居不见了,可能是以前在桌面上直接删除了.现右击桌面--个性化--更改桌面图标,也找不到网上邻居了.怎么找回来啊? 网上邻居已经改名叫网络了.可以右键桌面选择“个性化”,然后更改 ... 
- android开发文档工具集(持续更新中...)
			http://www.androiddevtools.cn/ android 产品->交互->视觉->开发->测试各种工具地址下载, 各种文档下载应有尽有,强烈推荐. ht ... 
- rpm安装和卸载软件
			1.安装 rpm -i 需要安装的包文件名 举例如下: rpm -i example.rpm 安装 example.rpm 包: rpm -iv example.rpm 安装 example.rpm ... 
- 解决本机安装多版本jdk导致The type java.lang.Object cannot be resolved It is indirectly referenced ...
			本机开始安装了jdk1.6,然后安装了jdk1.8 当在调自动化的时候,发现传入函数传参String类型,报错The type java.lang.Object cannot be resolved ... 
- 安装mongodb
			安装mongodb的时候遇到一些麻烦 首先将安装包下下来 安装的是windows版本的 将bin文件夹加入环境变量后通过mongod和mongo指令就可以进行操作,很方便 用指令mongod --db ... 
- 无法查找或打开pdb文件
			工具->选项->调试{常规->启动源服务支持,符号->Microsoft符号服务器} 如果再不行.要重新生成一下,(不是重新生成解决方案) 
- iOS开发UI篇—控制器的View的创建
			iOS开发UI篇—控制器的View的创建 一.6种创建控制器View的方式 #import "NJAppDelegate.h" #import "NJViewContro ... 
