| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
a00c04d757 | test | 1 year ago |
|
|
2a40f169d3 | kg部分代码 | 1 year ago |
| @@ -248,6 +248,21 @@ | |||||
| <artifactId>hutool-all</artifactId> | <artifactId>hutool-all</artifactId> | ||||
| <version>5.8.5</version> | <version>5.8.5</version> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>org.springframework.boot</groupId> | |||||
| <artifactId>spring-boot-starter-data-neo4j</artifactId> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>com.alibaba</groupId> | |||||
| <artifactId>easyexcel</artifactId> | |||||
| <version>4.0.3</version> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>org.springframework.boot</groupId> | |||||
| <artifactId>spring-boot-starter-test</artifactId> | |||||
| <scope>test</scope> | |||||
| </dependency> | |||||
| </dependencies> | </dependencies> | ||||
| <build> | <build> | ||||
| @@ -0,0 +1,15 @@ | |||||
| package com.ruoyi.platform.config; | |||||
| import org.neo4j.cypherdsl.core.renderer.Dialect; | |||||
| import org.springframework.context.annotation.Bean; | |||||
| import org.springframework.context.annotation.Configuration; | |||||
| @Configuration | |||||
| public class Neo4jConfig { | |||||
| @Bean | |||||
| org.neo4j.cypherdsl.core.renderer.Configuration cypherDslConfiguration() { | |||||
| return org.neo4j.cypherdsl.core.renderer.Configuration.newConfig() | |||||
| .withDialect(Dialect.NEO4J_5).build(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,124 @@ | |||||
| package com.ruoyi.platform.controller.kg; | |||||
| import com.ruoyi.common.core.domain.R; | |||||
| import com.ruoyi.platform.utils.ExcelReaderInputStream; | |||||
| import org.springframework.web.bind.annotation.PostMapping; | |||||
| import org.springframework.web.bind.annotation.RequestMapping; | |||||
| import org.springframework.web.bind.annotation.RequestParam; | |||||
| import org.springframework.web.bind.annotation.RestController; | |||||
| import org.springframework.web.multipart.MultipartFile; | |||||
| import java.io.File; | |||||
| import java.io.InputStream; | |||||
| import java.nio.charset.StandardCharsets; | |||||
| import java.util.Map; | |||||
| @RestController | |||||
| @RequestMapping("/kg") | |||||
| public class MatKGController { | |||||
| @PostMapping("/uploadOntology") | |||||
| public R<String> uploadOntology(@RequestParam("file") MultipartFile file, | |||||
| @RequestParam("param") String param) { | |||||
| if (file.isEmpty()) { | |||||
| return R.fail("文件为空"); | |||||
| } | |||||
| try { | |||||
| // 直接读取文件内容为字符串 | |||||
| String jsonContent = new String(file.getBytes(), StandardCharsets.UTF_8); | |||||
| return R.ok(); | |||||
| } catch (Exception e) { | |||||
| return R.fail("文件处理失败: " + e.getMessage()); | |||||
| } | |||||
| } | |||||
| @PostMapping("/uploadKGData") | |||||
| public R<String> uploadKGData(@RequestParam("file") MultipartFile file, | |||||
| @RequestParam("id") String id) { | |||||
| if (file.isEmpty()) { | |||||
| return R.fail("文件为空"); | |||||
| } | |||||
| // 检查文件类型 | |||||
| String contentType = file.getContentType(); | |||||
| String fileName = file.getOriginalFilename(); | |||||
| if (!isValidFileType(contentType, fileName)) { | |||||
| return R.fail("不支持的文件格式。请上传CSV、XLSX或JSON文件。"); | |||||
| } | |||||
| try { | |||||
| // 创建目标文件 | |||||
| InputStream inputStream = file.getInputStream(); | |||||
| // 处理文件和参数 | |||||
| processJsonFile(inputStream, id); | |||||
| return R.ok(); | |||||
| } catch (Exception e) { | |||||
| return R.fail("文件处理失败: " + e.getMessage()); | |||||
| } | |||||
| } | |||||
| private void processJsonFile(InputStream inputStream, String id) { | |||||
| ExcelReaderInputStream<Map> reader = new ExcelReaderInputStream<>(inputStream,Map.class,data->{ | |||||
| //todo some logic | |||||
| }); | |||||
| // 读取Excel文件 | |||||
| reader.read(); | |||||
| } | |||||
| @PostMapping("/uploadKGData2") | |||||
| public R<String> uploadKGData2(@RequestParam("file") MultipartFile file, | |||||
| @RequestParam("param") String param) { | |||||
| if (file.isEmpty()) { | |||||
| return R.fail("文件为空"); | |||||
| } | |||||
| // 检查文件类型 | |||||
| String contentType = file.getContentType(); | |||||
| String fileName = file.getOriginalFilename(); | |||||
| if (!isValidFileType(contentType, fileName)) { | |||||
| return R.fail("不支持的文件格式。请上传CSV、XLSX或JSON文件。"); | |||||
| } | |||||
| try { | |||||
| // 创建目标文件 | |||||
| File targetFile = new File("uploadDir", file.getOriginalFilename()); | |||||
| // 确保目录存在 | |||||
| if (!targetFile.getParentFile().exists()) { | |||||
| targetFile.getParentFile().mkdirs(); | |||||
| } | |||||
| // 将文件写入目标路径 | |||||
| file.transferTo(targetFile); | |||||
| // 处理文件和参数 | |||||
| // processJsonFile(targetFile, param); | |||||
| return R.ok("文件上传并处理成功,参数: " + param); | |||||
| } catch (Exception e) { | |||||
| return R.fail("文件处理失败: " + e.getMessage()); | |||||
| } | |||||
| } | |||||
| private boolean isValidFileType(String contentType, String fileName) { | |||||
| // 检查文件扩展名 | |||||
| String extension = getFileExtension(fileName); | |||||
| // 检查MIME类型 | |||||
| if ("application/json".equals(contentType) || "text/csv".equals(contentType) || "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType)) { | |||||
| return true; | |||||
| } | |||||
| // 检查文件扩展名 | |||||
| return "csv".equalsIgnoreCase(extension) || "xlsx".equalsIgnoreCase(extension) || "json".equalsIgnoreCase(extension); | |||||
| } | |||||
| private String getFileExtension(String fileName) { | |||||
| if (fileName != null && fileName.contains(".")) { | |||||
| return fileName.substring(fileName.lastIndexOf('.') + 1); | |||||
| } | |||||
| return ""; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| package com.ruoyi.platform.domain.material; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Data; | |||||
| import org.springframework.data.annotation.Id; | |||||
| import org.springframework.data.neo4j.core.schema.Node; | |||||
| @Node | |||||
| @Data | |||||
| @AllArgsConstructor | |||||
| public class DOI { | |||||
| @Id | |||||
| private String doi; // DOI | |||||
| private Integer year;// YEAR | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| package com.ruoyi.platform.domain.material; | |||||
| import lombok.Data; | |||||
| import org.springframework.data.annotation.Id; | |||||
| import org.springframework.data.neo4j.core.schema.Node; | |||||
| import org.springframework.data.neo4j.core.schema.Relationship; | |||||
| @Data | |||||
| @Node | |||||
| public class MaterialEntity { | |||||
| @Id | |||||
| private String id; | |||||
| private String entity; | |||||
| @Relationship(type = "HAS_ENTITY") | |||||
| private PartOfText partOfText; | |||||
| @Relationship(type = "HAS_NER_TAG") | |||||
| private NERTag nerTag; | |||||
| @Relationship(type = "HAS_DOI") | |||||
| private DOI doi; | |||||
| @Relationship(type = "HAS_PREFERRED_ENTITY") | |||||
| private PreferredEntity preferredEntity; | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| package com.ruoyi.platform.domain.material; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Data; | |||||
| import org.springframework.data.annotation.Id; | |||||
| import org.springframework.data.neo4j.core.schema.Node; | |||||
| @Node | |||||
| @Data | |||||
| @AllArgsConstructor | |||||
| public class NERTag { | |||||
| @Id | |||||
| private String tag; // NER_Tag | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| package com.ruoyi.platform.domain.material; | |||||
| import cn.hutool.core.util.IdUtil; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Data; | |||||
| import org.springframework.data.annotation.Id; | |||||
| import org.springframework.data.neo4j.core.schema.Node; | |||||
| @Node | |||||
| @Data | |||||
| @AllArgsConstructor | |||||
| public class PartOfText { | |||||
| @Id | |||||
| private String text; // Part_of_text | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| package com.ruoyi.platform.domain.material; | |||||
| import lombok.AllArgsConstructor; | |||||
| import lombok.Data; | |||||
| import org.springframework.data.annotation.Id; | |||||
| import org.springframework.data.neo4j.core.schema.Node; | |||||
| @Node | |||||
| @Data | |||||
| @AllArgsConstructor | |||||
| public class PreferredEntity { | |||||
| @Id | |||||
| private String preferredEntity; | |||||
| } | |||||
| @@ -0,0 +1,8 @@ | |||||
| package com.ruoyi.platform.repository; | |||||
| import com.ruoyi.platform.domain.material.MaterialEntity; | |||||
| import org.springframework.data.neo4j.repository.Neo4jRepository; | |||||
| public interface MatKGRepository | |||||
| extends Neo4jRepository<MaterialEntity, String> { | |||||
| } | |||||
| @@ -0,0 +1,32 @@ | |||||
| package com.ruoyi.platform.service.impl; | |||||
| import com.ruoyi.platform.domain.material.MaterialEntity; | |||||
| import com.ruoyi.platform.repository.MatKGRepository; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | |||||
| import org.springframework.stereotype.Service; | |||||
| import java.util.List; | |||||
| import java.util.Optional; | |||||
| @Service | |||||
| public class MatKGServiceImpl { | |||||
| @Autowired | |||||
| private MatKGRepository repository; | |||||
| public MaterialEntity save(MaterialEntity entity) { | |||||
| return repository.save(entity); | |||||
| } | |||||
| public List<MaterialEntity> saveAll(List<MaterialEntity> entity) { | |||||
| return repository.saveAll(entity); | |||||
| } | |||||
| public Optional<MaterialEntity> findById(String id) { | |||||
| return repository.findById(id); | |||||
| } | |||||
| public void deleteById(String id) { | |||||
| repository.deleteById(id); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,154 @@ | |||||
| package com.ruoyi.platform.service.impl; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | |||||
| import org.springframework.data.neo4j.core.Neo4jClient; | |||||
| import org.springframework.stereotype.Service; | |||||
| import java.util.Map; | |||||
| import java.util.Random; | |||||
| @Service | |||||
| public class Neo4JDBService { | |||||
| @Autowired | |||||
| private Neo4jClient neo4jClient; | |||||
| private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; | |||||
| private static final Random RANDOM = new Random(); | |||||
| private static final int NAME_LENGTH = 10; // 数据库名称的长度 | |||||
| public void createDatabase(String dbName) { | |||||
| neo4jClient.query("CREATE DATABASE $dbName") | |||||
| .bind(dbName).to("dbName") | |||||
| .run(); | |||||
| } | |||||
| public void dropDatabase(String dbName) { | |||||
| neo4jClient.query("DROP DATABASE $dbName") | |||||
| .bind(dbName).to("dbName") | |||||
| .run(); | |||||
| } | |||||
| public void createNode(String nodeType, Map<String, Object> properties) { | |||||
| StringBuilder query = new StringBuilder("CREATE (n:" + nodeType + " {"); | |||||
| properties.forEach((key, value) -> query.append(key).append(": $").append(key).append(", ")); | |||||
| query.setLength(query.length() - 2); // 移除最后的逗号和空格 | |||||
| query.append("})"); | |||||
| Neo4jClient.UnboundRunnableSpec neo4jQuery = neo4jClient.query(query.toString()); | |||||
| properties.forEach((key, value) -> neo4jQuery.bind(value).to(key)); | |||||
| neo4jQuery.run(); | |||||
| } | |||||
| public void updateNode(String nodeType, String identifierKey, Object identifierValue, Map<String, Object> properties) { | |||||
| StringBuilder query = new StringBuilder("MATCH (n:" + nodeType + " {" + identifierKey + ": $" + identifierKey + "}) SET "); | |||||
| properties.forEach((key, value) -> query.append("n.").append(key).append(" = $").append(key).append(", ")); | |||||
| query.setLength(query.length() - 2); // 移除最后的逗号和空格 | |||||
| Neo4jClient.UnboundRunnableSpec neo4jQuery = neo4jClient.query(query.toString()); | |||||
| neo4jQuery.bind(identifierValue).to(identifierKey); | |||||
| properties.forEach((key, value) -> neo4jQuery.bind(value).to(key)); | |||||
| neo4jQuery.run(); | |||||
| } | |||||
| public void deleteNode(String nodeType, String identifierKey, Object identifierValue) { | |||||
| String query = "MATCH (n:" + nodeType + " {" + identifierKey + ": $" + identifierKey + "}) DETACH DELETE n"; | |||||
| neo4jClient.query(query) | |||||
| .bind(identifierValue).to(identifierKey) | |||||
| .run(); | |||||
| } | |||||
| public void createRelationship(String startNodeType, String startIdentifierKey, Object startIdentifierValue, | |||||
| String endNodeType, String endIdentifierKey, Object endIdentifierValue, | |||||
| String relationshipType) { | |||||
| String query = "MATCH (a:" + startNodeType + " {" + startIdentifierKey + ": $" + startIdentifierKey + "}), " + | |||||
| "(b:" + endNodeType + " {" + endIdentifierKey + ": $" + endIdentifierKey + "}) " + | |||||
| "CREATE (a)-[r:" + relationshipType + "]->(b)"; | |||||
| neo4jClient.query(query) | |||||
| .bind(startIdentifierValue).to(startIdentifierKey) | |||||
| .bind(endIdentifierValue).to(endIdentifierKey) | |||||
| .run(); | |||||
| } | |||||
| public void updateRelationship(String startNodeType, String startIdentifierKey, Object startIdentifierValue, | |||||
| String endNodeType, String endIdentifierKey, Object endIdentifierValue, | |||||
| String relationshipType, Map<String, Object> properties) { | |||||
| StringBuilder query = new StringBuilder("MATCH (a:" + startNodeType + " {" + startIdentifierKey + ": $" + startIdentifierKey + "}) " + | |||||
| "-[r:" + relationshipType + "]->(b:" + endNodeType + " {" + endIdentifierKey + ": $" + endIdentifierKey + "}) SET "); | |||||
| properties.forEach((key, value) -> query.append("r.").append(key).append(" = $").append(key).append(", ")); | |||||
| query.setLength(query.length() - 2); // 移除最后的逗号和空格 | |||||
| Neo4jClient.UnboundRunnableSpec neo4jQuery = neo4jClient.query(query.toString()); | |||||
| neo4jQuery.bind(startIdentifierValue).to(startIdentifierKey); | |||||
| neo4jQuery.bind(endIdentifierValue).to(endIdentifierKey); | |||||
| properties.forEach((key, value) -> neo4jQuery.bind(value).to(key)); | |||||
| neo4jQuery.run(); | |||||
| } | |||||
| public void deleteRelationship(String startNodeType, String startIdentifierKey, Object startIdentifierValue, | |||||
| String endNodeType, String endIdentifierKey, Object endIdentifierValue, | |||||
| String relationshipType) { | |||||
| String query = "MATCH (a:" + startNodeType + " {" + startIdentifierKey + ": $" + startIdentifierKey + "}) " + | |||||
| "-[r:" + relationshipType + "]->(b:" + endNodeType + " {" + endIdentifierKey + ": $" + endIdentifierKey + "}) " + | |||||
| "DELETE r"; | |||||
| neo4jClient.query(query) | |||||
| .bind(startIdentifierValue).to(startIdentifierKey) | |||||
| .bind(endIdentifierValue).to(endIdentifierKey) | |||||
| .run(); | |||||
| } | |||||
| public void clearDatabase(String dbName) { | |||||
| neo4jClient.query("MATCH (n) DETACH DELETE n") | |||||
| .bind(dbName).to("dbName") // 指定数据库 | |||||
| .run(); | |||||
| } | |||||
| public boolean doesDatabaseExist(String dbName) { | |||||
| String query = "CALL dbs() YIELD name WHERE name = $dbName RETURN name"; | |||||
| return neo4jClient.query(query) | |||||
| .bind(dbName).to("dbName") | |||||
| .fetchAs(String.class) | |||||
| .mappedBy((type, record) -> record.get("name").asString()) | |||||
| .one() | |||||
| .isPresent(); | |||||
| } | |||||
| public boolean isValidAndExists(String dbName) { | |||||
| return !doesDatabaseExist(dbName) && isValidDatabaseName(dbName); | |||||
| } | |||||
| public static String generateRandomDatabaseName() { | |||||
| StringBuilder name = new StringBuilder(NAME_LENGTH); | |||||
| // 首先添加一个字母 | |||||
| name.append(CHARACTERS.charAt(RANDOM.nextInt(52))); | |||||
| // 随后添加随机字符 | |||||
| for (int i = 1; i < NAME_LENGTH; i++) { | |||||
| name.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); | |||||
| } | |||||
| return name.toString(); | |||||
| } | |||||
| public static boolean isValidDatabaseName(String name) { | |||||
| // 检查长度 | |||||
| if (name == null || name.isEmpty() || name.length() > 255) { | |||||
| return false; | |||||
| } | |||||
| // 检查首字符是否为字母 | |||||
| if (!Character.isLetter(name.charAt(0))) { | |||||
| return false; | |||||
| } | |||||
| // 检查字符是否合法 | |||||
| for (char c : name.toCharArray()) { | |||||
| if (!Character.isLetterOrDigit(c) && c != '_') { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,34 @@ | |||||
| package com.ruoyi.platform.utils; | |||||
| import com.alibaba.excel.EasyExcel; | |||||
| import com.alibaba.excel.context.AnalysisContext; | |||||
| import com.alibaba.excel.read.listener.ReadListener; | |||||
| import java.util.function.Consumer; | |||||
| public class ExcelReader<T> { | |||||
| private final String filePath; | |||||
| private final Class<T> dataClass; | |||||
| private final Consumer<T> processor; | |||||
| public ExcelReader(String filePath, Class<T> dataClass, Consumer<T> processor) { | |||||
| this.filePath = filePath; | |||||
| this.dataClass = dataClass; | |||||
| this.processor = processor; | |||||
| } | |||||
| public void read() { | |||||
| EasyExcel.read(filePath, dataClass, new ReadListener<T>() { | |||||
| @Override | |||||
| public void invoke(T data, AnalysisContext context) { | |||||
| processor.accept(data); | |||||
| } | |||||
| @Override | |||||
| public void doAfterAllAnalysed(AnalysisContext context) { | |||||
| // 所有数据处理完毕后的操作 | |||||
| } | |||||
| }).sheet().doRead(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,35 @@ | |||||
| package com.ruoyi.platform.utils; | |||||
| import com.alibaba.excel.EasyExcel; | |||||
| import com.alibaba.excel.context.AnalysisContext; | |||||
| import com.alibaba.excel.read.listener.ReadListener; | |||||
| import java.io.InputStream; | |||||
| import java.util.function.Consumer; | |||||
| public class ExcelReaderInputStream<T> { | |||||
| private final InputStream inputStream; | |||||
| private final Class<T> dataClass; | |||||
| private final Consumer<T> processor; | |||||
| public ExcelReaderInputStream(InputStream inputStream, Class<T> dataClass, Consumer<T> processor) { | |||||
| this.inputStream = inputStream; | |||||
| this.dataClass = dataClass; | |||||
| this.processor = processor; | |||||
| } | |||||
| public void read() { | |||||
| EasyExcel.read(inputStream, dataClass, new ReadListener<T>() { | |||||
| @Override | |||||
| public void invoke(T data, AnalysisContext context) { | |||||
| processor.accept(data); | |||||
| } | |||||
| @Override | |||||
| public void doAfterAllAnalysed(AnalysisContext context) { | |||||
| // 所有数据处理完毕后的操作 | |||||
| } | |||||
| }).sheet().doRead(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| package com.ruoyi.platform.vo; | |||||
| import lombok.Data; | |||||
| @Data | |||||
| public class MatKGVo { | |||||
| private String Unnamed; | |||||
| private String Entity; | |||||
| private String Part_of_text; | |||||
| private String NER_Tag; | |||||
| private String DOI; | |||||
| private String Preferred_Entity; | |||||
| private Integer Year; | |||||
| } | |||||
| @@ -0,0 +1,52 @@ | |||||
| package com.ruoyi.platform.utils; | |||||
| import com.ruoyi.platform.domain.kg.*; | |||||
| import com.ruoyi.platform.repository.MatKGRepository; | |||||
| import com.ruoyi.platform.service.impl.MatKGServiceImpl; | |||||
| import com.ruoyi.platform.vo.MatKGVo; | |||||
| import org.junit.jupiter.api.Test; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | |||||
| import org.springframework.boot.test.context.SpringBootTest; | |||||
| import java.util.Optional; | |||||
| import java.util.concurrent.ExecutorService; | |||||
| import java.util.concurrent.Executors; | |||||
| @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | |||||
| public class ExcelReaderTest { | |||||
| @Autowired | |||||
| private MatKGServiceImpl service; | |||||
| @Autowired | |||||
| private MatKGRepository repository; | |||||
| @Test | |||||
| void read() { | |||||
| String excelFilePath = "C:\\haha\\matKG\\ENTDOI.csv"; | |||||
| ExecutorService executorService = Executors.newFixedThreadPool(10); | |||||
| // 创建ExcelReader实例 | |||||
| ExcelReader<MatKGVo> excelReader = new ExcelReader<>(excelFilePath, MatKGVo.class, data -> { | |||||
| // Optional<MaterialEntity> existingEntity = service.findById(data.getEntity()); | |||||
| // executorService.execute(() -> { | |||||
| MaterialEntity entity = new MaterialEntity(); | |||||
| entity.setId(data.getUnnamed()); | |||||
| entity.setEntity(data.getEntity()); | |||||
| entity.setPreferredEntity(new PreferredEntity(data.getPreferred_Entity())); | |||||
| entity.setDoi(new DOI(data.getDOI(),data.getYear())); | |||||
| entity.setNerTag(new NERTag(data.getNER_Tag())); | |||||
| entity.setPartOfText(new PartOfText(data.getPart_of_text())); | |||||
| service.save(entity); | |||||
| // }); | |||||
| // System.out.println(data); | |||||
| }); | |||||
| // 读取Excel文件 | |||||
| excelReader.read(); | |||||
| } | |||||
| @Test | |||||
| public void xx(){ | |||||
| Optional<MaterialEntity> byId = repository.findById("27358"); | |||||
| System.out.println(byId.get()); | |||||
| } | |||||
| } | |||||