''' 根据标签和类型来查找对应的符合条件的人、企业、职位 ''' 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 return total,job_ids[{start}..{end}] as jobIds """ result = connect_graph.run(query, Id=uniqueid).data() if result: total = result[0]['total'] jobIds = result[0]['jobIds'] return jobIds, total else: total = 10 return default_job(), total else: return default_job(),10 except Exception as e: current_app.logger.error(f'similar_job error: {e}') return default_job(),10 # 职位详情推荐类似的职位 def home_job(uniqueid,start,end): try: if uniqueid: query = f""" // 1. 查找 seeker 节点 MATCH (s:seeker {{uniqueId: $Id}}) // 2. 获取 seekerLabel 节点 WITH s MATCH (s)-[:connection]->(sl:seekerLabel) // 3. 获取 jobLabel 节点 WITH s, sl MATCH (jl:jobLabel) // 4. 计算 seekerLabel 和 jobLabel 之间的 Levenshtein 距离 WITH s, sl, jl, apoc.text.levenshteinDistance(sl.name, jl.name) AS distance // 5. 找到距离最小的 jobLabel WITH s, sl, jl, distance ORDER BY distance ASC WITH s, sl, collect({{jl: jl, distance: distance}}) AS jobLabels WITH s, sl, jobLabels, min(jobLabels[0].distance) AS min_distance UNWIND jobLabels AS jl_with_distance WITH s, sl, jl_with_distance.jl AS jl, jl_with_distance.distance AS distance, min_distance WHERE distance <= min_distance // 6. 获取 job 节点 WITH s, sl, jl MATCH (j:job)-[:connection]->(jl) // 7. 返回 job 的 id 和总数 WITH s, j.uniqueId AS jobId WITH count(DISTINCT jobId) AS total, collect(DISTINCT jobId) AS jobIds RETURN total, jobIds[{start}..{end}] AS jobIds """ result = connect_graph.run(query,Id = uniqueid).data() if result: total = result[0]['total'] jobIds = result[0]['jobIds'] return jobIds, total else: total = 10 return default_job(),total else: return default_job(),10 except Exception as e: current_app.logger.error(f'home_job error: {e}') return default_job(),10 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 []