集成
添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-neo4j</artifactId></dependency>
spring:# neo4j 图数据库neo4j:uri: bolt://localhost:7687authentication:username: neo4jpassword: admin# 指定数据库data:neo4j:database: neo4j
如果和数据库一起集成,需要配置多数据源事务,不然事务会失效
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")@Primarypublic 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进行查询
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@GeneratedValueprivate Long id;@Property(name = "name")private String name;/*** 文件路径*/@Property(name = "url")private String url;}
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);}
2. 使用cypher进行查询
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 结果*/@Overridepublic 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 结果*/@Overridepublic 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 文献关系*/@Overridepublic 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 结果*/@Overridepublic 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 结果*/@Overridepublic 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 结果*/@Overridepublic 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);}}
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;@Overridepublic List<Neo4jData> run(String cypherSql) {try (Session session = driver.session()) {Result result = session.run(cypherSql);return this.parseResult(result);}}/*** 开启事务执行脚本** @param cypherSql 脚本* @return 结果*/@Overridepublic 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 结果*/@Overridepublic 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 结果*/@Overridepublic List<Neo4jData> runTx(Transaction tx, String cypherSql) {// 开启事务Result result = tx.run(cypherSql);return this.parseResult(result);}/*** 开启事务执行脚本** @param tx 事务* @param cypherSql 脚本* @param parameters 参数* @return 结果*/@Overridepublic 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 结果*/@Overridepublic 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 结果*/@Overridepublic 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 结果*/@Overridepublic 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 结果*/@Overridepublic 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.propertiesString 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 结果*/@Overridepublic 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.propertiesString 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 结果*/@Overridepublic 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 relfields.add(this.parseRelationship((InternalRelationship) item.getValue()));} else if (item.getValue() instanceof InternalPath) {// 路径, 如: MATCH p=()-[r:`作者`]->() RETURN p LIMIT 25InternalPath 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));}}// 获取segmentList<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));}}// 获取segmentList<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;}
}
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;}
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;}
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;}
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进行查询
/*** 文献搜索** @param keyword 关键字* @param pageable 分页查询* @return 结果*/@Overridepublic 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);}