如何使用neo4j和transformer构建知识图谱-金马国际
- 2022 年 3 月 21 日
本文字数:4765 字
阅读完需:约 16 分钟
本文最初发布于 towards data science。
在这篇文章中,我将展示如何使用经过优化的、基于转换器的命名实体识别(ner)以及 spacy 的关系提取模型,基于职位描述创建一个知识图谱。这里介绍的方法可以应用于其他任何领域,如生物医学、金融、医疗保健等。
以下是我们要采取的步骤:
在 google colab 中加载优化后的转换器 ner 和 spacy 关系提取模型;
创建一个 neo4j sandbox,并添加实体和关系;
查询图,找出与目标简历匹配度最高的职位,找出三个最受欢迎的技能和共现率最高的技能。
要了解关于如何使用 ubiai 生成训练数据以及优化 ner 和关系提取模型的更多信息,请查看以下文章。
职位描述数据集可以从获取。
在本文结束的时候,我们就可以创建出如下所示的知识图谱。
首先,我们加载 ner 和关系模型的依赖关系,以及之前优化过的 ner 模型本身,以提取技能、学历、专业和工作年限:
!pip install -u pip setuptools wheel
!python -m spacy project clone tutorials/rel_component
!pip install -u spacy-nightly --pre
!!pip install -u spacy transformers
import spacy
#安装完依赖项后重启运行时
nlp = spacy.load("[path_to_the_model]/model-best")
加载我们想从中提取实体和关系的职位数据集:
import pandas as pd
def get_all_documents():
df = pd.read_csv("/content/drive/mydrive/job_db1_1_29.csv",sep='"',hea
der=none)
documents = []
for index,row in df.iterrows():
documents.append(str(row[0]))
return documents
documents = get_all_documents()
documents = documents[:]
从职位数据集中提取实体:
import hashlib
def extract_ents(documents,nlp):
docs = list()
for doc in nlp.pipe(documents, disable=["tagger", "parser"]):
dictionary=dict.fromkeys(["text", "annotations"])
dictionary["text"]= str(doc)
dictionary['text_sha256'] = hashlib.sha256(dictionary["text"].encode('utf-8')).hexdigest()
annotations=[]
for e in doc.ents:
ent_id = hashlib.sha256(str(e.text).encode('utf-8')).hexdigest()
ent = {"start":e.start_char,"end":e.end_char, "label":e.label_,"label_upper":e.label_.upper(),"text":e.text,"id":ent_id}
if e.label_ == "experience":
ent["years"] = int(e.text[0])
annotations.append(ent)
dictionary["annotations"] = annotations
docs.append(dictionary)
#print(annotations)
return docs
parsed_ents = extract_ents(documents,nlp)
在将实体提供给关系提取模型之前,我们可以看下提取出的部分实体:
[('stock market analysis', 'skills'),
('private investor', 'skills'),
('c ', 'skills'),
('investment software', 'skills'),
('ms windows', 'skills'),
('web development', 'skills'),
('computer science', 'diploma_major'),
('ai', 'skills'),
('software development', 'skills'),
('coding', 'skills'),
('c', 'skills'),
('c ', 'skills'),
('visual studio', 'skills'),
('2 years', 'experience'),
('c/c development', 'skills'),
('data compression', 'skills'),
('financial markets', 'skills'),
('financial calculation', 'skills'),
('gui design', 'skills'),
('windows development', 'skills'),
('mfc', 'skills'),
('win', 'skills'),
('http', 'skills'),
('tcp/ip', 'skills'),
('sockets', 'skills'),
('network programming', 'skills'),
('system administration', 'skills')]
我们现在准备好预测关系了;首先加载关系提取模型,务必将目录改为 rel_component/scripts 以便可以访问关系模型的所有必要脚本。
cd rel_component/
import random
import typer
from pathlib import path
import spacy
from spacy.tokens import docbin, doc
from spacy.training.example import example
#使factory生效
from rel_pipe import make_relation_extractor, score_relations
#使config生效
from rel_model import create_relation_model, create_classification_layer, create_instances, create_tensors
#安装完依赖项后重启运行时
nlp2 = spacy.load("/content/drive/mydrive/training_rel_roberta/model-best")
def extract_relations(documents,nlp,nlp2):
predicted_rels = list()
for doc in nlp.pipe(documents, disable=["tagger", "parser"]):
source_hash = hashlib.sha256(doc.text.encode('utf-8')).hexdigest()
for name, proc in nlp2.pipeline:
doc = proc(doc)
for value, rel_dict in doc._.rel.items():
for e in doc.ents:
for b in doc.ents:
if e.start == value[0] and b.start == value[1]:
max_key = max(rel_dict, key=rel_dict. get)
#print(max_key)
e_id = hashlib.sha256(str(e).encode('utf-8')).hexdigest()
b_id = hashlib.sha256(str(b).encode('utf-8')).hexdigest()
if rel_dict[max_key] >=0.9 :
#print(f" entities: {e.text, b.text} --> predicted relation: {rel_dict}")
predicted_rels.append({'head': e_id, 'tail': b_id, 'type':max_key, 'source': source_hash})
return predicted_rels
predicted_rels = extract_relations(documents,nlp,nlp2)
predicted relations:
entities: ('5 years', 'software engineering') --> predicted relation: {'degree_in': 9.5471655e-08, 'experience_in': 0.9967771}
entities: ('5 years', 'technical management') --> predicted relation: {'degree_in': 1.1285037e-07, 'experience_in': 0.9961034} entities: ('5 years', 'designing') --> predicted relation:{'degree_in': 1.3603304e-08, 'experience_in': 0.9989103}
entities: ('4 years', 'performance management') --> predicted relation: {'degree_in': 6.748373e-08, 'experience_in': 0.92884386}
现在,我们可以加载职位数据集,并将数据提取到 neo4j 数据库中了。
首先,我们创建一个,并添加连接信息,如下所示:
documents = get_all_documents()
documents = documents[:]
parsed_ents = extract_ents(documents,nlp)
predicted_rels = extract_relations(documents,nlp,nlp2)
#neo4j的基础查询功能
from neo4j import graphdatabase
import pandas as pd
host = 'bolt://[your_host_address]'
user = 'neo4j'
password = '[your_password]'
driver = graphdatabase.driver(host,auth=(user, password))
def neo4j_query(query, params=none):
with driver.session() as session:
result = session.run(query, params)
return pd.dataframe([r.values() for r in result], columns=result.keys())
接下来,我们将文档、实体和关系添加到知识图谱中。注意,我们需要从实体 experience 的 name 中提取出整数年限,并将其作为一个属性存储起来。
#清空当前的neo4j sandbox db (删除所有东西)
neo4j_query("""
match (n) detach delete n;
""")
#创建第一个主节点
neo4j_query("""
merge (l:labormarket {name:"labor market"})
return l
""")
#向kg中添加实体:技能、经验、学历、专业
neo4j_query("""
match (l:labormarket)
unwind $data as row
merge (o:offer{id:row.text_sha256})
set o.text = row.text
merge (l)-[:has_offer]->(o)
with o, row.annotations as entities
unwind entities as entity
merge (e:entity {id:entity.id})
on create set
e.name = entity.text,
e.label = entity.label_upper
merge (o)-[m:mentions]->(e)
on create set m.count = 1
on match set m.count = m.count 1
with e as e
call apoc.create.addlabels( id(e), [ e.label ] )
yield node
remove node.label
return node
""", {'data': parsed_ents})
#为实体experience添加属性'name'
res = neo4j_query("""
match (e:experience)
return e.id as id, e.name as name
""")
#从experience name中提取工作年限,并保存在属性years中
import re
def get_years(name):
return re.findall(r"\d ",name)[0]
res["years"] = res.name.map(lambda name: get_years(name))
data = res.to_dict('records')
#为实体experience添加属性'years'
neo4j_query("""
unwind $data as row
match (e:experience {id:row.id})
set e.years = row.years
return e.name as name, e.years as years
""",{"data":data})
#将关系添加到kg
neo4j_query("""
unwind $data as row
match (source:entity {id: row.head})
match (target:entity {id: row.tail})
match (offer:offer {id: row.source})
merge (source)-[:rel]->(r:relation {type: row.type})-[:rel]->(target)
merge (offer)-[:mentions]->(r)
""", {'data': predicted_rels})
现在开始进入有趣的部分了。我们可以启动知识图谱并运行查询了。让我们运行一个查询,找出与目标简历最匹配的职位:
#在表中显示最佳匹配项
other_id = "8de6e42ddfbc2a8bd7008d93516c57e50fa815e64e387eb2fc7a27000ae904b6"
query = """
match (o1:offer {id:$id})-[m1:mentions]->(s:entity)<- [m2:mentions]-(o2:offer)
return distinct o1.id as source,o2.id as proposed_offer, count(*) as freq, collect(s.name) as common_terms
order by freq
desc limit $limit
"""
res = neo4j_query(query,{"id":other_id,"limit":3})
res
#在neo4j浏览器中,使用该查询显示最佳匹配项的图
"""match (o1:offer {id:"8de6e42ddfbc2a8bd7008d93516c57e50fa815e64e387eb2fc7a27000ae904b6"})-[m1:mentions]->(s:entity)<- [m2:mentions]-(o2:offer)
with o1,s,o2, count(*) as freq
match (o1)--(s)
return collect(o2)[0], o1,s, max(freq)"""
以表格形式显示的结果中的公共实体:
以可视化形式显示的图:
虽然这个数据集只有 29 个职位描述,但这里介绍的方法可以应用于有成千上万个职位的大规模数据集。只需几行代码,我们立马就可以提取出与目标简历匹配度最高的工作。
下面,让我们找出最需要的技能:
query = """
match (s:skills)<-[:mentions]-(o:offer)
return s.name as skill, count(o) as freq
order by freq desc
limit 10
"""
res = neo4j_query(query)
res
以及需要最高工作年限的技能:
query = """
match (s:skills)--(r:relation)--(e:experience) where r.type = "experience_in"
return s.name as skill,e.years as years
order by years desc
limit 10
"""
res = neo4j_query(query)
res
web 开发和金马国际的技术支持需要的工作年限最高,然后是安全设置。
最后,让我们查下共现率最高的技能对:
neo4j_query("""
match (s1:skills)<-[:mentions]-(:offer)-[:mentions]->(s2:skills)
where id(s1) < id(s2)
return s1.name as skill1, s2.name as skill2, count(*) as cooccurrence
order by cooccurrence
desc limit 5
""")
在这篇文章中,我们描述了如何利用基于转换器的 ner 和 spacy 的关系提取模型,用 neo4j 创建知识图谱。除了信息提取之外,图的拓扑结构还可以作为其他机器学习模型的输入。
将 nlp 与图数据库 neo4j 相结合,可以加速许多领域的信息发现,相比之下,在医疗和生物医学领域的应用效果更为显著。
如果你有任何问题或希望为具体用例创建自定义模型,请给我们发邮件(admin@ubiai.tools),或是在 twitter 上给我们留言()。
原文链接:
更多内容推荐
lightbend最近推出了kalix,这是一种新的paas产品,用于使用任何编程语言构建无数据库的云原生业务关键型应用程序。
企业要想重塑数据洞察,一定要做到数智融合,将数据(大数据技术)和智能(机器学习技术)进行融合和统一。
由于 rdma 技术在数据中心领域的广泛使用,龙蜥社区高性能网络 sig 认为 smc-r 将成为下一代数据中心内核协议栈的重要方向之一。
中国卓越技术团队访谈录(2022 年第一季)
《中国卓越技术团队访谈录》是 infoq 打造的重磅内容产品,以各个国内优秀企业的 it 技术团队为线索策划系列采访,希望向外界传递杰出技术团队的做事方法 / 技术实践,让开发者了解他们的知识积累、技术演进、产品锤炼与团队文化等,并从中获得有价值的见解。
最近几年,开源在全球蓬勃发展:一方面,越来越多人投身于开源生态中,除了开发者,不懂代码的人也能为开源社区做贡献;另一方面,开源贡献的形式更多元,不再拘泥于写代码,文档贡献、开源布道也是建设开源生态的重要动作。
如何使用 neo4j 和 transformer 构建知识图谱
本文将展示如何使用经过优化的、基于转换器的命名实体识别(ner)以及spacy的关系提取模型,基于职位描述创建一个知识图谱。
知道这些表现,你才能在自己的程序员职业生涯中不犯相同的错误。
目前,小马智行和文远知行的估值在国内 robotaxi 自动驾驶公司排名前二。
像万花筒一样千变万化、快速搭建的爱奇艺低代码引擎的技术核心是什么?
英伟达正式宣布开源 gpu 内核模块代码
目前该项目已经收获 7.7k star,众多网友对本次开源纷纷表示难以置信。
企业出海要增长,业务如何步入“快车道”?
在全球化浪潮跌宕起伏、国内流量红利逐渐消失的背景下,进军海外市场成为越来越多国内企业的新选择。
大量开源仓库被关闭,必须先审核再上线,gitee:无奈之举
波士顿动力机器狗又调皮了。
首次揭秘,字节跳动数据平台为什么不选“纯中台制”
“规模尺度每增大十倍,很多架构设计点都需要再重新调整”。
推荐阅读
电子书
大厂实战ppt下载
吴小伟 | 杭州端点网络科技有限公司 合伙人兼资深技术专家
王杰西 | 字节跳动 资深视频算法工程师
冯斌 | 深圳复临科技有限公司(ones) 联合创始人兼cto
评论