| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- # -*- coding: utf-8 -*-
- """知识图谱管理:Neo4j + Py2neo 构建初中化学知识点与关联关系的结构化网络"""
- from typing import List, Dict, Any, Optional
- from backend.config import get_settings
- try:
- from py2neo import Graph, Node, Relationship, NodeMatcher
- except ImportError:
- Graph = Node = Relationship = NodeMatcher = None # type: ignore
- def _get_graph() -> Optional["Graph"]:
- if Graph is None:
- return None
- s = get_settings()
- try:
- return Graph(s.NEO4J_URI, auth=(s.NEO4J_USER, s.NEO4J_PASSWORD))
- except Exception:
- return None
- _FALLBACK_TRIPLES = [
- {"subject": "电解质", "predicate": "定义", "obj": "在水溶液或熔融状态下能够导电的化合物"},
- {"subject": "电解质", "predicate": "包含", "obj": "酸、碱、盐"},
- {"subject": "氧化还原反应", "predicate": "特征", "obj": "有元素化合价发生变化的反应"},
- {"subject": "物质的量", "predicate": "单位", "obj": "mol(摩尔)"},
- {"subject": "离子反应", "predicate": "条件", "obj": "有沉淀、气体或弱电解质生成"},
- {"subject": "原子", "predicate": "结构", "obj": "原子核和核外电子"},
- ]
- def search_knowledge_graph(query: str, limit: int = 15) -> List[Dict[str, Any]]:
- """
- 知识图谱检索:
- - 优先从 Neo4j 任意节点/关系中,按 name/subject/object/relationship 等常见字段模糊匹配;
- - 若 Neo4j 中没有命中,则回退到内置兜底三元组(保证常见基础概念可用)。
- """
- q = (query or "").strip()
- if len(q) < 1:
- return []
- g = _get_graph()
- if g is not None:
- try:
- # 通用检索:兼容不同建模方式(KnowledgePoint 图 + 三元组节点等)
- cypher = """
- MATCH (s)-[r]->(o)
- WITH
- s, r, o,
- coalesce(
- s.name,
- s.subject,
- s.subject_name,
- s.formula,
- s.symbol,
- s.description,
- toString(s)
- ) AS subj,
- coalesce(
- o.name,
- o.object,
- o.object_name,
- o.formula,
- o.symbol,
- o.description,
- toString(o)
- ) AS obj,
- coalesce(
- r.name,
- r.relationship,
- toString(type(r))
- ) AS rel
- WHERE subj CONTAINS $q
- OR obj CONTAINS $q
- OR rel CONTAINS $q
- RETURN subj AS subject,
- rel AS predicate,
- obj AS obj
- LIMIT $limit
- """
- cursor = g.run(cypher, q=q, limit=limit)
- results = [
- {
- "subject": r["subject"],
- "predicate": r["predicate"],
- "obj": r["obj"],
- }
- for r in cursor
- if r.get("subject") and r.get("obj")
- ]
- if results:
- return results
- except Exception:
- # 连接或查询失败时,退回内置数据
- pass
- # 兜底:从内置基础三元组中模糊匹配
- results = [t for t in _FALLBACK_TRIPLES if q in t["subject"] or q in t["obj"] or q in t["predicate"]]
- return results[:limit]
- def get_graph_for_visualization(limit: int = 50) -> Dict[str, Any]:
- """Force-directed 布局可视化"""
- g = _get_graph()
- if g is not None:
- try:
- # 适配三元组节点模型:id, subject, predicate, object
- cursor = g.run(
- """
- MATCH (t)
- WHERE t.subject IS NOT NULL
- AND t.predicate IS NOT NULL
- AND t.object IS NOT NULL
- RETURN t.subject AS src,
- t.object AS tgt,
- t.predicate AS rel
- LIMIT $limit
- """,
- limit=limit,
- )
- nodes_set, links = set(), []
- for record in cursor:
- nodes_set.add(record["src"])
- nodes_set.add(record["tgt"])
- links.append({"source": record["src"], "target": record["tgt"], "value": record["rel"]})
- return {"nodes": [{"name": n} for n in nodes_set], "links": links}
- except Exception:
- pass
- # 兜底
- nodes_set = set()
- links = []
- for t in _FALLBACK_TRIPLES:
- nodes_set.add(t["subject"])
- nodes_set.add(t["obj"])
- links.append({"source": t["subject"], "target": t["obj"], "value": t["predicate"]})
- return {"nodes": [{"name": n} for n in nodes_set], "links": links}
- def init_neo4j_schema(graph: "Graph") -> None:
- """初始化 Neo4j 初中化学知识图谱结构(若为空)"""
- try:
- graph.run("""
- MERGE (a:KnowledgePoint {name: '电解质'})
- MERGE (b:KnowledgePoint {name: '在水溶液或熔融状态下能够导电的化合物'})
- MERGE (a)-[:定义]->(b)
- """)
- graph.run("""
- MERGE (a:KnowledgePoint {name: '电解质'})
- MERGE (b:KnowledgePoint {name: '酸、碱、盐'})
- MERGE (a)-[:包含]->(b)
- """)
- graph.run("""
- MERGE (a:KnowledgePoint {name: '氧化还原反应'})
- MERGE (b:KnowledgePoint {name: '有元素化合价发生变化的反应'})
- MERGE (a)-[:特征]->(b)
- """)
- graph.run("""
- MERGE (a:KnowledgePoint {name: '物质的量'})
- MERGE (b:KnowledgePoint {name: 'mol(摩尔)'})
- MERGE (a)-[:单位]->(b)
- """)
- graph.run("""
- MERGE (a:KnowledgePoint {name: '原子'})
- MERGE (b:KnowledgePoint {name: '原子核和核外电子'})
- MERGE (a)-[:结构]->(b)
- """)
- graph.run("""
- MERGE (a:KnowledgePoint {name: '原子核'})
- MERGE (b:KnowledgePoint {name: '质子和中子'})
- MERGE (a)-[:组成]->(b)
- """)
- except Exception:
- pass
|