如何提高架构的稳定性、可扩展性和易用性等能力?点击看大咖分享
写点什么

如何使用neo4j和transformer构建知识图谱-金马国际

  • 2022 年 3 月 21 日
  • 本文字数:4765 字

    阅读完需:约 16 分钟

本文最初发布于 towards data science。


图片由作者提供:neo4j中的知识图谱


在这篇文章中,我将展示如何使用经过优化的、基于转换器的命名实体识别(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 transformersimport spacy#安装完依赖项后重启运行时nlp = spacy.load("[path_to_the_model]/model-best")
复制代码


加载我们想从中提取实体和关系的职位数据集:


import pandas as pddef get_all_documents():df = pd.read_csv("/content/drive/mydrive/job_db1_1_29.csv",sep='"',header=none)documents = []for index,row in df.iterrows():documents.append(str(row[0]))return documentsdocuments = get_all_documents()documents = documents[:]
复制代码


从职位数据集中提取实体:


import hashlibdef 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 docsparsed_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 randomimport typerfrom pathlib import pathimport spacyfrom spacy.tokens import docbin, docfrom 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_relspredicted_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 graphdatabaseimport pandas as pdhost = '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 rowmerge (o:offer{id:row.text_sha256})set o.text = row.textmerge (l)-[:has_offer]->(o)with o, row.annotations as entitiesunwind entities as entitymerge (e:entity {id:entity.id})on create set e.name = entity.text, e.label = entity.label_uppermerge (o)-[m:mentions]->(e)on create set m.count = 1on match set m.count = m.count   1with e as ecall apoc.create.addlabels( id(e), [ e.label ] )yield noderemove node.labelreturn 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 redef 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 rowmatch (e:experience {id:row.id})set e.years = row.yearsreturn e.name as name, e.years as years""",{"data":data})#将关系添加到kgneo4j_query("""unwind $data as rowmatch (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_termsorder by freqdesc 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 freqmatch (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 freqorder by freq desclimit 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 yearsorder by years desclimit 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 cooccurrenceorder by cooccurrencedesc limit 5""")
复制代码



在这篇文章中,我们描述了如何利用基于转换器的 ner 和 spacy 的关系提取模型,用 neo4j 创建知识图谱。除了信息提取之外,图的拓扑结构还可以作为其他机器学习模型的输入。


将 nlp 与图数据库 neo4j 相结合,可以加速许多领域的信息发现,相比之下,在医疗和生物医学领域的应用效果更为显著。


如果你有任何问题或希望为具体用例创建自定义模型,请给我们发邮件(admin@ubiai.tools),或是在 twitter 上给我们留言()。


原文链接:

2022 年 3 月 21 日 15:201910

评论

发布
暂无评论
发现更多内容

“芯”有灵“蜥” 走进 intel meetup

“芯”有灵“蜥” 走进 intel meetup

网站地图