知识图谱(Knowledge Graph,KG)将数据结构化为实体(如人、产品或事件等具体对象)和关系(描述这些实体之间如何相互关联)。与独立的数据表或文档不同,KG形成了一个相互关联的知识网络,便于从中获取洞察、回答复杂查询,并增强AI驱动的应用。但在构建知识图谱之前,首先需要定义其模式(schema)——一个描述图中存在哪些实体、属性和关系的蓝图。
在本文中,我们将深入探讨知识图谱的核心概念、模式的作用,以及如何利用AI进行模式发现。我们还将介绍如何存储和管理发现的模式。所有这些将通过一个示例案例来理解。最后,我们将讨论自动化知识图谱模式发现的架构。
知识图谱简介
知识图谱的核心概念包括三个要素:
- 1. 实体(Entity):领域中的一个独立对象。每个实体可以有多个节点实例。
- 2. 属性(Property):描述实体的特性。每个实体的一个属性作为关键属性(Key Property),用于区分该实体的不同节点实例。
- 3. 关系(Relationship):连接两个实体的边。
让我们通过一个例子来理解。请看下图:
从上图可以观察到以下几点:
- o 有三个带有标签的节点——John、Rita_和_Pen。John → Pen 和 Rita → Pen 通过“Purchased”(购买)关系连接。
- o 其中,带有标签_John_和_Rita_的节点是PERSON(人)实体的实例。而带有标签_Pen_的节点是PRODUCT(产品)实体的实例。
- o PERSON实体的属性有:name、mobile_no、address。PRODUCT实体的属性有:Product_Name、Cost。每个实体实例的属性都有各自的值。
- o 在这个例子中,用作节点实例标签的关键属性分别是PERSON实体的name和PRODUCT实体的Product_Name。关键属性的值必须唯一,以确保不同实例能够被明确区分。
- o “Purchased”关系(边)也可以拥有属性,例如Quantity(数量)。如果John买了2支笔,John-Pen这条边的quantity属性值可以是2;如果Rita买了3支,Rita-Pen这条边的quantity属性值可以是3。
- o 人-购买→产品的关系是一种典型的业务关系,可用于回答诸如“谁购买了这支笔?”这样的查询。
上述示例展示了一个简单的知识图谱,包含两个实体(PERSON和PRODUCT)和一个关系(Purchased)。
什么是知识图谱模式?
模式发现(Schema Discovery) 是指从数据中识别实体、属性和关系的过程,帮助我们理解数据的结构及其之间的连接。要将数据加载到知识图谱中,不仅需要识别实体、属性和关系,还需要确定每个属性的数据来源以及如何从源数据中映射关系。这种结构化定义构成了模式,该模式随后可用于将数据注入知识图谱。
构建知识图谱的数据来源包括结构化数据(如数据库表、CSV文件)以及非结构化内容(如文本、图片和视频)。本系列文章将专注于如何基于结构化数据构建知识图谱。
知识图谱模式发现
通过结合现有数据与领域知识,我们可以分析并识别出构建知识图谱所需的关键元素。在整个过程中,考虑最终用例和领域知识至关重要,以确保模式准确地表示有意义的实体、属性和关系,使得构建的知识图谱对业务有效且富有洞察力。
然而,手动执行此分析可能耗时且容易出错,特别是对于大型数据集。这正是AI可以自动化和简化模式发现的地方。
案例分析:
接下来,我们通过一个简单的例子进一步说明。以下是医院数据库中维护的三张数据表:Patient_Visits、Doctors_Record和Prescription_Record。
Patient_Visits
Doctors_Record
Prescription_Record
我们已将这些表保存为CSV文件。下面我们将一步步实现相关代码:
- o utils/llm_initializer.py — 用于初始化并与大型语言模型(LLM)提供商交互的类。本例使用了OpenAI。
from openai import OpenAI
classLLMInitializer:
# 用于初始化并与大型语言模型(LLM)提供商交互的类。
def__init__(self):
self.llm_provider = "OpenAI"
self.llm_name = "gpt-4o"
self.client = self.intialize_client()
defintialize_client(self):
# 初始化并返回指定LLM提供商的客户端对象。
ifself.llm_provider == "OpenAI":
return OpenAI()
else:
raise ValueError("LLM provider not supported")
defget_response(self, system_prompt, user_prompt, response_format_pydantic_model):
# 向LLM发送提示并返回结构化响应。
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
completion = self.client.beta.chat.completions.parse(
model=self.llm_name,
messages=messages,
response_format = response_format_pydantic_model,
temperature=0.2
)
return completion.choices[0].message.parsed
- o models.py – 定义用于实体和关系创建配置的Pydantic模型。
from pydantic import BaseModel
from typing importList, Optional
classEntityProperty(BaseModel):
property: str
is_key_property: bool
mapping_table: str
mapping_column: str
classEntity(BaseModel):
entity: str
properties: List[EntityProperty]
classEntityConfig(BaseModel):
entities: List[Entity]
classRelationship(BaseModel):
source_entity: str
target_entity: str
relationship: str
source_property: str
target_property: str
source_mapping_table: str
target_mapping_table: str
source_mapping_column: str
target_mapping_column: str
joining_condition: Optional[str]
classRelationshipConfig(BaseModel):
relationships: List[Relationship]
- o utils/table_schema_extractor.py – 用于从数据源中检索现有表的模式。具体的实现可以根据特定的数据库或存储系统进行定制。
import os
import pandas as pd
import json
classDataSchemaLoader:
def__init__(self):
self.data_folder_path = "../data"
self.file_format = "csv"
defload_schemas(self) -> str:
schema_list = []
for file_name in os.listdir(self.data_folder_path):
if file_name.endswith(self.file_format):
table_name = file_name.split(".")[0]
schema_list.append({table_name: self.load_schema(file_name)})
return json.dumps(schema_list)
defload_schema(self, file_name: str) -> dict:
file_path = os.path.join(self.data_folder_path, file_name)
df = pd.read_csv(file_path)
return df.columns.to_list()
- o prompts.py – 包含精心设计的系统提示,用于指导LLM发现数据中的实体和关系。可以进一步优化这些提示以获得更好的结果。
ENTITY_DISCOVERY_PROMPT = """
You are an expert knowledge graph schema designer with deep expertise in the
healthcare domain. You have extensive experience in extracting entities and
their properties from structured data to design efficient and meaningful
knowledge graphs. Your task is to analyze the provided table schemas and
discover key entities along with their relevant properties, ensuring an
optimal structure for knowledge representation to be used in a hospital
chatbot.
Given a set of tables schemas, discover the entities and their properties
that are most relevant for a hospital chatbot.
Instructions:
1. Identify distinct entities from the given table(s).
An entity represents a unique concept (e.g., Product, Customer, Order).
2. Assign relevant properties to each entity that define it.
3. Use the exact column name as the property name (do not rename columns).
4. Each entity must have exactly one key property that uniquely identifies it.
5. An entity can be derived from multiple tables, and a table can contain
multiple entities.
6. Ignore irrelevant columns that do not contribute meaningfully to an
entity's definition.
7. Don't add same property to more than one entity.
Output:
Return the entity creation config which contains the following fields for
each entry:
1. entity
2. property
3. is_key_property
4. source_table
5. source_column
Example:
<placeholder to add example>
"""
RELATIONSHIP_DISCOVERT_PROMPT = """
As an experienced data modeler specializing in knowledge graph design,
you have deep expertise in structuring data for hospital systems.
With extensive domain knowledge, you understand the frequently
asked questions and how data should be interconnected for efficient retrieval.
Your task is to identify meaningful relationships between entities
based on the provided table schemas and entity configurations.
You ensure that relationships in the graph database are structured,
relevant, and non-redundant, avoiding generic or unnecessary links.
Given table schemas and entity creation configurations, discover the
relationships between the entities to establish a well-defined knowledge
graph to be used for hospital chatbot.
How to Discover a Relationship?
1. Create a relationship only if there is a meaningful connection according
to the domain.
2. Avoid generic or vague relationships like "RELATED_TO" or "HAS."
3. Ensure that relationships improve query efficiency for the hospital chatbot
by linking entities that users are likely to ask about.
4. Derive relationships from the same table if the key properties of the
entities are present as columns in that table.
5. If key properties of connecting entities exist in different tables, check if a common column can be used for joining and establishing the relationship.
6. Ensure proper relationship direction - e.g., if defining "Placed" between
Customer and Order, Customer should be the source entity, and Order
should be the target entity (not vice versa).
BEWARE OF THE RELATIONSHIP DIRECTION.
7. THE RELATIONSHIPS YOU IDENTIFY SHOULD BE MEANINGUL AND USEFUL FOR A
HOSPITAL CHATBOT. THINK OF WHAT CAN BE THE MOST ASKED QUESTIONS IN A HOSPITAL
AND HOW THE RELATIONSHIPS CAN HELP IN ANSWERING THEM. BUILD RELATIONSHIPS
WHICH ARE FORMED BOTH USING SAME TABLE AND DIFFERENT TABLES.
Output:
Return the relationship creation config which contains the following fields for each entry:
1. Source_Entity
2. Relationship
3. Target_Entity
4. Source_Property
5. Target_Property
6. Source_Table
7. Target_Table
8. Source_Column
9. Target_Column
10. Joining_Condition (if applicable)
Example:
<placeholder to add example>
"""
- o knowledge_graph_schema.py — 利用上述提示调用LLM,自动生成实体和关系配置。
from utils.models import EntityConfig, RelationshipConfig
from utils.llm_initializer import LLMInitializer
from prompts import ENTITY_DISCOVERY_PROMPT, RELATIONSHIP_DISCOVERT_PROMPT
classKnowledgeGraphSchemaCreator:
def__init__(self, table_schema_list : str):
self.table_schema_list = table_schema_list
self.llm_intializer = LLMInitializer()
defgenerate_entity_config(self) -> EntityConfig:
user_prompt = "The following are the table schemas extracted from the data source: \n" + self.table_schema_list + "\nPlease provide the entity creation config based on the table schemas."
response = self.llm_intializer.get_response(
system_prompt=ENTITY_DISCOVERY_PROMPT,
user_prompt=user_prompt,
response_format_pydantic_model=EntityConfig
)
return response
defgenerate_relationship_schema(self,
entity_config : EntityConfig
) -> RelationshipConfig:
entity_config_str = entity_config.model_dump_json()
user_prompt = "The following are the table schemas extracted from the data source: \n" + self.table_schema_list + "\n. The following are the entity creation configurations: \n" + entity_config_str + "\nPlease provide the relationship discovery config based on the table schemas and entity creation configurations."
response = self.llm_intializer.get_response(
system_prompt=RELATIONSHIP_DISCOVERT_PROMPT,
user_prompt=user_prompt,
response_format_pydantic_model=RelationshipConfig
)
return response
- o main.py – 整个流程的入口点和编排器。
from knowledge_graph_schema import KnowledgeGraphSchemaCreator
from utils.table_schema_extractor import DataSchemaLoader
from dotenv import load_dotenv
load_dotenv()
data_schema_loader = DataSchemaLoader()
table_schema_list = data_schema_loader.load_schemas()
knowledge_graph_schema = KnowledgeGraphSchemaCreator(table_schema_list)
entity_config = knowledge_graph_schema.generate_entity_config()
relationship_config = knowledge_graph_schema.generate_relationship_schema(entity_config)
# write some print statements to parse the Pydnantic models...
- o 请创建一个.env文件,并将您的OPENAI_API_KEY添加到其中。
- o 此外,以下是该项目所需的requirements.txt文件内容:
openai==1.60.2
python-dotenv==1.0.1
pandas==2.2.3
安装完依赖包后,即可运行代码并查看结果。打开终端,执行命令python main.py。下面是返回的响应:
实体创建配置
关系创建配置
通过这些配置,我们可以看到LLM如何根据特定的领域用例,有效提取实体、属性、关系并建立它们与源数据的映射。这简化了复杂的数据建模任务,使流程更加高效和易于访问。在现实世界中,可能存在多个数据表,AI可以帮助我们节省大量的时间和精力进行模式发现。
存储和管理知识图谱模式
生成的模式可以存储为配置文件(CSV/JSON/YAML) ,这些文件随后可用于加载数据以构建知识图谱。生成的CSV配置文件应如下所示:
实体创建配置
关系创建配置
可以编写Python脚本,利用实体创建和关系创建的Pydantic模型来生成这些配置文件,从而自动化这一步骤。
然而,一种更强大的方法是将其作为图(元图,metagraph) 存储在知识图谱内部。
以图的形式表示模式,即将实体、其属性及关系建模为相互连接的节点,这样便于进行可视化展示、查询操作以及数据结构的动态更新。
下面是使用Neo4j为上述示例创建的元图。
知识图谱模式图
ENTITY节点的四个节点实例。Name表示元图中的实体名称。
ENTITY节点“Doctor”通过HAS_PROPERTY边连接到PROPERTY节点“Doctor_ID”。
RELATIONSHIP节点包含连接条件(如果存在)。
CONNECTS_TO边包含建立关系的目标实体的详细信息。
在上面的元图中,我们可以观察到:
- o 创建了实体(ENTITY)、属性(PROPERTY)和关系(RELATIONSHIP)节点。蓝色表示实体,橙色表示属性,绿色表示关系。
- o 每个ENTITY节点都有一个Name属性,表示它代表的实体名称;类似地,PROPERTY和RELATIONSHIP节点也有相应的属性,分别指定它们代表的属性名称和关系类型。
- o ENTITY节点通过HAS_PROPERTY边与PROPERTY节点连接,这些边记录了属性信息——Is_Key_Property、Source_Table和Source_Column。
- o RELATIONSHIP节点通过CONNECTS_FROM和CONNECTS_TO边连接ENTITY节点。CONNECTS_FROM边包含了属性信息:Source_Property、Source_Table、Source_Column。CONNECTS_TO边则包含了Target_Property、Target_Table和Target_Column等详细信息。如果RELATIONSHIP节点是通过连接两个表推导出来的,它会包含一个Joining_Condition属性。
这种将模式作为图存储的方法带来了以下优势:
- o 这提供了更好的可视化效果,更容易让领域专家探索和完善模式。
- o 其他应用程序也可以查询模式,实现自动化数据验证和治理。
- o 此外,将模式存储为图确保保留所有关系和约束,支持动态模式演进,以应对新的实体和属性出现。
- o 这种方法保持模式管理集中化、可扩展且适应性强。
让我们编写代码来实现这一点。
我们将使用Neo4j作为图数据库。安装Neo4j Desktop(
https://neo4j.com/deployment-center/?desktop-gdb),并在Web浏览器中访问`localhost:7474`打开Neo4j Browser(
https://neo4j.com/docs/browser-manual/current/deployment-modes/neo4j-desktop/)。Neo4j使用一种称为“Bolt”的专用协议(通常在端口7687上运行)进行程序化交互。当您访问Neo4j Browser时,输入用户名和密码后,它会自动连接到bolt://localhost:7687。Bolt连接允许应用程序以编程方式与Neo4j交互。连接后,即可运行Cypher查询来创建元图。
from neo4j import GraphDatabase
from utils.models import EntityConfig, RelationshipConfig
defcreate_metagraph(uri, username, password, database_name,
entity_config: EntityConfig, relationship_config: RelationshipConfig):
with GraphDatabase.driver(uri, auth=(username, password),
database=database_name
) as driver, driver.session() as session:
for entity in entity_config.entities:
entity_query = f"""
MERGE (e:ENTITY {{Name: '{entity.entity}'}})
{''.join([f"MERGE (p{idx}:PROPERTY {{Name: '{prop.property}'}})
MERGE (e)-[:HAS_PROPERTY {{Is_Key_Property:
{prop.is_key_property}, Source_Table: '{prop.mapping_table}',
Source_Column: '{prop.mapping_column}'}}]->(p{idx}) "
for idx, prop in enumerate(entity.properties, 1)])};
"""
session.run(entity_query)
for rel in relationship_config.relationships:
relationship_query = f"""
MATCH (s:ENTITY {{Name: '{rel.source_entity}'}}),
(t:ENTITY {{Name: '{rel.target_entity}'}})
MERGE (r:RELATIONSHIP {{Name: '{rel.relationship}',
Joining_Condition: '{rel.joining_condition or ''}'}})
MERGE (r)-[:CONNECTS_FROM {{Source_Property:
'{rel.source_property}', Source_Table:
'{rel.source_mapping_table}', Source_Column:
'{rel.source_mapping_column}'}}]->(s)
MERGE (r)-[:CONNECTS_TO {{Target_Property:
'{rel.target_property}', Target_Table:
'{rel.target_mapping_table}', Target_Column:
'{rel.target_mapping_column}'}}]->(t);
"""
session.run(relationship_query)
# 将实体和关系配置传递给此方法
uri = "bolt://localhost:7687"
username = ""
password = ""
database_name = ""
# create_metagraph(uri, username, password, database_name,
# entity_config, relationship_config)
所有上述代码均可在以下链接找到:
https://github.com/Pallavi-Sinha-12/Knowledge-Graph/tree/main/knowledge_graph_schema_discovery
知识图谱模式发现模块架构:
模式发现是一个持续的过程,因为新的数据表会不断出现,现有模式也会随之演进。保持知识图谱模式的更新至关重要。为了提高准确性,基于LLM的多智能体系统可以辅助模式发现。然而,AI的输出不应直接使用——领域专家必须进行评审和验证,然后才能将数据注入KG。在发现过程中,可以维护一个草稿元图,并在验证后最终确定。
下图展示了一个自动化模式发现的示例架构。图中所示的过程始于提取表模式,然后AI代理通过参考现有的知识图谱模式(元图)来识别实体和关系。生成Cypher查询来更新模式图,并结合SME(领域专家)的反馈进行持续完善。
AI驱动的知识图谱模式发现