基于笔者之前写的博客基础上:https://blog.csdn.net/zhanghan11366/article/details/142139488【基于开源WQ装备知识图谱的智能问答全流程构建】进行优化。
优化一、
解决你提出的多武器、多关系解析问题,并确保每个武器只匹配其对应的关系,结合分句功能
- 改进点:
- 分句功能:将问题分成多个句子,每个句子分别处理。
- 关系和武器的精确匹配:确保每个武器只匹配其对应的关系。
- 灵活解析:可以识别并处理句子中多个武器、多个关系。
- 改进点说明:
- 分句处理:问题会被切分为多个句子,使用 split_sents 函数根据常见的标点符号(如句号、问号、感叹号)进行分割。每个句子会独立处理。
- 多武器和多关系匹配:在每个句子中,分别提取出相关的武器和关系,并进行相应的查询。确保不会混淆多个武器和它们的对应关系。
- 缓存武器节点:程序启动时会从 Neo4j 缓存所有武器节点,避免重复查询,提高效率。
主要代码如下:
import re
from neo4j import GraphDatabase
# 全局缓存武器节点
cached_weapons = []
# 查询Neo4j数据库
def query_neo4j(query, parameters=None):
with driver.session() as session:
result = session.run(query, parameters)
return [record for record in result]
# 分句功能
def split_sents(content):
return [sentence.strip() for sentence in re.split(r'[??!!。;;\n\r]', content) if sentence.strip()]
# 生成回答模块
def generate_answer(sentence):
# 解析问题,提取武器和关系类型
parsed_sentence = parse_question(sentence)
weapons = parsed_sentence.get('weapons')
relations = parsed_sentence.get('relations')
if not weapons or not relations:
return f"无法识别句子中的武器或关系类型: {sentence}"
answers = []
for weapon in weapons:
for relation in relations:
# 构建查询语句
query = (
f"MATCH (w:Weapon {{name: $weapon}})-[r:`{relation}`]->(e) "
"RETURN e.name AS entity"
)
result = query_neo4j(query, parameters={"weapon": weapon})
# 生成单个武器-关系的回答
if result:
entity_list = [record["entity"] for record in result]
answers.append(f"{weapon}的{relation}是: {', '.join(entity_list)}")
else:
answers.append(f"没有找到{weapon}的{relation}信息。")
return "\n".join(answers)
结果
优化二
查寻两个武器之间的关系:“PZL P.6战斗机"和"PZL P.1战斗机”。为了解决两两配对查询中可能存在重复结果的问题,可以对配对后的武器查询进行优化。
- 主要思路是:
- 去重处理:在查询之前,使用集合来存储查询对,以避免重复查询同一对武器(无论顺序如何)。
- 只查询唯一的武器组合:即 (‘weapon1’, ‘weapon2’) 和 (‘weapon2’, ‘weapon1’) 应该视为同一对武器,不必重复查询。
- 关键优化点
- 使用 set():queried_pairs 集合用于存储已经查询过的武器对,确保每个组合只查询一次。这里使用 tuple(sorted([node1, node2])) 来生成无序的组合,即 (‘A’, ‘B’) 和 (‘B’, ‘A’) 会被视为同一个组合。
- 避免重复查询:每次进行查询前,检查该武器组合是否已经存在于 queried_pairs 中。如果不存在,则进行查询,并将其添加到 queried_pairs 中。
- 优化后的效果
- 同一对武器(如 PZL P.6战斗机 和 PZL P.1战斗机)无论顺序如何,只会查询一次,避免了重复结果。
提升了查询效率,尤其是在输入包含多个武器节点时,系统不会因重复查询浪费时间。
主要代码:
def generate_answer(sentence):
# 解析问题,提取武器和关系类型
parsed_sentence = parse_question(sentence)
weapons = parsed_sentence.get('weapons')
print(weapons)
relations = parsed_sentence.get('relations')
# 处理两个武器节点之间的关系查询
if len(weapons) == 2 and not relations:
node1, node2 = weapons[0], weapons[1]
return query_relation_between_weapons(node1, node2)
if not weapons or not relations:
return f"无法识别句子中的武器或关系类型: {sentence}"
answers = []
for weapon in weapons:
for relation in relations:
# 构建查询语句
query = (
f"MATCH (w:Weapon {{name: $weapon}})-[r:`{relation}`]->(e) "
"RETURN e.name AS entity"
)
result = query_neo4j(query, parameters={"weapon": weapon})
# 生成单个武器-关系的回答
if result:
entity_list = [record["entity"] for record in result]
answers.append(f"{weapon}的{relation}是: {', '.join(entity_list)}")
else:
answers.append(f"没有找到{weapon}的{relation}信息。")
return "\n".join(answers)
结果如下:
优化三
查找任意两个节点之间的关系。并在生成每个回答时,仅保留那些有实际关系的答案,避免输出那些无效的“没有找到关系”的信息。可以通过简单的条件检查实现这一点。
主要代码如下:
def generate_answer(sentence):
# 解析问题,提取节点和关系类型
parsed_sentence = parse_question(sentence)
nodes = parsed_sentence.get('nodes')
relations = parsed_sentence.get('relations')
# 处理多个节点之间的两两关系查询
if len(nodes) > 1 and not relations:
answers = []
# 使用集合存储查询对,避免重复查询
queried_pairs = set()
# 两两配对查询,避免重复的节点组合
for i in range(len(nodes)):
for j in range(i + 1, len(nodes)):
node1, node1_type = nodes[i]
node2, node2_type = nodes[j]
# 生成无序的节点对,用于去重
pair = tuple(sorted([(node1, node1_type), (node2, node2_type)]))
# 仅当这个配对未被查询过时才进行查询
if pair not in queried_pairs:
queried_pairs.add(pair) # 记录这个节点配对
answer = query_relation_between_nodes(node1, node1_type, node2, node2_type)
if answer: # 仅添加有关系的答案
answers.append(answer)
# 过滤掉没有关系的答案
return "\n".join(answers) if answers else "没有找到相关的关系。"
if not nodes or not relations:
return f"无法识别句子中的节点或关系类型: {sentence}"
# 单节点与关系类型的查询
answers = []
for node, node_type in nodes:
for relation in relations:
# 构建查询语句
query = (
f"MATCH (n:{node_type} {{name: $node}})-[r:`{relation}`]->(e) "
"RETURN e.name AS entity"
)
result = query_neo4j(query, parameters={"node": node})
# 生成单个节点-关系的回答
if result:
entity_list = [record["entity"] for record in result]
answers.append(f"{node}的{relation}是: {', '.join(entity_list)}")
else:
answers.append(f"没有找到{node}的{relation}信息。")
return "\n".join(answers)
结果展示: