基于Neo4j构建的外贸企业关系图谱做企业相似度查询「建议收藏」

基于Neo4j构建的外贸企业关系图谱做企业相似度查询「建议收藏」基于Neo4j的外贸企业关系图谱做企业相似度查询一、外贸企业关系图谱的构建1.从Oracle导出数据2.导入数据到Neo4j3.Neo4j数据展示二、用Cypher做企业关联查询1.多层关系查询2.基于邻居信息的Jaccard相似度计算3.加权关联度得分计算三、总结一、外贸企业关系图谱的构建说来惭愧,本科、研究生期间还没写过博客,正巧最近在写论文,想结合自己开发的项目来构思,于是就通过这篇博客记录一下使用Neo4j图数据库来做企业相似度查询的过程,方便以后参考。这次外贸企业关系图谱的构建用到以前项目中

大家好,又见面了,我是你们的朋友全栈君。

一、外贸企业关系图谱的构建

说来惭愧,本科、研究生期间还没写过博客,正巧最近在写论文,想结合自己开发的项目来构思,于是就通过这篇博客记录一下使用Neo4j图数据库来做企业相似度查询的过程,方便以后参考。
这次外贸企业关系图谱的构建用到以前项目中测试库(Oracle)的数据,导入成csv格式后,再通过python的py2neo导入到neo4j中。
———–由于数据涉及项目的私密信息,暂时就不分享出来了————

1.从Oracle导出数据

该表在Oracle数据库中的部分结构如下:
在这里插入图片描述
目前数据库中的外贸企业数据约30多万条,经过两轮的数据清洗和过滤,我选出了约12万条数据导出,并保存为csv格式。

2.导入数据到Neo4j

Neo4j有自己的csv导入工具,还可以通过cypher语句导入csv格式的数据,但是这里我使用的是pyhon的py2neo库来完成数据的导入。
编写的python代码结构如下:
在这里插入图片描述
下面介绍每个函数的详细代码实现:

'''初始化,用于连接到Neo4j'''
def __init__(self, data):
    self.data = data
    self.g = Graph(
        host="127.0.0.1",  # neo4j 搭载服务器的ip地址
        http_port=7474,  # neo4j 服务器监听的端口号
        user="neo4j",  # 数据库user name
        password="112233") # 密码
'''读取文件'''
def read_nodes(self):
# 共5类节点
enterprise = self.data['COMP_NAME_CH']  # 企业
region = set(self.data['PROVINCE_CH'])  # 地区
if (np.nan in region):
region.remove(np.nan)
country = []  # 出口国家
for index, row in self.data.iterrows():
for r in row['EXPORT_COUNTRY_MXT'].split(','):
country.append(r)
# 企业类型:1-manufacture-生产型、2-trader-贸易型(贸信通)3-服务型
enterprise_type = ['生产型', '贸易型', '服务型']  # 企业类型
legal_representative = self.data['LEGAL_REPRESENTATIVE']  # 法人代表
# 构建节点实体关系
rels_region = []  # 企业-地区关系 locate
rels_country = []  # 企业-出口国家关系 export
rels_type = []  # 企业-企业类型关系 type
# rels_product = [] # 企业-产品关系 product
rels_legal = []  # 企业-法人代表关系 legal
for index, row in self.data.iterrows():
if (row['PROVINCE_CH'] is not np.nan):
rels_region.append([row['COMP_NAME_CH'], row['PROVINCE_CH']])
for r in row['EXPORT_COUNTRY_MXT'].split(','):
# 一个企业有多个出口国家
rels_country.append([row['COMP_NAME_CH'], r])
rels_type.append([row['COMP_NAME_CH'], '生产型' if row['COMP_TYPE'] == 1\
else ('服务型' if row['COMP_TYPE'] == 2 else '贸易型')])
rels_legal.append([row['COMP_NAME_CH'], row['LEGAL_REPRESENTATIVE']])
return set(enterprise), set(region), set(country), set(enterprise_type), set(legal_representative), \
rels_region, rels_country, rels_type, rels_legal
'''建立单标签节点'''
def create_node(self, label, nodes):
count = 0
for node_name in nodes:
node = Node(label, name=node_name)
self.g.create(node)
count += 1
print(count, len(nodes))
return
'''创建知识图谱外贸企业的节点'''
def create_enterprise_nodes(self):
count = 0
for index, row in self.data.iterrows():
node = Node("Enterprise", name=row['COMP_NAME_CH'], credit_code=row['CREDIT_CODE'],
setup_time=row['SETUP_TIME'], address=row['ADDRESS_CH'],
captial=str(row['REG_CAPITAL']) + '万人民币')
self.g.create(node)
count += 1
print(count)
return
'''创建实体关联边'''
def create_relationship(self, start_node, end_node, edges, rel_type, rel_name):
count = 0
# 去重处理
set_edges = []
for edge in edges:
set_edges.append('###'.join(edge))
all = len(set(set_edges))
for edge in set(set_edges):
edge = edge.split('###')
p = edge[0]
q = edge[1]
query = "match(p:%s),(q:%s) where p.name='%s'and q.name='%s' create (p)-[rel:%s{name:'%s'}]->(q)" % (
start_node, end_node, p, q, rel_type, rel_name)
try:
self.g.run(query)
count += 1
print(rel_type, count, all)
except Exception as e:
print(e)
return
'''创建知识图谱实体节点类型schema'''
def create_graphnodes(self):
# 获取所有节点和关系
Enterprises, Regions, Countries, Enterprise_types, Legal_representatives, \
rels_region, rels_country, rels_type, rels_legal = self.read_nodes()
# 创建图数据库节点
self.create_enterprise_nodes() # 企业
self.create_node('Region', Regions) # 地区
print('地区:' + str(len(Regions)))
self.create_node('Country', Countries) # 出口国家
print('出口国家:' + str(len(Countries)))
self.create_node('Type', Enterprise_types)  #企业类型
print('企业类型:' + str(len(Enterprise_types)))
# 暂不需要使用该节点和关系
# self.create_node('Legal', Legal_representatives) # 法人代表
# print('法人代表:' + len(Legal_representatives))
return
'''创建实体关系边'''
def create_graphrels(self):
# 获取所有关系组
Enterprises, Regions, Countries, Enterprise_types, Legal_representatives, \
rels_region, rels_country, rels_type, rels_legal = self.read_nodes()
self.create_relationship('Enterprise', 'Region', rels_region, 'locate', '所在地区')
self.create_relationship('Enterprise', 'Country', rels_country, 'export', '出口')
self.create_relationship('Enterprise', 'Type', rels_type, 'type', '类型')
# 暂不需要导入该关系
# self.create_relationship('Enterprise', 'Legal', rels_legal, 'legal', '法人')

最后是main函数:

if __name__ == '__main__':
# 获取当前路径,并转换为正确格式
cur_dir = '/'.join(os.path.abspath(__file__).split('\\')[:-1])
data_path = cur_dir + '/TB_ENTERPRISEINFO_FUSE_BAK.csv'
print('read_csv from:' + data_path)
data = pd.read_csv(data_path)
# 创建实例
handler = EnterpriseGragh(data)
# 构建企业图谱的节点和关系
handler.create_graphnodes()
handler.create_graphrels()

3.Neo4j数据展示

大约运行了20多小时,终于成功在Neo4j构建好了外贸企业关系图谱,感觉应该是自己在代码优化上可能没有做好=_=||,如果使用Neo4j自带的工具感觉会快上不少。
数据库信息以及查询效果如下图所示:(一共4类节点,3种关系)
在这里插入图片描述

二、用Cypher做企业关联查询

简单查询就不打上来了,感觉有一定参考意义有以下几种查询,可以找到和查询企业关联度最高的企业,作为查询结果。

1.多层关系查询

由于该图数据的有向关系只有一层,所以查询时不能指定关系的方向,这里我们以‘陕西和沃进出口有限公司’为例,查询该企业的多层关系,查询结果如下图:
在这里插入图片描述
对应的Cypher查询语句如下:

match p=(n:Enterprise{name:'陕西和沃进出口有限公司'})-[*2..3]-() return p limit 20

2.基于邻居信息的Jaccard相似度计算

以查询‘陕西和沃进出口有限公司’为例,根据企业的出口国家,计算企业之间的Jaccard相似度,作为相似度衡量标准。(由于Jaccard计算以出口国家关系为基准,所以结果与3.加权关联度得分计算得到的结果不同)
Jaccard的计算公式参考如下:
在这里插入图片描述
根据计算公式,查询到的结果展示如下:
在这里插入图片描述
对应的Cypher查询语句如下:

MATCH (n:Enterprise{name:'陕西和沃进出口有限公司'})-[:export]->(c:Country)<-[:export]-(other:Enterprise)
with n,other,count(c) as intersection,collect(c.name) as collection
match (n)-[:export]->(nc:Country)
with n,other,intersection,collection,collect(nc.name) as s1
match (other)-[:export]->(oc:Country)
with n,other,intersection,collection,s1,collect(oc.name) as s2
with n,other,intersection,s1,s2
with n,other,intersection,s1+filter(x IN s2 where not x IN s1) as uni,s1,s2
return n.name,other.name,s1,s2,((1.0*intersection)/SIZE(uni)) as jaccard
order by jaccard DESC
limit 20

3.加权关联度得分计算

以查询‘陕西和沃进出口有限公司’为例,找到和该企业有相同关系的节点,我们对三种关系企业类型、所在地区、出口国家(type、locate、export)进行加权求和并计算得分,以该得分作为企业相似度的评价标准,可以得到最相关的企业如下。
在这里插入图片描述
对应的Cypher查询语句如下:

MATCH (n:Enterprise) where n.name='陕西和沃进出口有限公司'
match (n)-[:type]->(t:Type)<-[:type]-(other:Enterprise)
with n,other,count(t) as tn
optional match (n)-[:locate]->(r:Region)<-[:locate]-(other)
with n,other,tn,count(r) as rn
optional match (n)-[:export]->(c:Country)<-[:export]-(other)
with n,other,tn,rn,count(c) as cn
return other.name as 推荐企业,tn as 相同企业类型,rn as 相同地区,cn as 相同出口国家,(3*tn)+(3*rn)+(1*cn) as score
ORDER BY score DESC
limit 100

三、总结

以上就是外贸企业关系图谱的构建+查询的整个流程,比较基础。

个人认为可以应用和研究的方向:企业合作伙伴发现、相似企业推荐、投资风险预测、企业市场预测等场景。

看起来像是那么回事奥,但是其实现在论文还没动笔。。。
希望能尽早确定好论文方向,加油!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/153327.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • JS转换HTML转义符

    JS转换HTML转义符//去掉html标签functionremoveHtmlTab(tab){returntab.replace(/]+?>/g,'');//删除所有HTML标签}//普通字

  • cocos2d-x for android:士兵听我的命令移动

    cocos2d-x for android:士兵听我的命令移动

  • android .dex文件探究

    android .dex文件探究在我们写Java代码的时候,生成的文件是.java文件,但是JVM并不识别这个,所以会先转成class文件,而在Android端,Android上的Davlik虚拟机能运行.dex。所以dex文件中包含了所有的app代码,可利用反编译工具获取java代码。即dex文件就是AndroidDalvik虚拟机运行的程序。为了能够加深印象,我们先构造一个dex文件。publicclassDEX…

  • sigaction函数和signal函数

    sigaction函数和signal函数signal和sigaction的区别:signal都是指以前的oldersignal函数,现在大多系统都用sigaction重新实现了signal函数。1.      signal在调用handler之前先把信号的handler指针恢复;sigaction调用之后不会恢复handler指针,直到再次调用sigaction修改handler指针。这样,signal就会丢失信号,而且不能处

  • html表格居中代码怎么写_html代码大全(很全的)

    html表格居中代码怎么写_html代码大全(很全的)<table align=”center”> </table>

  • 差分数组技巧

    差分数组技巧一、差分数组适用题型,和技巧前缀和数组:适用于原始数组不会被修改的情况下,频繁查询某个区间的累加和差分数组:主要适⽤场景是频繁对原始数组的某个区间的元素进⾏增减(比如:给你和数组arr,然后再下标0-4之间各元素加一,2-5之间各个元素减2,求最终的原数组)差分数组技巧1.构建差分数组(diff),diff[0]=nums[0],之后diff[i]=nums[i]-nums[i-1]int[]diff=newint[nums.length];//构造差分数组diff[0]=n

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号