| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
a00c04d757 | test | 1 year ago |
|
|
2a40f169d3 | kg部分代码 | 1 year ago |
| @@ -248,6 +248,21 @@ | |||
| <artifactId>hutool-all</artifactId> | |||
| <version>5.8.5</version> | |||
| </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> | |||
| <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()); | |||
| } | |||
| } | |||