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

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.data</groupId>
  4. <artifactId>spring-data-neo4j</artifactId>
  5. <version>3.3.2.RELEASE</version>
  6. </dependency>
  7. <!-- with production Neo4j Server -->
  8. <dependency>
  9. <groupId>org.springframework.data</groupId>
  10. <artifactId>spring-data-neo4j-rest</artifactId>
  11. <version>3.3.2.RELEASE</version>
  12. </dependency>
  13. <!-- validation -->
  14. <dependency>
  15. <groupId>org.hibernate</groupId>
  16. <artifactId>hibernate-validator</artifactId>
  17. <version>5.1.3.Final</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.springframework</groupId>
  21. <artifactId>spring-test</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework</groupId>
  25. <artifactId>spring-tx</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>javax.el</groupId>
  29. <artifactId>javax.el-api</artifactId>
  30. <version>2.2.4</version>
  31. </dependency>
  32. <!-- log -->
  33. <dependency>
  34. <groupId>org.slf4j</groupId>
  35. <artifactId>slf4j-api</artifactId>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.slf4j</groupId>
  39. <artifactId>slf4j-log4j12</artifactId>
  40. </dependency>
  41. <dependency>
  42. <groupId>log4j</groupId>
  43. <artifactId>log4j</artifactId>
  44. </dependency>
  45. <dependency>
  46. <groupId>junit</groupId>
  47. <artifactId>junit</artifactId>
  48. <scope>test</scope>
  49. </dependency>
  50. </dependencies>

Configuration

  1. package com.spike.springdata.neo4j;
  2. import org.neo4j.graphdb.GraphDatabaseService;
  3. import org.neo4j.graphdb.factory.GraphDatabaseFactory;
  4. import org.neo4j.graphdb.factory.GraphDatabaseSettings;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
  8. import org.springframework.data.neo4j.config.Neo4jConfiguration;
  9. import com.spike.springdata.neo4j.anno.Neo4jInActionBook;
  10. @Configuration
  11. @EnableNeo4jRepositories
  12. public class Neo4jAppDevConfig extends Neo4jConfiguration {
  13. /**
  14. * local file directory of embedded database of Neo4j
  15. */
  16. public static final String Embedded_DB_DIR = "springdataneo4j.db";
  17. /**
  18. * Must use {@link #setBasePackage(String...)}!!!
  19. */
  20. public Neo4jAppDevConfig() {
  21. setBasePackage("com.spike.springdata.neo4j");
  22. }
  23. @Neo4jInActionBook(chapter = { "5" })
  24. @Bean
  25. public GraphDatabaseService graphDatabaseService() {
  26. // GraphDatabaseService result = new
  27. // GraphDatabaseFactory().newEmbeddedDatabase(Embedded_DB_DIR);
  28. // see manual-v2.2.3 37.12. Automatic Indexing
  29. GraphDatabaseService result = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(Embedded_DB_DIR)
  30. .setConfig(GraphDatabaseSettings.node_auto_indexing, "true")
  31. .setConfig(GraphDatabaseSettings.relationship_auto_indexing, "true")
  32. .setConfig(GraphDatabaseSettings.node_keys_indexable, "name, dateOfBirth")
  33. .setConfig(GraphDatabaseSettings.relationship_keys_indexable, "type, name").newGraphDatabase();
  34. return result;
  35. }
  36. }

1 手工创建索引

  1. package com.spike.springdata.neo4j.nativeAPI;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.apache.log4j.Logger;
  5. import org.neo4j.graphdb.GraphDatabaseService;
  6. import org.neo4j.graphdb.Node;
  7. import org.neo4j.graphdb.Transaction;
  8. import org.neo4j.graphdb.factory.GraphDatabaseFactory;
  9. import org.neo4j.graphdb.index.Index;
  10. import org.neo4j.graphdb.index.IndexHits;
  11. import org.neo4j.graphdb.index.IndexManager;
  12. import com.spike.springdata.neo4j.Neo4jAppDevConfig;
  13. import com.spike.springdata.neo4j.Neo4jAppUtils;
  14. import com.spike.springdata.neo4j.anno.Neo4jInActionBook;
  15. /**
  16. * DemonStration of Neo4j manual indexing using APIs
  17. *
  18. * @author zhoujiagen<br/>
  19. * Aug 15, 2015 11:15:32 PM
  20. */
  21. @Neo4jInActionBook(chapter = { "5" })
  22. public class Neo4jManualIndexingDemonstration {
  23. private static final Logger logger = Logger.getLogger(Neo4jManualIndexingDemonstration.class);
  24. /**
  25. * it's not a good practice!
  26. */
  27. private static final String NEWLINE = System.getProperty("line.separator");
  28. private static final String names[] = { "Joanne Smith", "Kate Smith", "John Johnson" };
  29. private static final String emails[] = { "jsmith@example.org", "ksmith@exmaple.org", "jjohnson@exmaple.org" };
  30. private static final Integer ages[] = { 34, 35, 35 };
  31. private static Long[] person_ids = new Long[3];
  32. private static final String NODE_INDEX_NAME = "users";
  33. public static void main(String[] args) {
  34. Neo4jAppUtils.clean(Neo4jAppDevConfig.Embedded_DB_DIR);
  35. // create graph database service
  36. GraphDatabaseService gds = new GraphDatabaseFactory().newEmbeddedDatabase(Neo4jAppDevConfig.Embedded_DB_DIR);
  37. populateGraphData(gds);
  38. List<Node> persons = getNodesByIds(gds, person_ids);
  39. createNodeIndex(gds, NODE_INDEX_NAME, persons.get(0), PropEnum.EMAIL.name(), emails[0]);
  40. searchWithNodeIndex(gds, NODE_INDEX_NAME, PropEnum.EMAIL.name(), emails[0]);
  41. createNodeIndex(gds, NODE_INDEX_NAME, persons.get(0), PropEnum.AGE.name(), ages[0]);
  42. createNodeIndex(gds, NODE_INDEX_NAME, persons.get(1), PropEnum.AGE.name(), ages[1]);
  43. createNodeIndex(gds, NODE_INDEX_NAME, persons.get(2), PropEnum.AGE.name(), ages[2]);
  44. searchWithIndexReturnMultipleResults(gds, PropEnum.AGE.name(), ages[1]);
  45. // dealing with changed indexed entry
  46. String newEmail = "jsmith_new@example.org";
  47. changeIndexValue(gds, NodeIndexEnum.USERS.name(), PropEnum.EMAIL.name(), emails[0], newEmail);
  48. searchWithNodeIndex(gds, NODE_INDEX_NAME, PropEnum.EMAIL.name(), emails[0]);
  49. searchWithNodeIndex(gds, NODE_INDEX_NAME, PropEnum.EMAIL.name(), newEmail);
  50. }
  51. static void populateGraphData(GraphDatabaseService gds) {
  52. try (Transaction tx = gds.beginTx();) {
  53. Node person1 = gds.createNode();
  54. person_ids[0] = person1.getId();
  55. person1.setProperty(PropEnum.NAME.name(), names[0]);
  56. person1.setProperty(PropEnum.EMAIL.name(), emails[0]);
  57. person1.setProperty(PropEnum.AGE.name(), ages[0]);
  58. Node person2 = gds.createNode();
  59. person_ids[1] = person2.getId();
  60. person2.setProperty(PropEnum.NAME.name(), names[1]);
  61. person2.setProperty(PropEnum.EMAIL.name(), emails[1]);
  62. person2.setProperty(PropEnum.AGE.name(), ages[1]);
  63. Node person3 = gds.createNode();
  64. person_ids[2] = person3.getId();
  65. person3.setProperty(PropEnum.NAME.name(), names[2]);
  66. person3.setProperty(PropEnum.EMAIL.name(), emails[2]);
  67. person3.setProperty(PropEnum.AGE.name(), ages[2]);
  68. tx.success();
  69. } catch (Exception e) {
  70. logger.error("Strange things happeded when populate graph data, refer", e);
  71. }
  72. }
  73. static Node getNodeById(GraphDatabaseService gds, Long nodeId) {
  74. Node result = null;
  75. try (Transaction tx = gds.beginTx();) {
  76. result = gds.getNodeById(nodeId);
  77. tx.success();
  78. } catch (Exception e) {
  79. logger.error("Strange things happeded when get node by its id, refer", e);
  80. }
  81. return result;
  82. }
  83. static List<Node> getNodesByIds(GraphDatabaseService gds, Long... nodeIds) {
  84. List<Node> result = new ArrayList<Node>();
  85. try (Transaction tx = gds.beginTx();) {
  86. for (Long nodeId : nodeIds) {
  87. result.add(gds.getNodeById(nodeId));
  88. }
  89. tx.success();
  90. } catch (Exception e) {
  91. logger.error("Strange things happeded when get nodes by their ids, refer", e);
  92. }
  93. return result;
  94. }
  95. static void createNodeIndex(GraphDatabaseService gds, String indexName, Node node, String indexKey,
  96. Object indexValue) {
  97. try (Transaction tx = gds.beginTx();) {
  98. // obtain a reference to IndexManager
  99. IndexManager indexManager = gds.index();
  100. // find or create an named index
  101. Index<Node> index = indexManager.forNodes(indexName);
  102. // 3 parameters: the indexed node, the index key, the indexed value
  103. index.add(node, indexKey, indexValue);
  104. tx.success();
  105. } catch (Exception e) {
  106. logger.error("Strange things happeded when create index, refer", e);
  107. }
  108. }
  109. static void searchWithNodeIndex(GraphDatabaseService gds, String indexName, String indexKey, String indexValue) {
  110. logger.info(NEWLINE + "searchWithIndex(" + indexKey + "," + indexValue + ")");
  111. try (Transaction tx = gds.beginTx();) {
  112. Index<Node> index = gds.index().forNodes(indexName);
  113. // search with index
  114. IndexHits<Node> indexHits = index.get(indexKey, indexValue);
  115. Node resultNode = indexHits.getSingle();// single match
  116. if (resultNode != null) {
  117. logger.info(NEWLINE + renderNode(resultNode));
  118. }
  119. tx.success();
  120. } catch (Exception e) {
  121. logger.error("Strange things happeded when search with index, refer", e);
  122. }
  123. }
  124. static void searchWithIndexReturnMultipleResults(GraphDatabaseService gds, String indexKey, Integer indexValue) {
  125. try (Transaction tx = gds.beginTx();) {
  126. Index<Node> index = gds.index().forNodes(indexKey);
  127. // search with index
  128. IndexHits<Node> indexHits = index.get(indexKey, indexValue);
  129. for (Node node : indexHits) {
  130. logger.info(NEWLINE + renderNode(node));
  131. }
  132. tx.success();
  133. } catch (Exception e) {
  134. logger.error("Strange things happeded when search with index, and multiple results expected, refer", e);
  135. }
  136. }
  137. static void changeIndexValue(GraphDatabaseService gds, String indexName, String indexKey, String sourceIndexValue,
  138. String targetIndexValue) {
  139. try (Transaction tx = gds.beginTx();) {
  140. Index<Node> index = gds.index().forNodes(indexName);
  141. IndexHits<Node> hits = index.get(indexKey, sourceIndexValue);
  142. Node targetNode = hits.getSingle();
  143. if (targetNode != null) {
  144. // remove source indexed entry
  145. index.remove(targetNode, indexKey, sourceIndexValue);
  146. // create the new indexed entry
  147. index.add(targetNode, indexKey, targetIndexValue);
  148. }
  149. } catch (Exception e) {
  150. logger.error("Strange things happeded when changing index values, refer", e);
  151. }
  152. }
  153. /**
  154. * How lovely is Scala's `sealed`
  155. */
  156. static final PropEnum[] ALL_PropEnum = { PropEnum.NAME, PropEnum.EMAIL, PropEnum.AGE };
  157. static String renderNode(Node node) {
  158. StringBuilder sb = new StringBuilder();
  159. for (PropEnum propEnum : ALL_PropEnum) {
  160. sb.append(propEnum.name() + ": " + node.getProperty(propEnum.name()) + ",");
  161. }
  162. String result = sb.toString();
  163. return result.substring(0, result.length() - 1);
  164. }
  165. private static enum PropEnum {
  166. NAME, EMAIL, AGE
  167. }
  168. /**
  169. * the indexes used for nodes
  170. */
  171. private static enum NodeIndexEnum {
  172. USERS
  173. }
  174. }

2 自动创建索引

  1. @Bean
  2. public GraphDatabaseService graphDatabaseService() {
  3. // GraphDatabaseService result = new
  4. // GraphDatabaseFactory().newEmbeddedDatabase(Embedded_DB_DIR);
  5. // see manual-v2.2.3 37.12. Automatic Indexing
  6. GraphDatabaseService result = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(Embedded_DB_DIR)
  7. .setConfig(GraphDatabaseSettings.node_auto_indexing, "true")
  8. .setConfig(GraphDatabaseSettings.relationship_auto_indexing, "true")
  9. .setConfig(GraphDatabaseSettings.node_keys_indexable, "name, dateOfBirth")
  10. .setConfig(GraphDatabaseSettings.relationship_keys_indexable, "type, name").newGraphDatabase();
  11. return result;
  12. }

3 schema创建索引

Graph database不是声称无schema的吗?那是骗鬼的!

  1. package com.spike.springdata.neo4j.nativeAPI;
  2. import org.apache.log4j.Logger;
  3. import org.neo4j.graphdb.DynamicLabel;
  4. import org.neo4j.graphdb.GraphDatabaseService;
  5. import org.neo4j.graphdb.Label;
  6. import org.neo4j.graphdb.Node;
  7. import org.neo4j.graphdb.ResourceIterable;
  8. import org.neo4j.graphdb.Transaction;
  9. import org.neo4j.graphdb.factory.GraphDatabaseFactory;
  10. import org.neo4j.helpers.collection.IteratorUtil;
  11. import com.spike.springdata.neo4j.Neo4jAppDevConfig;
  12. import com.spike.springdata.neo4j.Neo4jAppUtils;
  13. import com.spike.springdata.neo4j.anno.Neo4jInActionBook;
  14. /**
  15. * Demonstration of Neo4j Schema Indexing<br/>
  16. * a feature was introduced in 2.0+
  17. *
  18. * @author zhoujiagen<br/>
  19. * Aug 17, 2015 11:07:27 PM
  20. */
  21. @Neo4jInActionBook(chapter = { "5" })
  22. public class Neo4jSchemaIndexingDemonstration {
  23. private static final Logger logger = Logger.getLogger(Neo4jSchemaIndexingDemonstration.class);
  24. /**
  25. * it's not a good practice!
  26. */
  27. private static final String NEWLINE = System.getProperty("line.separator");
  28. static final Label movieLabel = DynamicLabel.label(LabelEnum.MOVIE.name());
  29. static final Label userLabel = DynamicLabel.label(LabelEnum.USER.name());
  30. static Node movie, user;
  31. static final String name = "Michael Collins";
  32. public static void main(String[] args) {
  33. Neo4jAppUtils.clean(Neo4jAppDevConfig.Embedded_DB_DIR);
  34. Label movieLabel = DynamicLabel.label(LabelEnum.MOVIE.name());
  35. Label userLabel = DynamicLabel.label(LabelEnum.USER.name());
  36. // create graph database service
  37. GraphDatabaseService gds = new GraphDatabaseFactory().newEmbeddedDatabase(Neo4jAppDevConfig.Embedded_DB_DIR);
  38. createSchemaWithIndex(gds);
  39. populateGraphDataWithLabel(gds);
  40. searchWithIndex(gds, movieLabel, PropEnum.NAME.name(), name);
  41. searchWithIndex(gds, userLabel, PropEnum.NAME.name(), name);
  42. }
  43. static void searchWithIndex(GraphDatabaseService gds, Label label, String indexKey, String indexValue) {
  44. try (Transaction tx = gds.beginTx();) {
  45. ResourceIterable<Node> result = gds.findNodesByLabelAndProperty(label, indexKey, indexValue);
  46. logger.info(NEWLINE + "result's size=" + IteratorUtil.count(result));
  47. logger.info(NEWLINE + "movie[" + movie.getId() + "], user[" + user.getId() + "], and result's id="
  48. + result.iterator().next().getId());
  49. tx.success();
  50. } catch (Exception e) {
  51. logger.error("Strange things happend when search with indexes, refer", e);
  52. }
  53. }
  54. static void populateGraphDataWithLabel(GraphDatabaseService gds) {
  55. try (Transaction tx = gds.beginTx();) {
  56. /**
  57. * note {@link GraphDatabaseService#createNode(Label... labels)}<br/>
  58. * so we can create a node with multiple labels, this example is
  59. * omitted
  60. */
  61. movie = gds.createNode(movieLabel);
  62. movie.setProperty(PropEnum.NAME.name(), name);
  63. user = gds.createNode(userLabel);
  64. user.setProperty(PropEnum.NAME.name(), name);
  65. tx.success();
  66. } catch (Exception e) {
  67. logger.error("Strange things happend when populateing data with labels, refer", e);
  68. }
  69. }
  70. static void createSchemaWithIndex(GraphDatabaseService gds) {
  71. // create schema
  72. try (Transaction tx = gds.beginTx();) {
  73. // define indexes
  74. gds.schema().indexFor(movieLabel).on(PropEnum.NAME.name()).create();
  75. gds.schema().indexFor(userLabel).on(PropEnum.NAME.name()).create();
  76. tx.success();
  77. } catch (Exception e) {
  78. logger.error("Strange things happend when creating schema, refer", e);
  79. }
  80. }
  81. private static enum LabelEnum {
  82. MOVIE, USER
  83. }
  84. private static enum PropEnum {
  85. NAME
  86. }
  87. }

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. Oracle子查询(嵌套查询)

    概念: 所谓子查询,即一个select语句中嵌套了另外的一个或者多个select语句 需求:查找和Smith同部门的所有员工的id和last_name 目标: 员工id,last_name from: ...

  2. 【Unity3D游戏开发】之常用代码 (十二)

    //创建一个名为"Player"的游戏物体 //并给他添加刚体和立方体碰撞器. player=new GameObject("Player"); player. ...

  3. 怎样让webservice在浏览器远程浏览时像在本地浏览一样有参数输入框

    从远程客户端访问服务器上的WebService能够显示,但点击调用相关的方法时显示“只能用于来自本地计算机的请求”,这时提醒我们还需要在服务器进行相关的配置才能让其他机器正常访问该WebService ...

  4. 运行时c函数

    // 修改isa,本质就是改变当前对象的类名    object_setClass(self, [XMGKVONotifying_Person class]); // self动态添加关联    // ...

  5. (转) vector的reserve和resize

    文章转自  http://www.cnblogs.com/qlee/archive/2011/05/16/2048026.html vector 的reserve增加了vector的capacity, ...

  6. js之oop <四>对象管理

    对象扩展管理 Object.isExtensible() 检测对象是否可扩展(一般返回true).Object.preventExtensions() 防止对象扩展. var p = {p1:&quo ...

  7. android定义启动唯一apk

    <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="ht ...

  8. i2c设备驱动移植笔记(二)

    说明:上一篇博客写了我在移植android驱动之TEF6606的苦逼遭遇,即驱动层向应用层提供接口支持,查找了两天的资料,不得不放弃,转而进行IIC下移植RTC设备的实验. 第一步:查找设备的数据手册 ...

  9. css-九宫格自适应的实现

    高度自适应使用padding 或 padding-bottom + 百分比来实现: 宽度自适应使用width + 百分比来实现. 下面是实现九宫格自适应的代码: <!DOCTYPE html&g ...

  10. Add two numbers [LeetCode]

    You are given two linked lists representing two non-negative numbers. The digits are stored in rever ...