springboot + neo4j 功能使用

集成

添加依赖

XML 复制代码
        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-neo4j</artifactId>
		</dependency>
XML 复制代码
spring:
  # neo4j 图数据库
  neo4j:
    uri: bolt://localhost:7687
    authentication:
      username: neo4j
      password: admin
  # 指定数据库
  data:
    neo4j:
      database: neo4j

如果和数据库一起集成,需要配置多数据源事务,不然事务会失效

java 复制代码
import org.neo4j.driver.Driver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * 配置neo4j 和 mysql 事务
 * 1、@EnableNeo4jRepositories 用于扫描指定包下的repository
 * 2、@EntityScan 用于扫描 neo4j实体类
 */
@Configuration
@EnableTransactionManagement
@EnableNeo4jRepositories(basePackages = {"com.graph.repository"})
@EntityScan(basePackages = {"com.graph.model.neo4j"})
public class Neo4jConfig {

	/**
	 * 此处为了修改默认事务,必须改。
	 * 加载了Neo4J依赖库之后,transactionManager变成Neo4jTransactionManager
	 *
	 * @param dataSource 数据源
	 * @return
	 */
	@Bean("transactionManager")
	@Primary
	public DataSourceTransactionManager transactionManager(DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource);
	}

	/**
	 * Neo4J的事务管理
	 *
	 * @param driver
	 * @return
	 */
	@Bean("neo4jTransactionManager")
	public Neo4jTransactionManager neo4jTransactionManager(Driver driver) {
		return new Neo4jTransactionManager(driver);
	}

	/**
	 * 需要使用多种事务时
	 *
	 * @param neo4jTransactionManager
	 * @param mysqlTransactionManager
	 * @return
	 */
	@Autowired
	@Bean(name = "multiTransactionManager")
	public PlatformTransactionManager multiTransactionManager(
			Neo4jTransactionManager neo4jTransactionManager,
			DataSourceTransactionManager mysqlTransactionManager) {
		return new ChainedTransactionManager(
				neo4jTransactionManager, mysqlTransactionManager);
	}
}

1.使用Neo4jRepository 进行查询,可以使用jpa进行查询

java 复制代码
import lombok.Data;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;

/**
 * 文献
 *
 * @author kou
 */
@Data
@Node(labels = "文献")
public class Literature {

	@Id
	@GeneratedValue
	private Long id;

	@Property(name = "name")
	private String name;


	/**
	 * 文件路径
	 */
	@Property(name = "url")
	private String url;

}
java 复制代码
import com.haiwanyoutian.hai.graph.model.neo4j.Literature;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 文献 持久层
 *
 * @author kou
 */
@Repository
public interface LiteratureRepository extends Neo4jRepository<Literature, Long> {

	/**
	 * 按名称查询
	 *
	 * @param name 名称
	 * @return 结果
	 */
//	@Query("MATCH(p:`文献`{name:$name}) return p")
	List<Literature> findByName(@Param("name") String name);

	/**
	 * 按名称模糊查询
	 *
	 * @param name 名称
	 * @return 结果
	 */
	List<Literature> findByNameLike(@Param("name") String name);

	/**
	 * 分页查询
	 *
	 * @param name     名称
	 * @param pageable 分页条件
	 * @return 结果
	 */
	Page<Literature> findByNameLike(@Param("name") String name, Pageable pageable);

	@Query(value = "match (n:`文献`) " +
			" WHERE (n.name CONTAINS $keyword" +
			" or n.full_paper_outline_en CONTAINS $keyword" +
			" or n.full_paper_outline_zh CONTAINS $keyword" +
			" or n.full_paper_summary_en CONTAINS $keyword" +
			" or n.full_paper_summary_zh CONTAINS $keyword) " +
			" return n" +
			" SKIP $skip LIMIT $limit ",
			countQuery = "match (n:`文献`) " +
					" WHERE (n.name CONTAINS $keyword" +
					" or n.full_paper_outline_en CONTAINS $keyword" +
					" or n.full_paper_outline_zh CONTAINS $keyword" +
					" or n.full_paper_summary_en CONTAINS $keyword" +
					" or n.full_paper_summary_zh CONTAINS $keyword) " +
					"return count(*)"
	)
	Page<Literature> findByKeyword(@Param("keyword") String keyword, @Param("pageable") Pageable pageable);

	/**
	 * 查询关系
	 *
	 * @param name 名称
	 * @return 结果
	 */
	@Query("MATCH(n:`文献`{name:$name}) return (n)-[]-()")
	Literature queryLiteratureRelation(@Param("name") String name);


	/**
	 * 查询关键字期刊
	 *
	 * @param keyword 关键字
	 * @param limit   数量
	 * @return 结果
	 */
	@Deprecated
	@Query("match(n) where labels(n) in [['文献'],['作者']]  " +
			"with n, [x in keys(n) WHERE n[x]=~'.*'+$keyword+'.*'] as dm " +
			"where size(dm) > 0 " +
			"with n " +
			"LIMIT $limit " +
			"match p=(n)-[]-(k) " +
			"return p ")
	List<Literature> queryLiteratureByKeyword(@Param("keyword") String keyword, @Param("limit") Integer limit);

}
  1. 使用cypher进行查询
java 复制代码
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 知识接口实现类
 *
 * @author kou
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class LiteratureServiceImpl implements ILiteratureService {

	private final LiteratureRepository literatureRepository;

	private final INeo4jService neo4jService;

	/**
	 * 文献搜索
	 *
	 * @param keyword  关键字
	 * @param pageable 分页查询
	 * @return 结果
	 */
	@Override
	public Page<Literature> search(String keyword, Pageable pageable) {

		if (StringUtils.isNotBlank(keyword)) {
			// return literatureRepository.findByNameLike(keyword, pageable);
			return literatureRepository.findByKeyword(keyword, pageable);
		}
		return literatureRepository.findAll(pageable);
	}

	/**
	 * 文献图库搜索
	 *
	 * @param keyword 关键字
	 * @param limit   数量
	 * @return 结果
	 */
	@Override
	public Object graphSearch(String keyword, Integer limit) {

		StringBuffer sql = new StringBuffer();
		if (StringUtils.isNotBlank(keyword)) {
			sql.append("match(n) where labels(n) in [['文献'],['作者']] ");
			sql.append("with n, [x in keys(n) WHERE n[x]=~'.*").append(keyword).append(".*'] as dm ");
			sql.append("where size(dm) > 0 ");
		} else {
			sql.append("match (n:`文献`) ");
		}
		sql.append("with n ");
		sql.append("LIMIT ").append(limit).append(" ");
		sql.append("match p=(n)-[]-(k) ");
		sql.append("return p ");

		return neo4jService.run(sql.toString());
	}

	/**
	 * 通过文献名查询文献关系
	 *
	 * @param name 文献名
	 * @return 文献关系
	 */
	@Override
	public Object queryGraphByName(String name) {

		StringBuffer sql = new StringBuffer();
		sql.append("match (n:`文献`) ");
		if (StringUtils.isNotBlank(name)) {
			sql.append("where n.name='").append(name).append("' ");
			sql.append("return (n)-[]-() ");
		} else {
			sql.append("return (n)-[]-() ");
			sql.append("limit 200 ");
		}
		return neo4jService.run(sql.toString());
	}

	/**
	 * 通过文献id查询文献知识点关系
	 *
	 * @param id 文献id
	 * @return 结果
	 */
	@Override
	public NodeRelation queryKnowledgePointRelation(Long id) {
		StringBuffer sql = new StringBuffer();
		sql.append("match (p:`文献`)-[rel]-(k:`知识点`) ");
		sql.append(" where id(p) = ").append(id);
		sql.append(" return p, k, rel");

		List<Neo4jData> datas = neo4jService.run(sql.toString());
		return Neo4jNodeUtil.convert(datas);
	}

	/**
	 * 通过节点id查询相关的知识点/文献节点数据
	 *
	 * @param id 节点id
	 * @return 结果
	 */
	@Override
	public NodeRelation queryLiteratureOrKnowledgePointRelation(Long id) {

		StringBuffer sql = new StringBuffer();
		sql.append("match (p)-[rel]-(k) ");
		sql.append(" where id(p) = ").append(id).append(" and labels(k) in [['文献'],['知识点']] ");
		sql.append(" return p, k, rel");

		List<Neo4jData> datas = neo4jService.run(sql.toString());
		return Neo4jNodeUtil.convert(datas);
	}

	/**
	 * 通过文献id查询知识词条
	 *
	 * @param id 节点id
	 * @return 结果
	 */
	@Override
	public List<Neo4jNode> queryKnowledgeEntry(Long id) {
		StringBuffer sql = new StringBuffer();
		sql.append("match (p:`文献`)-[:`知识词条`]-(k) ");
		sql.append(" where id(p) = ").append(id);
		sql.append(" return k");

		List<Neo4jData> datas = neo4jService.run(sql.toString());
		return Neo4jNodeUtil.getNodes(datas);
	}

}
java 复制代码
import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.neo4j.driver.*;
import org.neo4j.driver.internal.InternalNode;
import org.neo4j.driver.internal.InternalPath;
import org.neo4j.driver.internal.InternalRelationship;
import org.neo4j.driver.types.Node;
import org.neo4j.driver.types.Path;
import org.neo4j.driver.types.Relationship;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * neo4j 业务接口
 *
 * @author kou
 */
@AllArgsConstructor
@Service
public class Neo4jServiceImpl implements INeo4jService {

	private final Driver driver;

	@Override
	public List<Neo4jData> run(String cypherSql) {

		try (Session session = driver.session()) {
			Result result = session.run(cypherSql);
			return this.parseResult(result);
		}
	}

	/**
	 * 开启事务执行脚本
	 *
	 * @param cypherSql 脚本
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> runTx(String cypherSql) {
		try (Session session = driver.session()) {
			// 开启事务
			try (Transaction tx = session.beginTransaction()) {
				Result result = tx.run(cypherSql);
				List<Neo4jData> dataList = this.parseResult(result);
				// 提交事务
				tx.commit();
				return dataList;
			}
		}
	}

	/**
	 * 开启事务执行脚本
	 *
	 * @param cypherSql  脚本
	 * @param parameters 参数
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> runTx(String cypherSql, Map<String, Object> parameters) {
		try (Session session = driver.session()) {
			// 开启事务
			try (Transaction tx = session.beginTransaction()) {
				Result result = tx.run(cypherSql, parameters);
				List<Neo4jData> dataList = this.parseResult(result);
				// 提交事务
				tx.commit();
				return dataList;
			}
		}
	}

	/**
	 * 开启事务执行脚本
	 *
	 * @param tx        事务
	 * @param cypherSql 脚本
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> runTx(Transaction tx, String cypherSql) {
		// 开启事务
		Result result = tx.run(cypherSql);
		return this.parseResult(result);
	}

	/**
	 * 开启事务执行脚本
	 *
	 * @param tx         事务
	 * @param cypherSql  脚本
	 * @param parameters 参数
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> runTx(Transaction tx, String cypherSql, Map<String, Object> parameters) {
		// 开启事务
		Result result = tx.run(cypherSql, parameters);
		return this.parseResult(result);
	}

	/**
	 * 批量创建节点
	 *
	 * @param label        节点类型
	 * @param nodeDataList 参数,{"name": "", "properties": Map<String, Object>}, label:标签类型,name:节点名称,properties: 节点数据
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> batchCreateNode(String label, List<Map<String, Object>> nodeDataList) {

		// 数据不为空进行入图库
		Map<String, Object> parameters = new HashMap<>(1);
		parameters.put("props", nodeDataList);
		// sql格式:UNWIND $props AS p create/merge(n:Person{name: p.name} set n += p.properties)
		String cypherSql = "UNWIND $props AS p merge(n:" + label + "{name: p.name}) set n += p.properties";

		return this.runTx(cypherSql, parameters);
	}

	/**
	 * 批量创建节点
	 *
	 * @param tx           事务
	 * @param label        节点类型
	 * @param nodeDataList 参数,{"name": "", "properties": Map<String, Object>}, label:标签类型,name:节点名称,properties: 节点数据
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> batchCreateNode(Transaction tx, String label, List<Map<String, Object>> nodeDataList) {

		// 数据不为空进行入图库
		Map<String, Object> parameters = new HashMap<>(1);
		parameters.put("props", nodeDataList);
		// sql格式:UNWIND $props AS p create/merge(n:Person{name: p.name} set n += p.properties)
		String cypherSql = "UNWIND $props AS p merge(n:" + label + "{name: p.name}) set n += p.properties";

		return this.runTx(tx, cypherSql, parameters);
	}

	/**
	 * 批量创建节点
	 *
	 * @param tx           事务
	 * @param labels       节点类型
	 * @param nodeDataList 参数,{"name": "", "properties": Map<String, Object>}, label:标签类型,name:节点名称,properties: 节点数据
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> batchCreateNode(Transaction tx, List<String> labels, List<Map<String, Object>> nodeDataList) {

		// 数据不为空进行入图库
		Map<String, Object> parameters = new HashMap<>(1);
		parameters.put("props", nodeDataList);
		// sql格式:UNWIND $props AS p create/merge(n:Person:Country{name: p.name} set n += p.properties)
		StringBuffer multipleLabels = new StringBuffer();
		for (int i = 0; i < labels.size(); i++) {
			if (StringUtils.isNotBlank(labels.get(i))) {
				multipleLabels.append(":").append(labels.get(i));
			}
		}
		String cypherSql = "UNWIND $props AS p merge(n" + multipleLabels + "{name: p.name}) set n += p.properties";

		return this.runTx(tx, cypherSql, parameters);
	}

	/**
	 * 批量创建关系
	 *
	 * @param headLabel    头节点类型
	 * @param tailLabel    尾节点类型
	 * @param relation     关系
	 * @param relationList 参数,{"head": "", tail:"", "properties": Map<String, Object>}, head:头节点名称,tail:尾节点名称,properties: 关系数据,必须有,可以写{}
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> batchCreateRelationship(String headLabel, String tailLabel, String relation, List<Map<String, Object>> relationList) {

		Map<String, Object> parameters = new HashMap<>(1);
		parameters.put("props", relationList);
		// sql格式:UNWIND $props AS p match (n:文献{name: p.head}), (m:作者{name: p.tail}) create (n)-[r:连接]->(m)  SET r += p.properties
		String relationSql = "UNWIND $props AS p match (n: " + headLabel + "{name: p.head}), (m: " + tailLabel + "{name: p.tail}) MERGE (n)-[r:" + relation + "]->(m) SET r += p.properties";

		return this.runTx(relationSql, parameters);
	}

	/**
	 * 批量创建关系
	 *
	 * @param tx           事务
	 * @param headLabel    头节点类型
	 * @param tailLabel    尾节点类型
	 * @param relation     关系
	 * @param relationList 参数,{"head": "", tail:"", "properties": Map<String, Object>}, head:头节点名称,tail:尾节点名称,properties: 关系数据,必须有,可以写{}
	 * @return 结果
	 */
	@Override
	public List<Neo4jData> batchCreateRelationship(Transaction tx, String headLabel, String tailLabel, String relation, List<Map<String, Object>> relationList) {

		Map<String, Object> parameters = new HashMap<>(1);
		parameters.put("props", relationList);
		// sql格式:UNWIND $props AS p match (n:文献{name: p.head}), (m:作者{name: p.tail}) create (n)-[r:连接]->(m)  SET r += p.properties
		String relationSql = "UNWIND $props AS p match (n: " + headLabel + "{name: p.head}), (m: " + tailLabel + "{name: p.tail}) MERGE (n)-[r:" + relation + "]->(m) SET r += p.properties";

		return this.runTx(tx, relationSql, parameters);
	}

	/**
	 * 批量创建节点及关系
	 *
	 * @param nodeRelationDataDto 节点关系数据
	 * @return 结果
	 */
	@Override
	public boolean createNodeAndRelation(NodeRelationDataDto nodeRelationDataDto) {

		try (Session session = driver.session()) {
			// 开启事务
			try (Transaction tx = session.beginTransaction()) {
				// 创建节点
				if (CollectionUtil.isNotEmpty(nodeRelationDataDto.getNodes())) {
					nodeRelationDataDto.getNodes().stream().forEach(d -> {
						this.batchCreateNode(tx, d.getLabels(), d.getProperties());
					});
				}

				// 创建关系
				if (CollectionUtil.isNotEmpty(nodeRelationDataDto.getRelations())) {
					nodeRelationDataDto.getRelations().stream().forEach(r -> {
						this.batchCreateRelationship(tx, r.getHeadLabel(), r.getTailLabel(), r.getRelation(), r.getProperties());
					});
				}
				// 提交事务
				tx.commit();
				return true;
			}
		}
	}

	/**
	 * 解析结果数据
	 *
	 * @param result 执行结果
	 * @return 解析结果
	 */
	private List<Neo4jData> parseResult(Result result) {

		List<Neo4jData> dataList = new ArrayList<>();
		while (result.hasNext()) {
			dataList.add(parseRecord(result.next()));
		}
		return dataList;
	}

	/**
	 * 解析结果数据
	 *
	 * @param record 执行结果
	 * @return 解析结果
	 */
	private Neo4jData parseRecord(Record record) {

		Neo4jData data = new Neo4jData();
		data.setKeys(record.keys());
		Map<String, Integer> keysIndex = new HashMap<>(record.keys().size());
		data.setLength(record.values().size());
		// 字段信息
		List fields = new ArrayList(data.getLength());

		for (Map.Entry<String, Object> item : record.asMap().entrySet()) {
			keysIndex.put(item.getKey(), record.index(item.getKey()));
			if (item.getValue() instanceof InternalNode) {
				// 节点
				fields.add(this.parseNode((InternalNode) item.getValue()));
			} else if (item.getValue() instanceof InternalRelationship) {
				// 关系, 如: MATCH (n)-[rel:`作者`]->(r) return rel
				fields.add(this.parseRelationship((InternalRelationship) item.getValue()));
			} else if (item.getValue() instanceof InternalPath) {
				// 路径, 如: MATCH p=()-[r:`作者`]->() RETURN p LIMIT 25
				InternalPath internalPath = (InternalPath) item.getValue();
				Iterator<Node> iterNode = internalPath.nodes().iterator();
				int count = 0;
				while (iterNode.hasNext()) {
					iterNode.next();
					count++;
				}
				// 当前节点数据
				Map<String, Object> path = new HashMap<>();
				// 获取节点
				List<Neo4jNode> nodeList = new ArrayList<>(count);
				Iterator<Node> nodes = internalPath.nodes().iterator();
				while (nodes.hasNext()) {
					nodeList.add(this.parseNode(nodes.next()));
				}
				if (CollectionUtil.isNotEmpty(nodeList)) {
					path.put("start", nodeList.get(0));
					if (nodeList.size() > 1) {
						path.put("end", nodeList.get(1));
					}
				}

				// 获取segment
				List<Neo4jSegment> segmentsList = new ArrayList<>(count);
				Iterator<Path.Segment> segments = internalPath.iterator();
				while (segments.hasNext()) {
					segmentsList.add(this.parseSegment(segments.next()));
				}
				path.put("segments", segmentsList);
				fields.add(path);
			} else if (item.getValue() instanceof List) {
				if (CollectionUtil.isNotEmpty((Collection<?>) item.getValue())) {
					if (((List<?>) item.getValue()).get(0) instanceof InternalNode) {
						// 节点列表
						fields.add(this.parseNodeList((List<InternalNode>) item.getValue()));
					} else if (((List<?>) item.getValue()).get(0) instanceof InternalRelationship) {
						// 关系列表
						fields.add(this.parseRelationship((List<InternalRelationship>) item.getValue()));
					} else if (((List<?>) item.getValue()).get(0) instanceof InternalPath) {
						// 路径
						List<InternalPath> internalPathList = ((List<InternalPath>) item.getValue());
						Iterator<InternalPath> ipNode = internalPathList.iterator();
						InternalPath ipath = null;
						while (ipNode.hasNext()) {
							ipath = ipNode.next();
							Iterator<Node> iterNode = ipath.nodes().iterator();
							int count = 0;
							while (iterNode.hasNext()) {
								iterNode.next();
								count++;
							}
							// 当前节点数据
							Map<String, Object> path = new HashMap<>();
							// 获取节点
							List<Neo4jNode> nodeList = new ArrayList<>(count);
							Iterator<Node> nodes = ipath.nodes().iterator();
							while (nodes.hasNext()) {
								nodeList.add(this.parseNode(nodes.next()));
							}
							if (CollectionUtil.isNotEmpty(nodeList)) {
								path.put("start", nodeList.get(0));
								if (nodeList.size() > 1) {
									path.put("end", nodeList.get(1));
								}
							}

							// 获取segment
							List<Neo4jSegment> segmentsList = new ArrayList<>(count);
							Iterator<Path.Segment> segments = ipath.iterator();
							while (segments.hasNext()) {
								segmentsList.add(this.parseSegment(segments.next()));
							}
							path.put("segments", segmentsList);
							fields.add(path);
						}
					}
				}
			}
		}

		data.setFieldLookup(keysIndex);
		data.setFields(fields);
		return data;
	}

	/**
	 * 解析节点
	 * 不解析直接返回拿不到数据
	 *
	 * @param nodeList 节点
	 * @return 节点
	 */
	private List<Neo4jNode> parseNodeList(List<InternalNode> nodeList) {

		List<Neo4jNode> dataList = new ArrayList<>(nodeList.size());
		nodeList.stream().forEach(n -> {
			dataList.add(this.parseNode(n));
		});
		return dataList;
	}

	/**
	 * 解析节点
	 * 不解析直接返回拿不到数据
	 *
	 * @param node 节点
	 * @return 节点
	 */
	private Neo4jNode parseNode(Node node) {
		Neo4jNode neo4jNode = new Neo4jNode();
		neo4jNode.setElementId(node.id());
		neo4jNode.setLabels(CollectionUtil.toCollection(node.labels()));
		neo4jNode.setProperties(node.asMap());
		neo4jNode.setIdentity(new Neo4jIdentity(node.id(), 0L));
		return neo4jNode;
	}

	/**
	 * 解析节点
	 * 不解析直接返回拿不到数据
	 *
	 * @param ir 节点
	 * @return 节点
	 */
	private Neo4jNode parseNode(InternalNode ir) {
		Neo4jNode node = new Neo4jNode();
		node.setElementId(ir.id());
		node.setLabels(ir.labels());
		node.setProperties(ir.asMap());
		node.setIdentity(new Neo4jIdentity(ir.id(), 0L));
		return node;
	}

	/**
	 * 解析关系
	 * 不解析直接返回拿不到数据
	 *
	 * @param relList 关系列表
	 * @return 关系
	 */
	private List<Neo4jRelation> parseRelationship(List<InternalRelationship> relList) {

		List<Neo4jRelation> dataList = new ArrayList<>(relList.size());
		relList.stream().forEach(n -> {
			dataList.add(this.parseRelationship(n));
		});
		return dataList;
	}

	/**
	 * 解析关系
	 * 不解析直接返回拿不到数据
	 *
	 * @param rel 关系
	 * @return 关系
	 */
	private Neo4jRelation parseRelationship(InternalRelationship rel) {
		Neo4jRelation relation = new Neo4jRelation();
		relation.setElementId(rel.id());
		relation.setStartNodeElementId(rel.startNodeId());
		relation.setEndNodeElementId(rel.endNodeId());
		relation.setType(rel.type());
		relation.setProperties(rel.asMap());
		relation.setIdentity(new Neo4jIdentity(rel.id(), 0L));
		relation.setStart(new Neo4jIdentity(rel.startNodeId(), 0L));
		relation.setEnd(new Neo4jIdentity(rel.endNodeId(), 0L));
		return relation;
	}

	/**
	 * 解析关系
	 * 不解析直接返回拿不到数据
	 *
	 * @param rel 关系
	 * @return 关系
	 */
	private Neo4jRelationship parseRelationship(Relationship rel) {

		Neo4jRelationship relation = new Neo4jRelationship();
		relation.setElementId(rel.id());
		relation.setStartNodeElementId(rel.startNodeId());
		relation.setEndNodeElementId(rel.endNodeId());
		relation.setIdentity(new Neo4jIdentity(rel.id(), 0L));
		relation.setStart(new Neo4jIdentity(rel.startNodeId(), 0L));
		relation.setEnd(new Neo4jIdentity(rel.endNodeId(), 0L));
		relation.setType(rel.type());
		relation.setProperties(rel.asMap());
		return relation;
	}

	/**
	 * 解析关系
	 * 不解析直接返回拿不到数据
	 *
	 * @param segment
	 * @return 关系
	 */
	private Neo4jSegment parseSegment(Path.Segment segment) {
		Neo4jSegment seg = new Neo4jSegment();
		seg.setStart(this.parseNode(segment.start()));
		seg.setEnd(this.parseNode(segment.end()));
		seg.setRelationship(this.parseRelationship(segment.relationship()));
		return seg;
	}
}
java 复制代码
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;
import java.util.Map;

/**
 * neo4j执行cypher语句返回结果
 *
 * @author kou
 */
@Data
public class Neo4jData {

	/**
	 * 查询字段
	 */
	private List<String> keys;

	/**
	 * 长度,fields个数
	 */
	private Integer length;

	/**
	 * 数据字段
	 */
	@JsonProperty(value = "_fields")
	private List fields;

	/**
	 * keys索引,字段keys在fields的位置
	 */
	@JsonProperty(value = "_fieldLookup")
	private Map<String, Integer> fieldLookup;

}
java 复制代码
import lombok.Data;

import java.util.Collection;
import java.util.Map;

/**
 * 结点信息
 *
 * @author kou
 */
@Data
public class Neo4jNode {

	/**
	 * 结点id
	 */
	private Long elementId;

	private Neo4jIdentity identity;

	/**
	 * label名称
	 */
	private Collection<String> labels;

	/**
	 * 属性
	 */
	private Map<String, Object> properties;

}
java 复制代码
import lombok.Data;

import java.util.Map;

/**
 * neo4j关系
 *
 * @author kou
 */
@Data
public class Neo4jRelation {

	/**
	 * 关系id
	 */
	private Long elementId;

	/**
	 * 关系类型
	 */
	private String type;

	/**
	 * id信息
	 */
	private Neo4jIdentity identity;

	/**
	 * 头节点信息
	 */
	private Neo4jIdentity start;

	/**
	 * 尾节点信息
	 */
	private Neo4jIdentity end;

	/**
	 * 头节点id
	 */
	private Long startNodeElementId;

	/**
	 * 尾节点id
	 */
	private Long endNodeElementId;

	/**
	 * 属性
	 */
	private Map<String, Object> properties;

}
java 复制代码
import cn.hutool.core.collection.CollectionUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * cypher脚本结果工具类
 *
 * @author kou
 */
public class Neo4jNodeUtil {

	/**
	 * 将cypher脚本查询出的结果转换为节点关系
	 *
	 * @param datas cypher脚本查询出的结果
	 * @return 节点关系
	 */
	public static NodeRelation convert(List<Neo4jData> datas) {

		if (CollectionUtil.isEmpty(datas)) {
			return null;
		}

		int length = datas.size() * 3;
		List<Neo4jNode> nodes = new ArrayList<>(length);
		List<Neo4jRelation> relations = new ArrayList<>(length);

		Map<Long, Long> nodeIds = new HashMap<>(length);
		Map<Long, Long> relationIds = new HashMap<>(length);

		datas.stream().forEach(d -> {
			d.getFields().stream().forEach(f -> {
				if (f instanceof Neo4jNode) {
					Neo4jNode node = (Neo4jNode) f;
					if (null == nodeIds.get(node.getElementId())) {
						nodeIds.put(node.getElementId(), node.getElementId());
						Map<String, Object> properties = node.getProperties();
						if (CollectionUtil.isNotEmpty(properties) && properties.containsKey("embedding")) {
							properties = ImmutableMap.copyOf(Maps.filterKeys(properties, key -> !key.equals("embedding")));
							node.setProperties(properties);
						}
						nodes.add(node);
					}
				} else if (f instanceof Neo4jRelation) {
					Neo4jRelation rel = (Neo4jRelation) f;
					if (null == relationIds.get(rel.getElementId())) {
						relationIds.put(rel.getElementId(), rel.getElementId());
						relations.add(rel);
					}
				}
			});
		});

		NodeRelation nodeRelation = new NodeRelation();
		nodeRelation.setNodes(nodes);
		nodeRelation.setRelations(relations);
		return nodeRelation;
	}

	/**
	 * 获取节点
	 *
	 * @param datas cypher脚本查询出的结果
	 * @return 节点关系
	 */
	public static List<Neo4jNode> getNodes(List<Neo4jData> datas) {

		if (CollectionUtil.isEmpty(datas)) {
			return null;
		}

		List<Neo4jNode> nodes = new ArrayList<>(datas.size());
		Map<Long, Long> nodeIds = new HashMap<>(datas.size());

		datas.stream().forEach(d -> {
			d.getFields().stream().forEach(f -> {
				if (f instanceof Neo4jNode) {
					Neo4jNode node = (Neo4jNode) f;
					if (null == nodeIds.get(node.getElementId())) {
						nodeIds.put(node.getElementId(), node.getElementId());
						Map<String, Object> properties = node.getProperties();
						if (CollectionUtil.isNotEmpty(properties) && properties.containsKey("embedding")) {
							properties = ImmutableMap.copyOf(Maps.filterKeys(properties, key -> !key.equals("embedding")));
							node.setProperties(properties);
						}
						nodes.add(node);
					}
				}
			});
		});

		return nodes;
	}

}

使用jpa进行查询

java 复制代码
    /**
	 * 文献搜索
	 *
	 * @param keyword  关键字
	 * @param pageable 分页查询
	 * @return 结果
	 */
	@Override
	public Page<Literature> search(String keyword, Pageable pageable) {
            ExampleMatcher matcher = ExampleMatcher.matching()
					.withMatcher("name", match -> match.contains())
					.withMatcher("fullPaperOutlineEn", match -> match.contains())
					.withMatcher("fullPaperOutlineZh", match -> match.contains())
					.withMatcher("fullPaperSummaryEn", match -> match.contains())
					.withMatcher("fullPaperSummaryZh", match -> match.contains());
			Literature literature = new Literature();
			literature.setName(keyword);
			literature.setFullPaperOutlineEn(keyword);
			literature.setFullPaperOutlineZh(keyword);
			literature.setFullPaperSummaryEn(keyword);
			literature.setFullPaperSummaryZh(keyword);

			// return literatureRepository.findByNameLike(keyword, pageable);
			return literatureRepository.findAll(Example.of(literature, matcher), pageable);
    }
相关推荐
集成显卡3 小时前
windows 下使用 bat 批处理运行 Chrome 无头模式刷一波访问量
windows·程序员
后端小张6 小时前
基于飞算AI的图书管理系统设计与实现
spring boot
考虑考虑1 天前
Jpa使用union all
java·spring boot·后端
阿杆1 天前
同事嫌参数校验太丑,我直接掏出了更优雅的 SpEL Validator
java·spring boot·后端
昵称为空C2 天前
SpringBoot3 http接口调用新方式RestClient + @HttpExchange像使用Feign一样调用
spring boot·后端
麦兜*2 天前
MongoDB Atlas 云数据库实战:从零搭建全球多节点集群
java·数据库·spring boot·mongodb·spring·spring cloud
麦兜*2 天前
MongoDB 在物联网(IoT)中的应用:海量时序数据处理方案
java·数据库·spring boot·物联网·mongodb·spring
汤姆yu2 天前
基于springboot的毕业旅游一站式定制系统
spring boot·后端·旅游
计算机毕业设计木哥2 天前
计算机毕设选题推荐:基于Java+SpringBoot物品租赁管理系统【源码+文档+调试】
java·vue.js·spring boot·mysql·spark·毕业设计·课程设计
路由侠内网穿透3 天前
本地部署 GPS 跟踪系统 Traccar 并实现外部访问
运维·服务器·网络·windows·tcp/ip