123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- '''
- 根据标签和类型来查找对应的符合条件的人、企业、职位
- '''
- from flask import current_app
- from configs.connections import connect_graph
- def similar_seeker(label):
- try:
- query = """
- WITH $Label AS target_labels
- UNWIND target_labels AS target_label
- MATCH (jl:seekerLabel)
- WITH target_label, jl, apoc.text.distance(target_label, jl.name) AS distance
- WITH target_label, jl, 1.0 / (1.0 + distance) AS similarity
- WHERE similarity > 0.5
- WITH target_label, jl, similarity
- MATCH (j:seeker)-[:connection]->(jl)
- WITH j, similarity
- ORDER BY similarity DESC
- WITH DISTINCT j, similarity
- RETURN j.uniqueId AS ids_list
- ORDER BY similarity DESC
- """
- result = connect_graph.run(query, Label=label)
- if result:
- return [record['ids_list'] for record in result] # 提取所有 uniqueId
- else:
- return []
- except Exception as e:
- current_app.logger.error(f'similar_seeker error: {e}')
- return str(e)
- def draw_graph():
- try:
- # 先判断图谱中是否存在投影图,不存在直接drop会报错
- create_query = """CALL gds.graph.exists('jobGraph') YIELD exists
- RETURN CASE exists WHEN true THEN 1 ELSE 0 END as graphExists"""
- result = connect_graph.run(create_query).evaluate()
- if result == 0:
- create_query = """
- // 创建图投影
- CALL gds.graph.project(
- 'jobGraph',
- ['job', 'jobLabel'],
- {
- r: {
- type: 'connection',
- orientation: 'UNDIRECTED'
- }
- }
- )
- """
- connect_graph.run(create_query)
- except Exception as e:
- current_app.logger.error(f'draw_graph error: {e}')
- return str(e)
- # 职位详情推荐类似的职位
- def similar_job(uniqueid,start,end):
- try:
- if uniqueid:
- query = f"""
- // 计算 Jaccard 相似度
- CALL gds.nodeSimilarity.stream('jobGraph', {{
- similarityCutoff: 0.0,
- topK: 10
- }})
- YIELD node1, node2, similarity
- WITH gds.util.asNode(node1) AS node1, gds.util.asNode(node2) AS node2, similarity
- WHERE node1.uniqueId = $Id AND node2.uniqueId <> $Id
- WITH node2.uniqueId AS job_id, node2.name AS job_name, similarity
- ORDER BY similarity DESC
- // 返回最相似的 job 节点
- //with count(job_id) as total,collect(job_id) as job_ids
- with collect(job_id) as job_ids
- return job_ids[{start}..{end}] as jobIds
- """
- result = connect_graph.run(query, Id=uniqueid).evaluate()
- if result:
- need_list = default_job()
- return result + need_list[:10 - len(result)]
- else:
- return default_job()
- else:
- return default_job()
- except Exception as e:
- current_app.logger.error(f'similar_job error: {e}')
- return default_job()
- # 职位详情推荐类似的职位
- def home_job(uniqueid,start,end):
- try:
- if uniqueid:
- query = f"""
- // 1. 使用索引查找 seeker 节点
- MATCH (s:seeker {{uniqueId: $Id}})-[:connection]->(sl:seekerLabel)
-
- // 2. 获取 jobLabel 节点并提前过滤
- WITH s, sl
- MATCH (jl:jobLabel)
- WHERE jl.name STARTS WITH sl.name OR sl.name STARTS WITH jl.name // 进一步过滤
-
- // 3. 计算jobLabel 和 seekerLabel 之间的 Levenshtein 距离
- WITH s, sl, jl, apoc.text.levenshteinDistance(jl.name, sl.name) AS distance
-
- // 4. 找到距离最小的 jobLabel
- ORDER BY distance ASC
- WITH s, sl, collect({{jl: jl, distance: distance}}) AS jobLabels
- WITH s, sl, jobLabels[0].jl AS closestJl, jobLabels[0].distance AS min_distance
-
- // 5. 获取 job 节点
- MATCH (j:job)-[:connection]->(closestJl)
-
- // 6. 返回 job 的 id,并限制结果数量
- WITH s, toString(j.uniqueId) AS jobId
- with collect(DISTINCT jobId) AS jobIds
- RETURN jobIds[{start}..{end}] AS jobIds
- """
- result = connect_graph.run(query,Id = uniqueid).evaluate()
- if result:
- need_list = default_job()
- return result + need_list[:10-len(result)]
- else:
- return default_job()
- else:
- return default_job()
- except Exception as e:
- current_app.logger.error(f'home_job error: {e}')
- return default_job()
- def default_job():
- try:
- query = """
- MATCH (n:job)-[r:connection]-(m:jobLabel)
- WITH n, COUNT(m) AS num_connections
- ORDER BY num_connections DESC
- LIMIT 10
- RETURN collect(n.uniqueId) AS job_ids
- """
- result = connect_graph.run(query).evaluate()
- return result
- except Exception as e:
- current_app.logger.error(f'default_job error: {e}')
- return []
- def draw_person_graph():
- try:
- # 先判断图谱中是否存在投影图,不存在直接drop会报错
- create_query = """CALL gds.graph.exists('personGraph') YIELD exists
- RETURN CASE exists WHEN true THEN 1 ELSE 0 END as graphExists"""
- result = connect_graph.run(create_query).evaluate()
- if result == 0:
- create_query = """
- // 创建图投影
- CALL gds.graph.project(
- 'personGraph',
- ['seeker', 'seekerLabel'],
- {
- r: {
- type: 'connection',
- orientation: 'UNDIRECTED'
- }
- }
- )
- """
- connect_graph.run(create_query)
- except Exception as e:
- current_app.logger.error(f'draw_graph error: {e}')
- return str(e)
- def home_person(uniqueid,start,end):
- try:
- if uniqueid:
- query = f"""
- // 1. 使用索引查找 job 节点
- MATCH (j:job {{uniqueId: $Id}})-[:connection]->(jl:jobLabel)
-
- // 2. 获取 seekerLabel 节点并提前过滤
- WITH j, jl
- MATCH (sl:seekerLabel)
- WHERE sl.name STARTS WITH jl.name OR jl.name STARTS WITH sl.name // 进一步过滤
-
- // 3. 计算jobLabel 和 seekerLabel 之间的 Levenshtein 距离
- WITH j, jl, sl, apoc.text.levenshteinDistance(jl.name, sl.name) AS distance
-
- // 4. 找到距离最小的 seekerLabel
- ORDER BY distance ASC
- WITH j, jl, collect({{sl: sl, distance: distance}}) AS seekerLabels
- WITH j, jl, seekerLabels[0].sl AS closestSl, seekerLabels[0].distance AS min_distance
-
- // 5. 获取 seeker 节点
- MATCH (s:seeker)-[:connection]->(closestSl)
-
- // 6. 返回 seeker 的 id,并限制结果数量
- WITH j, toString(s.uniqueId) AS seekerId
- with collect(DISTINCT seekerId) AS seekerIds
- RETURN seekerIds[{start}..{end}] AS seekerIds
- """
- result = connect_graph.run(query,Id = uniqueid).evaluate()
- if result:
- need_list = default_person()
- return result + need_list[:10 - len(result)]
- else:
- return default_person()
- else:
- return default_person()
- except Exception as e:
- current_app.logger.error(f'home_job error: {e}')
- return default_person()
- def default_person():
- try:
- query = """
- MATCH (n:seeker)-[r:connection]-(m:seekerLabel)
- WITH n, COUNT(m) AS num_connections
- ORDER BY num_connections DESC
- LIMIT 10
- RETURN collect(n.uniqueId) AS seeker_ids
- """
- result = connect_graph.run(query).evaluate()
- return result
- except Exception as e:
- current_app.logger.error(f'default_person error: {e}')
- return []
|