1 应用开发概述
基于数据传输效率以及接口自定义等特殊性需求,我们暂时放弃使用Neo4j服务器版本,而是在Neo4j嵌入式版本的基础上进行一些封装性的开发。封装的重点,是解决Neo4j嵌入式版本EmbeddedGraphDatabase中不能同时创建多个实例指向同一个数据库的问题。如果开发人员使用Neo4j嵌入式版本作为数据库,要想实现多个程序共享一个数据库,这将是一个不可回避的问题。本手册给出的解决方案是“构建一个中间服务层,提供各种接口方法,指向同一个数据库实例;其他客户端程序通过中间服务层与Neo4j嵌入式数据库进行通信”。因为我们已经从Neo4j官方声明中得知:Neo4j嵌入式实例可以在多个线程**享。
系统框架如下图所示:
Neo4j Java 工具包是对Neo4j嵌入式版本Java API的二次封装,根据业务类型划分为Node(Relationship)、Index、Path和Cypher等四种工具集。
之所以称其为Server端,是因为其中包含了对RMI Server的管理。此管理工具的主要功能包括图数据库信息管理(包括新建、删除、统计图数据库等)、图数据库数据管理(包括Node数据管理、Relationship数据管理等)、数据导入导出(包括Neo4j与oracle、mysql和excel等之间的数据转换)、RMI Server监控管理等。
管理工具Server端只能部署在Neo4j数据库服务器上,并且只能部署一套程序,否则将违背Neo4j图数据库单例的原则。
RMI Server(服务),是在Neo4j Java 工具包的基础上,设计的一套接口服务,分为Server端和Client端。Server端用于接口方法的实现和监控管理,Client端用于接口方法的定义和分发(供其他外部系统使用)。总体设计思路,是将Neo4j中的关键对象(Node、Relationship、Path、Direction等)进行可序列化的封装,通过远程调用服务返回给客户端使用。
管理工具Client端,是基于RMI Client设计的Neo4j数据管理工具,主要功能包括图数据库信息查看功能、图数据库数据管理功能、数据导入导出功能等。管理工具Client端可以部署多套。
2 Neo4j Java 工具包
以上所有功能(工具包、RMI Service以及管理工具)都包含在两个Java项目中,项目结构如下图所示:
hnepri-neo4j-common为工具包项目,包括Neo4j Java 工具包、RMI Server端和管理工具Server端;hnepri-neo4j-client为客户端项目,包括RMI Client端和管理工具Client端。
下面主要介绍Neo4j Java 工具包的几个封装关键点,其中,下图为各个工具类之间的关联效果图。
2.1 Node操作工具类(GraphNodeUtil)
Node操作工具类的主要功能包括Node节点和Relationship关系的创建、编辑、删除、查询,以及Label和Property的管理等。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。相关接口方法截图如下所示:
2.2 Index操作工具类(GraphIndexUtil)
Index操作工具类的主要功能包括Node和Relationship相关索引信息的创建、编辑、删除、查询,以及基于索引查询Node节点和Relationship关系等。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。相关接口方法截图如下所示:
2.3 Path操作工具类(GraphPathUtil)
Path操作工具类的主要功能包括针对Path的检索操作,包括路径深度遍历、两点之间路径寻址等接口方法。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。相关接口方法截图如下所示:
2.4 Cypher操作工具类(GraphCypherUtil)
Cypher操作工具类是对Cypher查询语言的封装,主要包括针对Node、Relationship和Path的自定义查询操作。另外,也包括了多种方式的分页查询。对于其中的部分接口方法,根据实际情况和需要则进行了事务处理。
其中,最基本的接口方法是executeQuery方法,执行Cypher查询语句,将查询结果以Properties的形式存在在List中,然后再由其他接口方法显式地转换为Node、Relationship、Path或者其他基本类型使用。
1 /** 2 * 执行Cypher查询语句,将检索结果封装进Properties列表中。 3 * @param query cypher查询语句 4 * @param params cypher查询语句参数集合 5 * @return 6 */ 7 public List<Properties> executeQuery(String query, Map<String,Object> params) { 8 GraphTimerModel timer = GraphTimerModel.create(); 9 List<Properties> propertiesList = new ArrayList<Properties>();10 if(StringUtils.isBlank(query)) {11 return propertiesList;12 }13 ExecutionResult result = null;14 if(params == null || params.size() == 0) {15 result = this.getExecutionEngine().execute(query);16 } else {17 result = this.getExecutionEngine().execute(query, params);18 }19 LogInfoUtil.printLog(query);20 21 for (Map<String, Object> row : result ) {22 Properties properties = new Properties();23 for ( Entry<String, Object> column : row.entrySet()){24 properties.put(column.getKey(), column.getValue());25 }26 propertiesList.add(properties);27 }28 timer.initEndTime();29 timer.printTimeInfo();30 return propertiesList;31 }32 举例如下所示:33 String query = "START n=node(*) WHERE n.name=’tom’ RETURN n AS NODE_ENTRY";34 List<Properties> list = this.executeQuery(query);35 for(Properties properties : list) {36 nodeList.add((Node)properties.get("NODE_ENTRY"));37 }
相关接口方法截图如下所示:
2.5 动态生成RelationshipType(GraphRelTypeUtil)
动态生成RelationshipType是构建RMI服务必须首先要解决的一个关键点,因为RMI要求Server端与Client端之间的传输对象必须是可序列化的对象,而Neo4j API中的接口类和枚举是无法真正序列化的,这也是我们在RMI Service中对相关实体进行封装的根本原因。
所谓动态生成RelationshipType,就是可根据字符串类型的关系类型,生成符合Neo4j Java API要求的枚举类型RelationshipType。关键代码如下表所示:
1 package com.hnepri.neo4j.common.util; 2 3 import java.lang.reflect.AccessibleObject; 4 import java.lang.reflect.Array; 5 import java.lang.reflect.Field; 6 import java.lang.reflect.Modifier; 7 import java.util.ArrayList; 8 import java.util.Arrays; 9 import java.util.HashMap; 10 import java.util.Iterator; 11 import java.util.List; 12 import java.util.Map; 13 14 import org.apache.commons.lang3.StringUtils; 15 import org.neo4j.graphdb.GraphDatabaseService; 16 import org.neo4j.graphdb.RelationshipType; 17 import org.neo4j.graphdb.Transaction; 18 19 import sun.reflect.ConstructorAccessor; 20 import sun.reflect.FieldAccessor; 21 import sun.reflect.ReflectionFactory; 22 23 /** 24 * Description: 图数据库关系类型工具类。<br> 25 * 1、可根据关系类型名称字符串动态生成关系类型枚举。<br> 26 * 2、可管理动态生成的关系类型枚举列表。 27 * Copyright: Copyright (c) 2015<br> 28 * Company: 河南电力科学研究院智能电网所<br> 29 * @author shangbingbing 2015-11-01编写 30 * @version 1.0 31 */ 32 public class GraphRelTypeUtil { 33 34 /** 35 * 构造函数。<br> 36 * 初始化对应的图数据库服务对象实例。 37 * @param graphDBService 38 */ 39 public GraphRelTypeUtil(GraphDatabaseService graphDBService) { 40 this.graphDBService = graphDBService; 41 } 42 43 private GraphDatabaseService graphDBService = null; 44 /** 45 * 获取对应的图数据库服务对象实例。 46 * @return 47 */ 48 public GraphDatabaseService getGraphDBService() { 49 return this.graphDBService; 50 } 51 52 /** 53 * 构建事务。 54 * @return 55 */ 56 public Transaction createTransaction() { 57 return this.getGraphDBService().beginTx(); 58 } 59 60 private GraphIndexUtil indexManager = null; 61 /** 62 * 获取图数据库索引信息管理器。 63 * @return 64 */ 65 public GraphIndexUtil getIndexManager() { 66 if(this.indexManager == null) { 67 this.indexManager = new GraphIndexUtil(this.getGraphDBService()); 68 } 69 return this.indexManager; 70 } 71 72 private Map<String,RelationshipType> relationshipTypeList = null; 73 /** 74 * 获取已动态生成的关系枚举类型列表。 75 * @return 76 */ 77 @SuppressWarnings("deprecation") 78 public Map<String, RelationshipType> getRelationshipTypeList() { 79 if(this.relationshipTypeList == null) { 80 this.relationshipTypeList = new HashMap<String, RelationshipType>(); 81 82 Iterator<RelationshipType> iterator = this.getGraphDBService().getRelationshipTypes().iterator(); 83 while(iterator.hasNext()) { 84 RelationshipType relType = iterator.next(); 85 String relTypeName = relType.name(); 86 this.relationshipTypeList.put(relTypeName, relType); 87 } 88 } 89 return this.relationshipTypeList; 90 } 91 92 /** 93 * 根据关系类型名称动态生成图数据库关系枚举类型。 94 * @param relTypeName 95 * @return 96 */ 97 public RelationshipType create(String relTypeName) { 98 if(StringUtils.isBlank(relTypeName)) { 99 return null;100 }101 if(this.getRelationshipTypeList().containsKey(relTypeName) == false) {102 addEnum(relTypeName);103 RelationshipType relType = RelationshipTypeEnum.valueOf(relTypeName);104 this.getRelationshipTypeList().put(relTypeName, relType);105 return relType;106 } else {107 return this.getRelationshipTypeList().get(relTypeName);108 }109 }110 111 /**112 * 根据关系类型名称,获取对应的关系枚举类型。113 * @param relTypeName114 * @return115 */116 public RelationshipType get(String relTypeName) {117 if(StringUtils.isBlank(relTypeName)) {118 return null;119 }120 return this.create(relTypeName);121 }122 123 /**124 * 根据关系类型名称,删除对应的关系枚举类型。125 * @param relTypeName126 * @return127 */128 public void remove(String relTypeName) {129 if(this.getRelationshipTypeList().containsKey(relTypeName)) {130 this.getRelationshipTypeList().remove(relTypeName);131 }132 }133 134 /**135 * 根据关系类型名称列表,初始化关系类型枚举列表。136 * @param relTypeNameList137 */138 public void init(List<String> relTypeNameList) {139 if(relTypeNameList == null || relTypeNameList.size() == 0) {140 return;141 }142 for(String relTypeName : relTypeNameList) {143 create(relTypeName);144 }145 }146 147 private static ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();148 149 private static void setFailsafeFieldValue(Field field, Object target, Object value) throws NoSuchFieldException,IllegalAccessException {150 field.setAccessible(true);151 Field modifiersField = Field.class.getDeclaredField("modifiers");152 modifiersField.setAccessible(true);153 int modifiers = modifiersField.getInt(field);154 155 modifiers &= ~Modifier.FINAL;156 modifiersField.setInt(field, modifiers);157 158 FieldAccessor fa = reflectionFactory.newFieldAccessor(field, false);159 fa.set(target, value);160 }161 162 private static void blankField(Class<?> enumClass, String fieldName) throws NoSuchFieldException, IllegalAccessException {163 for (Field field : Class.class.getDeclaredFields()) {164 if (field.getName().contains(fieldName)) {165 AccessibleObject.setAccessible(new Field[] { field }, true);166 setFailsafeFieldValue(field, enumClass, null);167 break;168 }169 }170 }171 172 private static void cleanEnumCache(Class<?> enumClass) throws NoSuchFieldException, IllegalAccessException {173 blankField(enumClass, "enumConstantDirectory");174 blankField(enumClass, "enumConstants");175 }176 177 private static ConstructorAccessor getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes) throws NoSuchMethodException {178 Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];179 parameterTypes[0] = String.class;180 parameterTypes[1] = int.class;181 System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);182 return reflectionFactory.newConstructorAccessor(enumClass.getDeclaredConstructor(parameterTypes));183 }184 185 private static Object makeEnum(Class<?> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues) throws Exception {186 Object[] parms = new Object[additionalValues.length + 2];187 parms[0] = value;188 parms[1] = Integer.valueOf(ordinal);189 System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);190 return enumClass.cast(getConstructorAccessor(enumClass, additionalTypes).newInstance(parms));191 }192 193 @SuppressWarnings("unchecked")194 private static <T extends Enum<?>> void addEnum(String enumName) {195 if (!Enum.class.isAssignableFrom(RelationshipTypeEnum.class)) {196 throw new RuntimeException("class " + RelationshipTypeEnum.class + " is not an instance of Enum");197 }198 199 Field valuesField = null;200 Field[] fields = RelationshipTypeEnum.class.getDeclaredFields();201 for (Field field : fields) {202 if (field.getName().contains("$VALUES")) {203 valuesField = field;204 break;205 }206 }207 AccessibleObject.setAccessible(new Field[] { valuesField }, true);208 209 try {210 211 T[] previousValues = (T[]) valuesField.get(RelationshipTypeEnum.class);212 List<T> values = new ArrayList<T>(Arrays.asList(previousValues));213 214 T newValue = (T) makeEnum(RelationshipTypeEnum.class, enumName, values.size(), new Class<?>[] {}, new Object[] {});215 values.add(newValue);216 setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(RelationshipTypeEnum.class, 0)));217 cleanEnumCache(RelationshipTypeEnum.class);218 } catch (Exception e) {219 e.printStackTrace();220 throw new RuntimeException(e.getMessage(), e);221 }222 }223 }224 225 /**226 * Description: 图数据库关系类型枚举。227 * Copyright: Copyright (c) 2015<br>228 * Company: 河南电力科学研究院智能电网所<br>229 * @author shangbingbing 2015-11-01编写230 * @version 1.0231 */232 enum RelationshipTypeEnum implements RelationshipType {233 NONE234 }
2.6 图数据库操作模板工具类(GraphTemplateUtil)
图数据库操作模板工具类,主要负责对以上工具集的组织和调用管理,以保证开发人员在调用习惯上遵循Neo4j嵌入式图数据库单例服务的原则。关键代码如下表所示:
1 package com.hnepri.neo4j.common.util; 2 3 import java.io.File; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 import org.apache.commons.lang3.StringUtils; 8 import org.neo4j.graphdb.GraphDatabaseService; 9 import org.neo4j.graphdb.Transaction; 10 import org.neo4j.graphdb.factory.GraphDatabaseFactory; 11 import org.neo4j.io.fs.FileUtils; 12 13 import com.hnepri.neo4j.client.form.graph.bean.GraphConfigOption; 14 import com.hnepri.neo4j.form.graph.util.GraphManageUtil; 15 16 /** 17 * Description: Neo4j图数据库操作模板类。<br> 18 * Copyright: Copyright (c) 2015<br> 19 * Company: 河南电力科学研究院智能电网所<br> 20 * @author shangbingbing 2015-11-01 编写 21 * @version 1.0 22 */ 23 public class GraphTemplate { 24 25 private String graphDBPath = ""; 26 /** 27 * 获取图数据库路径。 28 * @return 29 */ 30 public String getGraphDBPath() { 31 return graphDBPath; 32 } 33 private GraphDatabaseService graphDBService = null; 34 /** 35 * 获取图数据库服务实例对象。 36 * @return 37 */ 38 public GraphDatabaseService getGraphDBService() { 39 if(StringUtils.isBlank(this.getGraphDBPath())) { 40 try { 41 throw new Exception("警告:没有配置图数据库路径信息!"); 42 } catch (Exception e) { 43 e.printStackTrace(); 44 } 45 } 46 if(this.graphDBService == null) { 47 this.graphDBService = new GraphDatabaseFactory().newEmbeddedDatabase(this.getGraphDBPath()); 48 registerShutdownHook(); 49 } 50 return this.graphDBService; 51 } 52 53 /** 54 * 清除图数据库数据文件信息。 55 */ 56 public void clearGraphDB() { 57 try { 58 FileUtils.deleteRecursively(new File(this.getGraphDBPath())); 59 if(graphTemplateList.containsKey(this.getGraphDBPath())) { 60 graphTemplateList.remove(this.getGraphDBPath()); 61 } 62 } catch (Exception ex) { 63 ex.printStackTrace(); 64 } 65 } 66 67 /** 68 * 注册图数据库关闭钩子。 69 */ 70 public void registerShutdownHook() { 71 Runtime.getRuntime().addShutdownHook(new Thread(){ 72 @Override 73 public void run(){ 74 getGraphDBService().shutdown(); 75 } 76 }); 77 } 78 79 /** 80 * 构造函数。初始化图数据库路径。 81 * @param graphDBPath 82 */ 83 private GraphTemplate(String graphDBPath) { 84 this.graphDBPath = graphDBPath; 85 } 86 87 private static Map<String, GraphTemplate> graphTemplateList = new HashMap<String, GraphTemplate>(); 88 /** 89 * 根据图数据库路径信息,获取对应的GraphTemplate对象实例。<br> 90 * 目的是采用GraphTemplate的单例模式。 91 * @param graphPath 92 * @return 93 */ 94 public static GraphTemplate getInstance(String graphPath) { 95 if(graphTemplateList.containsKey(graphPath) == false) { 96 GraphTemplate template = new GraphTemplate(graphPath); 97 graphTemplateList.put(graphPath, template); 98 } 99 return graphTemplateList.get(graphPath);100 }101 102 /**103 * 根据图数据库名称标示信息,获取对应的GraphTemplate对象实例。<br>104 * 目的是采用GraphTemplate的单例模式。105 * @param graphName106 * @return107 */108 public static GraphTemplate getInstanceByName(String graphName) {109 if(GraphManageUtil.getGraphConfigOptionList().containsKey(graphName) == false) {110 return null;111 }112 GraphConfigOption option = GraphManageUtil.getGraphConfigOptionList().get(graphName);113 return getInstance(option.getPath());114 }115 116 /**117 * 构建事务。118 * @return119 */120 public Transaction createTransaction() {121 return this.getGraphDBService().beginTx();122 }123 124 private GraphIndexUtil indexUtil = null;125 /**126 * 获取图数据库索引信息管理功能库。127 * @return128 */129 public GraphIndexUtil getIndexUtil() {130 if(this.indexUtil == null) {131 this.indexUtil = new GraphIndexUtil(this.getGraphDBService());132 }133 return this.indexUtil;134 }135 136 private GraphNodeUtil nodeUtil = null;137 /**138 * 获取图数据库节点信息管理功能库。139 * @return140 */141 public GraphNodeUtil getNodeUtil() {142 if(this.nodeUtil == null) {143 this.nodeUtil = new GraphNodeUtil(this.getGraphDBService());144 }145 return this.nodeUtil;146 }147 148 private GraphCypherUtil cypherUtil = null;149 /**150 * 获取图数据库Cypher查询语言功能库。151 * @return152 */153 public GraphCypherUtil getCypherUtil() {154 if(this.cypherUtil == null) {155 this.cypherUtil = new GraphCypherUtil(this.getGraphDBService());156 }157 return this.cypherUtil;158 }159 160 private GraphPathUtil pathUtil = null;161 /**162 * 获取图数据库Path信息功能库。163 * @return164 */165 public GraphPathUtil getPathUtil() {166 if(this.pathUtil == null) {167 this.pathUtil = new GraphPathUtil(this.getGraphDBService());168 }169 return this.pathUtil;170 }171 172 private GraphRelTypeUtil relTypeUtil = null;173 /**174 * 获取图数据库关系类型信息功能库。175 * @return176 */177 public GraphRelTypeUtil getRelTypeUtil() {178 if(this.relTypeUtil == null) {179 this.relTypeUtil = new GraphRelTypeUtil(this.getGraphDBService());180 }181 return this.relTypeUtil;182 }183 }
2.7 数据分页模型GraphPageModel
数据分页模型主要是基于Cypher查询语言中的SKIP和LIMIT而设计的针对Node和Relationship的分页处理模型。关键代码如下表所示:
1 package com.hnepri.neo4j.common.model; 2 3 import java.io.Serializable; 4 import java.text.DecimalFormat; 5 import java.util.ArrayList; 6 import java.util.List; 7 8 import org.neo4j.graphdb.Node; 9 import org.neo4j.graphdb.Relationship; 10 11 import com.hnepri.common.util.LogInfoUtil; 12 13 /** 14 * Description: 图数据库数据分页模型类。<br> 15 * 利用此类可分页管理Node数据和Relationship数据等。 16 * Copyright: Copyright (c) 2015<br> 17 * Company: 河南电力科学研究院智能电网所<br> 18 * @author shangbingbing 2015-11-01编写 19 * @version 1.0 20 */ 21 public class GraphPageModel implements Serializable { 22 private static final long serialVersionUID = 330410716100946538L; 23 private int pageSize = 10; 24 private int pageIndex = 1; 25 private int prevPageIndex = 1; 26 private int nextPageIndex = 1; 27 private int pageCount = 0; 28 private int pageFirstRowIndex = 1; 29 private boolean hasNextPage = true; 30 private int totalCount = 0; 31 private long startTime = System.currentTimeMillis(); 32 private long endTime = System.currentTimeMillis(); 33 private List<Node> nodeList = new ArrayList<Node>(); 34 private List<Relationship> relationshipList = new ArrayList<Relationship>(); 35 36 /** 37 * 分页对象构造函数 38 * @param pageSize 每页记录数 39 */ 40 public GraphPageModel(int pageSize) { 41 this.pageSize = pageSize; 42 } 43 44 /** 45 * 获取分页记录数量 46 * @return 47 */ 48 public int getPageSize() { 49 return pageSize; 50 } 51 /** 52 * 获取当前页序号 53 * @return 54 */ 55 public int getPageIndex() { 56 return pageIndex; 57 } 58 /** 59 * 设置当前页序号 60 * @param pageIndex 61 */ 62 public void setPageIndex(int pageIndex) { 63 if(pageIndex <= 0) { 64 pageIndex = 1; 65 } 66 this.pageIndex = pageIndex; 67 } 68 /** 69 * 获取分页总数 70 * @return 71 */ 72 public int getPageCount() { 73 if(this.getTotalCount() == 0) { 74 this.pageCount = 0; 75 } else { 76 int shang = this.getTotalCount() / this.getPageSize(); 77 int yu = this.getTotalCount() % this.getPageSize(); 78 if(yu > 0) { 79 shang += 1; 80 } 81 this.pageCount = shang; 82 } 83 return pageCount; 84 } 85 /** 86 * 获取每页的第一行序号 87 * @return 88 */ 89 public int getPageFirstRowIndex() { 90 this.pageFirstRowIndex = (this.pageIndex - 1) * this.getPageSize() + 1; 91 return pageFirstRowIndex; 92 } 93 /** 94 * 获取上一页序号 95 * @return 96 */ 97 public int getPrevPageIndex() { 98 if(this.pageIndex > 1) { 99 this.prevPageIndex = this.pageIndex - 1;100 } else {101 this.prevPageIndex = 1;102 }103 return prevPageIndex;104 }105 /**106 * 获取下一页序号107 * @return108 */109 public int getNextPageIndex() {110 if(this.pageIndex < this.pageCount) {111 this.nextPageIndex = this.pageIndex + 1; 112 } else {113 this.nextPageIndex = this.pageCount;114 }115 return nextPageIndex;116 }117 /**118 * 跳转到下一页119 */120 public void nextPage() {121 if(this.totalCount == 0 || this.getPageCount() == 0) {122 this.pageIndex = 1;123 } else {124 if(this.pageIndex < this.pageCount) {125 this.pageIndex = this.pageIndex + 1; 126 } else {127 this.pageIndex = this.pageCount;128 }129 }130 }131 /**132 * 跳转到上一页133 */134 public void prevPage() {135 if(this.pageIndex > 1) {136 this.pageIndex = this.pageIndex - 1;137 } else {138 this.pageIndex = 1;139 }140 }141 /**142 * 获取是否有下一页143 * @return144 */145 public boolean isHasNextPage() {146 if(this.pageIndex < this.getPageCount()) {147 this.hasNextPage = true;148 } else {149 this.hasNextPage = false;150 }151 return hasNextPage;152 }153 /**154 * 获取总记录数 155 */156 public int getTotalCount() {157 return totalCount;158 }159 /**160 * 获取总记录数 161 * @param totalCount162 */163 public void setTotalCount(int totalCount) {164 this.totalCount = totalCount;165 }166 /**167 * 初始化起始时间(毫秒)168 */169 public void initStartTime() {170 this.startTime = System.currentTimeMillis();171 }172 /**173 * 初始化截止时间(毫秒)174 */175 public void initEndTime() {176 this.endTime = System.currentTimeMillis();177 }178 /**179 * 获取毫秒格式的耗时信息180 * @return181 */182 public String getTimeIntervalByMilli() {183 return String.valueOf(this.endTime - this.startTime) + "毫秒";184 }185 /**186 * 获取秒格式的耗时信息187 * @return188 */189 public String getTimeIntervalBySecond() {190 double interval = (this.endTime - this.startTime)/1000.0;191 DecimalFormat df = new DecimalFormat("#.##");192 return df.format(interval) + "秒";193 }194 /**195 * 打印时间信息196 */197 public void printTimeInfo() {198 LogInfoUtil.printLog("起始时间:" + this.startTime);199 LogInfoUtil.printLog("截止时间:" + this.endTime);200 LogInfoUtil.printLog("耗费时间:" + this.getTimeIntervalBySecond());201 }202 /**203 * 获取Node检索结果列表204 * @return205 */206 public List<Node> getNodeList() {207 return nodeList;208 }209 /**210 * 获取Relationship检索结果列表211 * @return212 */213 public List<Relationship> getRelationshipList() {214 return relationshipList;215 }216 }
【未完待续】
下一篇 Neo4j图数据库应用开发之二:RMI Service开发
原标题:Neo4j图数据库管理系统开发笔记之一:Neo4j Java 工具包
关键词:JAVA