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的更多相关文章

  1. Neo4j:Index索引

    Indexing in Neo4j: An Overview by Stefan Armbruster · Jan. 06, 14 · Java Zone Neo4j是一个图数据库,在做图的检索时,用 ...

  2. 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 ...

  3. 基于neo4j图数据库,实现人口关系大图的基本思路及实现方案。

    近期由于工作需要,需要做一个人口关系大图的存储及检索方案,我们主要的数据对象有:人口(年龄,身份证号码,性别..) :学校信息(学校地址,学校名称,学校级别,学校下边的年级班级..):就职信息(公司名 ...

  4. Neo4j中實現自定義中文全文索引

    資料庫檢索效率時,一般首要優化途徑是從索引入手,然後根據需求再考慮更復雜的負載均衡.讀寫分離和分散式水平/垂直分庫/表等手段:索引通過資訊冗餘來提高檢索效率,其以空間換時間並會降低資料寫入的效率,因此 ...

  5. NEO4J中文分词全文索引自动更新解决方案

    NEO4J中文分词全文索引自动更新解决方案 一.样例数据 二.英文与中文全文索引差别 1.创建NEO4J默认索引 2.删除索引 3.创建支持中文分词的索引 三.APOC自带英文全文索引过程(可自动更新 ...

  6. NEO4J亿级数据全文索引构建优化

    NEO4J亿级数据全文索引构建优化 一.数据量规模(亿级) 二.构建索引的方式 三.构建索引发生的异常 四.全文索引代码优化 1.Java.lang.OutOfMemoryError 2.访问数据库时 ...

  7. Neo4j中实现自定义中文全文索引

    数据库检索效率时,一般首要优化途径是从索引入手,然后根据需求再考虑更复杂的负载均衡.读写分离和分布式水平/垂直分库/表等手段:索引通过信息冗余来提高检索效率,其以空间换时间并会降低数据写入的效率:因此 ...

  8. Java基础学习总结--对象容器

    目录: ArrayList 顺序泛型容器 HashSet 集合容器 HashMap<Key,Value>容器 要用Java实现记事本的功能.首先列出记事本所需功能: 可以添加记录(字符串) ...

  9. MVC中Controller控制器相关技术

    第6章Controller相关技术 Controller(控制器)在ASP.NET MVC中负责控制所有客户端与服务器端的交互,并 且负责协调Model与View之间的数椐传递,是ASP.NET MV ...

随机推荐

  1. Java 中的 static 使用之静态方法

    与静态变量一样,我们也可以使用 static 修饰方法,称为静态方法或类方法.其实之前我们一直写的 main 方法就是静态方法.静态方法的使用如: 运行结果: 需要注意: 1. 静态方法中可以直接调用 ...

  2. 解决打开CHM文件后,右侧空白

    在网上下了一个chm的文件,打开后只有目录,右侧不显示内容. 不知道是文件有问题,还是系统有问题. <ignore_js_op> 右键点击文件–属性 看到 最下面有一个提示 说是这个文件是 ...

  3. (十)Linux 网络编程之ioctl函数

    1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ...

  4. win7 桌面上的网络邻居不见了

    win7 桌面上的网络邻居不见了,可能是以前在桌面上直接删除了.现右击桌面--个性化--更改桌面图标,也找不到网上邻居了.怎么找回来啊? 网上邻居已经改名叫网络了.可以右键桌面选择“个性化”,然后更改 ...

  5. android开发文档工具集(持续更新中...)

     http://www.androiddevtools.cn/ android 产品->交互->视觉->开发->测试各种工具地址下载, 各种文档下载应有尽有,强烈推荐.  ht ...

  6. rpm安装和卸载软件

    1.安装 rpm -i 需要安装的包文件名 举例如下: rpm -i example.rpm 安装 example.rpm 包: rpm -iv example.rpm 安装 example.rpm ...

  7. 解决本机安装多版本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 ...

  8. 安装mongodb

    安装mongodb的时候遇到一些麻烦 首先将安装包下下来 安装的是windows版本的 将bin文件夹加入环境变量后通过mongod和mongo指令就可以进行操作,很方便 用指令mongod --db ...

  9. 无法查找或打开pdb文件

    工具->选项->调试{常规->启动源服务支持,符号->Microsoft符号服务器} 如果再不行.要重新生成一下,(不是重新生成解决方案)

  10. iOS开发UI篇—控制器的View的创建

    iOS开发UI篇—控制器的View的创建 一.6种创建控制器View的方式 #import "NJAppDelegate.h" #import "NJViewContro ...