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 ...
随机推荐
- TextInfo
https://msdn.microsoft.com/en-us/library/system.globalization.textinfo.totitlecase(v=vs.110).aspx Co ...
- 【树莓派】使用树莓派制作img镜像(二)
树莓派制作的镜像,需要如何使用,这里直接引用目前树莓派官方的文章,不再重复描述: 参考:http://shumeipai.nxez.com/2013/08/31/usb-image-tool.html ...
- (转)C++中的static关键字的总结
文章转自 http://www.cnblogs.com/BeyondAnyTime/archive/2012/06/08/2542315.html C++的static有两种用法:面向过程程序设计中的 ...
- 《第一本docker书》第4章 使用docker镜像和仓库 读书笔记
docker最底端是一个引导文件系统,即bootfs. 第二层是root文件系统rootfs,位于引导文件系统之上. 在传统的Linux引导过程中,root文件系统会最先以只读的方式加载,当引导结束并 ...
- 使用jquery中height()方法获取各种高度大全
alert($(window).height()); //浏览器当前窗口可视区域高度 alert($(document).height()); //浏览器当前窗口文档的高度 alert($(docum ...
- sqlite与android交互 (封装)
学android已经有大概一周时间了吧 ,总感觉自己基础不怎么好,只能通过一点一点积累着敲来巩固平常的知识,有的时候就先不封装的敲一遍,再封装上,有些语句真的记不住,虽然知道他是什么意思,于是乎就反复 ...
- Deep Learning 16:用自编码器对数据进行降维_读论文“Reducing the Dimensionality of Data with Neural Networks”的笔记
前言 论文“Reducing the Dimensionality of Data with Neural Networks”是深度学习鼻祖hinton于2006年发表于<SCIENCE > ...
- Head First 设计模式 --4 工厂模式 抽象工厂模式
(用到了依赖倒置原则) 我们写的代码中,有的时候可能会出现根据外面给定的不同的参数在方法中根据参数实例化不同的实例,就是会根据不同的参数会new出不同的实例.如果这么写了,这段代码会非常的脆弱,一旦出 ...
- 阿里云服务器 FTP配置图文教程和添加两个FTP站点
1.添加FTP账号和密码. A. 选择“服务管理器”->“配置”->“本地用户和组”->“用户”:在空白处右键选择“新用户”: B. 输入用户名,全名和描述可以不填写:输入两遍密码: ...
- Mybatis 批量insert
@Override public int insertHouseTypeScene(int htid, String name, String icon,int sort, List<House ...