集成
添加依赖
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);
}
- 使用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);
}