|
@@ -0,0 +1,117 @@
|
|
|
|
+package com.qizhen.healsphere.util;
|
|
|
|
+
|
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
|
+import com.qizhen.healsphere.config.Neo4jUtil;
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+import org.neo4j.driver.v1.Record;
|
|
|
|
+import org.neo4j.driver.v1.Session;
|
|
|
|
+import org.neo4j.driver.v1.StatementResult;
|
|
|
|
+import org.neo4j.driver.v1.Values;
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
|
+
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
+
|
|
|
|
+@Slf4j
|
|
|
|
+@Component
|
|
|
|
+public class DrugRelationCreator {
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private Neo4jUtil neo4jUtil;
|
|
|
|
+
|
|
|
|
+ private static final int BATCH_SIZE = 1000;
|
|
|
|
+ // 匹配中文字符的正则表达式
|
|
|
|
+ private static final Pattern CHINESE_PATTERN = Pattern.compile("[\\u4e00-\\u9fa5]+");
|
|
|
|
+ private static final int MIN_LENGTH = 3;
|
|
|
|
+
|
|
|
|
+ public void createDrugSubclassRelations() {
|
|
|
|
+ log.info("开始创建药品子类关系...");
|
|
|
|
+
|
|
|
|
+ try (Session session = neo4jUtil.getSession()) {
|
|
|
|
+ // 1. 获取所有药品节点
|
|
|
|
+ String queryDrugs = "MATCH (d:药品) RETURN d.name as name";
|
|
|
|
+ StatementResult result = session.run(queryDrugs);
|
|
|
|
+
|
|
|
|
+ List<String> drugNames = new ArrayList<>();
|
|
|
|
+ while (result.hasNext()) {
|
|
|
|
+ Record record = result.next();
|
|
|
|
+ String name = record.get("name").asString();
|
|
|
|
+ // 过滤条件:非空、中文字符、长度大于3
|
|
|
|
+ if (isValidDrugName(name)) {
|
|
|
|
+ drugNames.add(name);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ log.info("共找到 {} 个符合条件的药品节点", drugNames.size());
|
|
|
|
+
|
|
|
|
+ // 2. 比较节点名称并创建关系
|
|
|
|
+ int count = 0;
|
|
|
|
+ for (int i = 0; i < drugNames.size(); i++) {
|
|
|
|
+ String drug1 = drugNames.get(i);
|
|
|
|
+
|
|
|
|
+ for (int j = 0; j < drugNames.size(); j++) {
|
|
|
|
+ if (i == j) continue;
|
|
|
|
+
|
|
|
|
+ String drug2 = drugNames.get(j);
|
|
|
|
+
|
|
|
|
+ // 如果drug1包含drug2,则drug1是drug2的父类
|
|
|
|
+ if (drug1.contains(drug2)) {
|
|
|
|
+ createSubclassRelation(session, drug2, drug1);
|
|
|
|
+ count++;
|
|
|
|
+
|
|
|
|
+ if (count % BATCH_SIZE == 0) {
|
|
|
|
+ log.info("已处理 {} 条关系", count);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 如果drug2包含drug1,则drug2是drug1的父类
|
|
|
|
+ else if (drug2.contains(drug1)) {
|
|
|
|
+ createSubclassRelation(session, drug1, drug2);
|
|
|
|
+ count++;
|
|
|
|
+
|
|
|
|
+ if (count % BATCH_SIZE == 0) {
|
|
|
|
+ log.info("已处理 {} 条关系", count);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ log.info("药品子类关系创建完成,共创建 {} 条关系", count);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("创建药品子类关系时发生错误", e);
|
|
|
|
+ throw new RuntimeException("创建药品子类关系失败", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 判断药品名称是否有效
|
|
|
|
+ * 条件:
|
|
|
|
+ * 1. 非空
|
|
|
|
+ * 2. 包含中文字符
|
|
|
|
+ * 3. 长度大于3个字符
|
|
|
|
+ */
|
|
|
|
+ private boolean isValidDrugName(String name) {
|
|
|
|
+ if (StrUtil.isBlank(name) || name.length() < MIN_LENGTH) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ // 检查是否包含中文字符
|
|
|
|
+ return CHINESE_PATTERN.matcher(name).find();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void createSubclassRelation(Session session, String subDrug, String parentDrug) {
|
|
|
|
+ try {
|
|
|
|
+ String cypher =
|
|
|
|
+ "MATCH (sub:药品 {name: $subName}), (parent:药品 {name: $parentName}) " +
|
|
|
|
+ "MERGE (sub)-[r:药品相关子类]->(parent) " +
|
|
|
|
+ "RETURN sub, parent, r";
|
|
|
|
+
|
|
|
|
+ session.run(cypher, Values.parameters(
|
|
|
|
+ "subName", subDrug,
|
|
|
|
+ "parentName", parentDrug
|
|
|
|
+ ));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("创建关系时发生错误: {} -> {}", subDrug, parentDrug, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|