def recommendUniversityAndCompany(town_id=None, uni_id=None, limit=20, filter_company=""): """ 针对给定的地区和高校,推荐适合与高校合作的企业 :param town_id: int 区镇id, 若 town_id==0 表示全部区镇 :param uni_id: String, eg: "123,456,345" :param limit: :param filter_company: String, 需要排除在外的企业id, 字符串类型,以英文逗号分割, eg: "123,4432,5,2354" :return: """ if town_id is None or town_id < 0: return public_service.returnResult(success=False, message="区镇选择不正确") if not uni_id or 0 == len(uni_id): return public_service.returnResult(success=False, message="高校不能为空") try: filter_list = [] if filter_company and len(filter_company) > 0: filter_list = [int(com_id) for com_id in filter_company.split(",")] university_id = [int(u_id) for u_id in uni_id.split(",")] except BaseException as e: logging.error(e) return public_service.returnResult(success=False, message="传入参数格式不正确")
def recommendTeacherForCompany(company_id, university_id, team=True, limit=20): """ 向企业推荐适合于 某一高校合作的企业及对应团队 :param company_id: str类型,以 “,” 作为 分隔符, eg: "123,234,456" :param university_id: String, eg: "123,456,345" :param team: 是否团队 :param limit: 一次获取的数据量 :return: """ if not company_id or len(company_id) == 0: return public_service.returnResult(success=False, message="企业不能为空") if not university_id or len(university_id) == 0: return public_service.returnResult(success=False, message="高校不能为空") try: company_id = [int(com_id) for com_id in company_id.split(",")] university_id = [int(uni_id) for uni_id in university_id.split(",")] except BaseException as e: logging.error(e) return public_service.returnResult(success=False, message="传入参数格式不正确") data = recommend_dao.recommendTeacherForCompany( company_id=company_id, university_id=university_id, limit=limit, team=team) return formatResultOfRecommendTeacherForCompany(data=data, team=team)
def technicalFieldComparison(eid=None, tid=None, team=1): """ 获取技术领域对比数据 :return: { success: True or False, data:{ "xAxis": ["ipc1", "ipc2", ..., "ipcn"], "eData": [n,n-1, ..., 1], "tData": [1,2,..., n] }, message: xxx } """ if eid is None or tid is None: return public_service.returnResult(success=False, message="参数有误,e_id=%s, t_id=%s" % (eid, tid)) # data = detail_dao.getTechnicalFieldComparison(eid=eid, tid=tid, team=True if team == 1 else False) # data = transformTechnicalFieldComparisonData(data=data) # ==> [{ipc:xxx, patent:xxx}, ...]结果中包含重复数据,需要去重 teacher_patent = detail_dao.getTeamTechnicalFieldDistribute(team_id=tid, teacher=True) engineer_patent = detail_dao.getTeamTechnicalFieldDistribute(team_id=eid, teacher=False) data = formatTechnicalFieldComparisonData( teacher=countIPCDistribute(IPC_patent=teacher_patent, merge=True), engineer=countIPCDistribute(IPC_patent=engineer_patent, merge=True)) # if data is None: # return public_service.returnResult(success=False, message="从图数据库获取数据格式不正确") return public_service.returnResult(success=True, data=data)
def technicalFieldComparisonForRadar(eid=None, tid=None): """ 获取技术领域对比数据 :return: { success: True or False, data:{ "indicator": [ {"name": '销售(sales)', "max": 6500}, {"name": '管理(Administration)', "max": 16000}, ], "t_value": [4300, 10000, 28000, 35000, 50000, 19000], "e_value": [5000, 14000, 28000, 31000, 42000, 21000], }, message: xxx } """ if eid is None or tid is None: return public_service.returnResult(success=False, message="参数有误,e_id=%s, t_id=%s" % (eid, tid)) # ==> [{ipc:xxx, patent:xxx}, ...]结果中包含重复数据,需要去重 teacher_patent = detail_dao.getTeamTechnicalFieldDistribute(team_id=tid, teacher=True) engineer_patent = detail_dao.getTeamTechnicalFieldDistribute(team_id=eid, teacher=False) data = formatFieldComparisonDataForRadar( teacher=formatIPC_PatentRelation(teacher_patent), engineer=formatIPC_PatentRelation(engineer_patent)) # if data is None: # return public_service.returnResult(success=False, message="从图数据库获取数据格式不正确") return public_service.returnResult(success=True, data=data)
def recommendResult(uni_id="", teacher_id=None, town_id=None, com_id="", limit=20): """ 根据传入参数的不同组合,调用不同的处理部分, 返回统一格式的推荐结果 :param uni_id: 高校id, str eg: "123,2343" :param teacher_id: 专家id, str, eg: "3224,3435" :param town_id: 区镇id, str, eg: "324,435" :param com_id: 企业id, str类型,多个企业id之间以 , 分割, eg:”123,234,345“ :param limit: :return: { success: True or False data: { # 此处使用二维数组存储 nodes, len(nodes) 表示共有多少列节点, len(nodes[i]) 表示 第 i 列有多少节点 nodes:[[{node prop}], [...], ...] links: [{source: xx, target:xxx, others: xxx}, ...] category: [{name: xxx}] } } """ if not isinstance(uni_id, str) or 0 == len(uni_id): return public_service.returnResult(success=False, message="高校值不正确") if not isinstance(town_id, str) or 0 == len(town_id): return public_service.returnResult(success=False, message="区镇值不正确") towns = [int(t_id) for t_id in town_id.split(",")] unis = [int(u_id) for u_id in uni_id.split(",")] if isinstance(com_id, str) and 0 < len(com_id) and isinstance( teacher_id, str) and 0 < len(teacher_id): # 指定企业 & 专家 # ==> 推荐 专家个人和 工程师团队 comps = [int(c_id) for c_id in com_id.split(",")] teachers = [int(t_id) for t_id in teacher_id.split(",")] return recommendEngineerAndTeacher(com_id=comps, uni_id=unis, teacher_id=teachers, limit=limit) elif isinstance(com_id, str) and 0 < len(com_id): # 指定高校 & 企业 # ==> 推荐企业工程师和高校专家 comps = [int(c_id) for c_id in com_id.split(",")] return recommend2Area_service.recommendEngineerAndTeacherTeam( com_id=comps, uni_id=unis, reverse=False, limit=limit) elif isinstance(teacher_id, str) and 0 < len(teacher_id): # 指定 专家 & 地区 # ===> 推荐 适合与专家合作的企业 # TODO return public_service.returnResult(success=False, message="未获取到数据") else: # 指定高校 & 地区 # ==> 推荐适合与当地企业合作的高校 return recommend2Area_service.recommendInstitutionAndCompany( town_id=towns, uni_id=unis, reverse=False, limit=limit)
def addContactInformation(agent_id=0, agent_type="area", target_id=0, target_type="engineer", visited=0, cooperate=0, activity=0): """ 创建/更新 中介与 专家/工程师之间的关系 :param agent_id: str 中介 id :param agent_type: str 中介类型 :area ==> Agent_Area or uni ==> Agent_University :param target_id: int 目标节点 id :param target_type: str 目标节点类型类型: teacher ==> Teacher or engineer ==> Engineer :param visited: int 拜访次数 :param cooperate: int 合作次数 :param activity: int 参与活动次数 :return : dict {success: True or False, message: xxx} """ agent_label = public_service.transformUser(user=agent_type) target_label = public_service.transformUser(user=target_type) if (not isinstance(target_id, int)) or target_id < 1 or target_label is None: return public_service.returnResult(success=False, message="目标节点参数不正确") start_node = neo4j.search_node(search_dict={ "label": agent_label, "search": { "id": agent_id } }) if start_node is None: return public_service.returnResult(success=False, message="用户信息有误") target_node = neo4j.search_node({ "label": target_label, "search": { "id": target_id } }) if target_node is None: return public_service.returnResult(success=False, message="目标节点信息有误") res = api_dao.addContactInformation(start_node=start_node, target_node=target_node, visited=visited, cooperate=cooperate, activity=activity) if res is False: return public_service.returnResult(success=False, message="创建/更新关系操作失败") return public_service.returnResult(success=True, message="操作成功")
def linkTargetBySocial(agent_id, agent_label, target_id, target_label, max_step=3, limit=5): """ 高校中介联络专家 or 地区中介联络工程师时, 通过社交关系获取联络路径 :param agent_id: str :param agent_label: str :param target_id: :param target_label: :param max_step: :param limit: :return: None or {success: True or False, data: None or {...}, message: xxx} """ path = path_dao.getLinkPath(agent_id=agent_id, agent_label=agent_label, target_id=target_id, target_label=target_label, step=max_step, limit=limit) if 0 == len(path): return None else: return public_service.returnResult( success=True, data=formatPath2Echarts(path_list=path))
def wordCloud(teamId, teacher=True): """ 根据团队id & 团队类型获取团队涉及行业的词云 :param teamId: 团队id , :param teacher: 是否是专家团队,布尔型。 :return: { success: True or False, message: xx, data: [ { name: xxx, value: 123 }, ... ] } """ # ==> [{ipc:xxx, patent:xxx, date: 1429142400}, ...]结果中包含重复数据,需要去重 ipc_patent_time = detail_dao.getTeamTechnicalFieldDistribute( team_id=teamId, teacher=teacher) ipc_patent = formatIPC_PatentRelation( ipc_patent_time) # {ipc: {p1,p2,...}, ...}\ # ==> [{code: xxxx, title: xxx, ipc: xx}, ...] industry_ipc = detail_dao.getIndustryIPC(ipc_patent.keys()) industry_title, ipc_industry = formatIPC_Industry(industry_ipc) # 统计每个行业下专利的数量 ==> {industry_code: {p1, p2, ...}, ...} industry_patent = countIndustryPatent(ipc_industry, ipc_patent) # ==> [["农药制造", 110], ....] res = [{ "name": industry_title[code], "value": len(patents) } for code, patents in industry_patent.items()] return public_service.returnResult(success=True, data=res)
def getLinkPath(agent_id=0, agent_type="area", target_id=0, target_type="engineer", max_step=3, limit=5): """ 获取两个节点之间的联络路径, 并格式化为 Echarts 关系图 可解析的数据格式 :param agent_id: int 中介 id :param agent_type: str 中介类型 :area ==> Agent_Area or uni ==> Agent_University :param target_id: int 目标节点 id :param target_type: str 目标节点类型类型: teacher ==> Teacher or engineer ==> Engineer :param max_step: int 路径最大长度 :param limit: int 路径数量 :return : {success: True or False, data: None or {...}, message: xxx} """ agent_label = public_service.transformUser(user=agent_type) if agent_label is None or not isinstance(agent_id, str) or len(agent_id) == 0: return public_service.returnResult(success=False, message="中介参数不正确") target_label = public_service.transformUser(user=target_type) if target_label is None or not isinstance(target_id, str) or len(target_id) == 0: return public_service.returnResult(success=False, message="目标节点参数不正确") if agent_label == LABEL["areaAGENT"] and target_label == LABEL["TEACHER"]: # 地区中介 联络 专家 return linkTeacherByPartner(agent_id=agent_id, teacher_id=target_id) if agent_label == LABEL["uniAGENT"] and target_label == LABEL["ENGINEER"]: # 高校中介联络工程师 return linkEngineerByPartner(agent_id=agent_id, engineer_id=target_id) social_path = linkTargetBySocial(agent_id=agent_id, agent_label=agent_label, target_id=target_id, target_label=target_label, max_step=max_step, limit=limit) if social_path is None: # 无法通过社交关系(如同事、朋友)等关系联系到目标 ==> 通过组织机构联系到目标 return linkTargetByOrg(agent_id=agent_id, agent_label=agent_label, target_id=target_id, target_label=target_label) return social_path
def linkTeacherByPartner(agent_id, teacher_id): """ 地区中介 通过 高校搭档联络到用户 :param agent_id: :param teacher_id: :return: {success=True or False, data={nodes, links}, message="xxx"} """ # ==> [{start, target, partner}] or [] path = path_dao.linkTeacherByPartner(agent_id=agent_id, teacher_id=teacher_id) if 0 == len(path): return public_service.returnResult(success=False, message="你在当前高校没有联络权限") return public_service.returnResult(success=True, data=generatePathWithPublicNode( start_node=path[0]["start"], target_node=path[0]["target"], agent_node=path[0]["partner"]))
def linkEngineerByPartner(agent_id, engineer_id): """ 高校中介月用户 通过 地区搭档联络到用户 :param agent_id: 技转中心用户id :param engineer_id: 目标工程师 id :return: {success=True or False, data={nodes, links}, message="xxx"} """ # ==> [{start, target, partner}] or [] path = path_dao.linkEngineerByPartner(agent_id=agent_id, engineer_id=engineer_id) if 0 == len(path): return public_service.returnResult(success=False, message="你在当前地区没有联络权限") return public_service.returnResult(success=True, data=generatePathWithPublicNode( start_node=path[0]["start"], target_node=path[0]["target"], agent_node=path[0]["partner"]))
def recommendTeacherForArea(area_id=None, uni_id=None, team=True, skip=0, limit=20, sort="", order="desc"): """ 向地区推荐适合于 某一高校合作的企业及对应团队 :param area_id: :param uni_id: String, eg: "123,456,345" :param team: 是够团队 :param skip: 偏移量 :param limit: 一次获取的数据量 :param sort: 用于排序的字段, 目前只根据 企业名 及 高校名 排序 :param order: 排序方式 asc or desc :return: """ if not area_id: return public_service.returnResult(success=False, message="找不到地区") if not uni_id or len(uni_id) == 0: return public_service.returnResult(success=False, message="找不到高校") try: uni_id_list = [int(uid) for uid in uni_id.split(",")] except BaseException as e: logging.error(e) return public_service.returnResult(success=False, message="参数格式不正确") sort = public_service.transformSort(sort, order) data = recommend_dao.recommendTeacherForArea(area_id=area_id, university_id=uni_id_list, team=team, sort=sort, skip=skip, limit=limit) total = recommend_dao.totalRecommendTeacherForArea( area_id=area_id, university_id=uni_id_list, team=team) total = 0 if len(total) == 0 else total[0]["total"] return public_service.returnResult(success=True, data=data, total=total, offset=skip, limit=limit, team=team)
def recommendUniversityForCompany(com_id, limit=20): """ 根据企业id, 为特定企业推荐 高校 :param com_id: list [2,3,4...] :param limit: :return: """ records = recommend2Area_dao.recommendUniversityForCompany( company_id=com_id, limit=limit) return public_service.returnResult( success=True, data=formatRecommendUniversityAndCompany(records))
def recommendEngineerAndTeacherTeam2(com_id, reverse=True, limit=20): """ 制定 高校 & 企业 推荐 专家团队 & 工程师团队 :param com_id: list, [] or [123,435...] :param reverse: True or False, 地区排列 与 高校排列 的顺序 :param limit: 一次获取的数据量 :return: """ records = recommend2Area_dao.recommendEngineerAndTeacherTeam2( com_id=com_id, limit=limit) return public_service.returnResult(success=True, data=formatRecommendEngineerAndTeacher( records=records, reverse=reverse))
def linkTargetByOrg(agent_id, agent_label, target_id, target_label): """ 通过 目标所属 学院 or 企业联络到目标的路径 :param agent_id: :param agent_label: :param target_id: :param target_label: :return: """ # ==> [{start, target, org}] or [] path = path_dao.linkTargetByOrg(agent_id=agent_id, agent_label=agent_label, target_id=target_id, target_label=target_label) if 0 == len(path): return public_service.returnResult(success=False, message="参数错误, 无法找到节点") return public_service.returnResult(success=True, data=generatePathWithPublicNode( start_node=path[0]["start"], target_node=path[0]["target"], agent_node=path[0]["org"]))
def recommendUniversityAndCompany(town_id=None, reverse=True, limit=20): """ 为特定区域内的企业 推荐 适合合作的高校 :param town_id: 整型 :param reverse: True or False, 地区排列 与 高校排列 的顺序 :param limit: :return: """ records = recommend2Area_dao.recommendUniversityAndCompany(town_id=town_id, limit=limit) return public_service.returnResult( success=True, data=formatRecommendUniversityAndCompany(records=records, reverse=reverse))
def recommendInstitutionAndCompany(town_id, uni_id, reverse=True, limit=20): """ 根据选定区域的id、 以及选定高校的id, 推荐地区企业 和 高校学院 :param town_id:list [2,3,4...] :param uni_id: :param reverse: True or False, 地区排列 与 高校排列 的顺序 :param limit: :return: """ records = recommend2Area_dao.recommendInstitutionAndCompany( town_id=town_id, uni_id=uni_id, limit=limit) return public_service.returnResult( success=True, data=formatRecommendInstitutionAndCompany(records, reverse=reverse))
def recommendEngineerAndTeacher(com_id, uni_id, teacher_id, limit=20): """ 指定企业 & 专家,推荐 专家和 工程师团队 :param com_id: list [12,34,3] :param uni_id: list [23,543] :param teacher_id: [234,453, 435] :param limit: :return: """ records = recommend2University_dao.recommendEngineerAndTeacher( com_id=com_id, uni_id=uni_id, teacher_id=teacher_id, limit=limit) return public_service.returnResult( success=True, data=recommend2Area_service.formatRecommendEngineerAndTeacher( records=records, reverse=False))
def getPersonalNetwork(agent_id, agent_type=0): """ 获取中介的个人中心网络 :param agent_id: :param agent_type: 中介类型: area ==> Agent_Area or uni ==> Agent_University :return: [{s_id, s_name, t_id, t_name, org_id, org_name}] """ agent_type = public_service.transformUser(user=agent_type) # if (not isinstance(agent_id, int)) or agent_id <= 0 or agent_type is None: # return public_service.returnResult(success=False, message="参数不正确") agent = personal_dao.getAgentNode(agent_id=agent_id, agent_type=agent_type) if not agent or 0 == len(agent): return public_service.returnResult(success=False, message="id有误, 查无此人") work_network = personal_dao.getAgentPartnerRelation(agent_id=agent_id, agent_type=agent_type) visit_network = personal_dao.getPersonalNetworkVisitedRelation( agent_id=agent_id, agent_type=agent_type) data = formatPersonalNetworkData(agent=agent[0], work_relation=work_network, visit_relation=visit_network) return public_service.returnResult(success=True, data=data)
def recommendResult(town_id=None, com_id="", uni_id="", limit=20): """ 根据传入参数的不同组合,调用不同的处理部分, 返回统一格式的推荐结果 :param town_id: 区镇id, str类型, :param com_id: 企业id, str类型,多个企业id之间以 , 分割, eg:”123,234,345“ :param uni_id: 高校id, str类型,多个id之间以 , 分割, eg:”321,453,465“ :param limit: :return: { success: True or False data: { # 此处使用二维数组存储 nodes, len(nodes) 表示共有多少列节点, len(nodes[i]) 表示 第 i 列有多少节点 nodes:[[{node prop}], [...], ...] links: [{source: xx, target:xxx, others: xxx}, ...] category: [{name: xxx}] } } """ if not isinstance(town_id, str) or 0 == len(town_id): return public_service.returnResult(success=False, message="区镇值不正确") towns = [int(t_id) for t_id in town_id.split(",")] if not isinstance(com_id, str) or 0 == len(com_id): # 未传入 企业参数 或 参数格式不正确 if not isinstance(uni_id, str) or 0 == len(uni_id): # 未传入高校参数 或 参数格式不正确 # ==> 只输入区镇信息, 为特定区域内的企业 推荐 适合合作的高校 return recommendUniversityAndCompany(town_id=towns, limit=limit) else: # 传入高校参数 # ==> 指定地区和高校,推荐适合与当地企业合作的高校 uni_id_list = [int(u_id) for u_id in uni_id.split(",")] return recommendInstitutionAndCompany(town_id=towns, uni_id=uni_id_list, limit=limit) else: # 输入企业 comps = [int(c_id) for c_id in com_id.split(",")] if not isinstance(uni_id, str) or 0 == len(uni_id): # 未传入高校参数 或 参数格式不正确 # ==> 推荐与特定企业相匹配的高校专家团队 # return recommendUniversityForCompany(com_id=comps, limit=limit) # return recommendInstitutionForCompany(com_id=comps, limit=limit) return recommendEngineerAndTeacherTeam2(com_id=comps, limit=limit) else: # ==> 推荐企业工程师和高校专家 uni_id_list = [int(u_id) for u_id in uni_id.split(",")] return recommendEngineerAndTeacherTeam(com_id=comps, uni_id=uni_id_list, limit=limit)
def chartsRiver(teamId=None, teacher=True): """ 获取某个团队的河流图数据 :param teamId: 团队id , :param teacher: 是否是专家团队,布尔型。 :return: { success: True or False, message: xx, data: { legend: [ipc1, ipc2, ...] data: [["2020/1/1", "xx行业" or "IPC", 123], 。。。] } } """ # ==> [{ipc:xxx, patent:xxx, date: 1429142400}, ...]结果中包含重复数据,需要去重 ipc_patent_time = detail_dao.getTeamTechnicalFieldDistribute( team_id=teamId, teacher=teacher) ipc_patent = formatIPC_PatentRelation( ipc_patent_time) # {ipc: {p1,p2,...}, ...}\ # ==> {year: {patent,...}} & {patent: year, ...} year_patent, patent_year = formatYear_PatentRelation(ipc_patent_time) # ==> [{code: xxxx, title: xxx, ipc: xx}, ...] industry_ipc = detail_dao.getIndustryIPC(ipc_patent.keys()) industry_title, ipc_industry = formatIPC_Industry(industry_ipc) # 统计每个行业下专利的数量 ==> {industry_code: {p1, p2, ...}, ...} industry_patent = countIndustryPatent(ipc_industry, ipc_patent) # 取涉及专利最多的 6 个行业 ==> {code1, code2, ...} tmp = sorted(industry_patent.items(), key=lambda kv: len(kv[1]), reverse=True)[:5] industry = {item[0] for item in tmp} legend = [industry_title[code] for code in industry] # ==> {2020: {industry1: 123, industry2: 345,...}, ...} time_industry = dict() max_year, min_year = max(year_patent.keys()), min(year_patent.keys()) for year in range(min_year, max_year + 1): if year not in time_industry: time_industry[year] = dict() industry_year = time_industry[year] for code in industry: patents = industry_patent[code] for patent in patents: if year == patent_year[patent]: if code not in industry_year: industry_year[code] = 1 else: industry_year[code] += 1 res = list() for year, industry_dict in time_industry.items(): for code in industry: num = 0 if code not in industry_dict else industry_dict[code] title = industry_title[code] res.append([str(year + 1), num, title]) return public_service.returnResult(success=True, data={ "legend": legend, "data": res })
def formatResultOfRecommendTeacherForCompany(data, team): """ 将从图数据库中获取的数据格式化为前端可处理的数据格式 """ if 0 == len(data): return public_service.returnResult(success=False, message="未查询到数据") nodes_com, nodes_engineer, nodes_teacher, nodes_uni = list(), list(), list( ), list() links = [] set_node = set() category_list, category_map = list(), dict() for record in data: com_id = "c_%s" % record["c_id"] e_id = "e_%s" % record["e_id"] t_id = "t_%s" % record["t_id"] u_id = "u_%s" % record["u_id"] # 添加企业节点 index_category = addCategory(category_list=category_list, category_map=category_map, node_id=record["c_id"], name=record["c_name"]) addNode(node_set=set_node, node_container=nodes_com, node_id=com_id, category=index_category, label=record["c_name"]) # 添加工程师节点 addNode(node_set=set_node, node_container=nodes_engineer, node_id=e_id, category=index_category, label=record["e_name"]) # 添加工程师与企业的关系 addLinks(links=links, source=com_id, target=e_id, category=index_category) # 添加高校节点 index_category = addCategory(category_list=category_list, category_map=category_map, node_id=record["u_id"], name=record["u_name"]) addNode(node_set=set_node, node_container=nodes_uni, node_id=u_id, category=index_category, label=record["u_name"]) # 添加专家节点 addNode(node_set=set_node, node_container=nodes_teacher, node_id=t_id, category=index_category, label=record["t_name"]) # 添加专家和高校的关系 addLinks(links=links, source=u_id, target=t_id, category=index_category) # 添加工程师与专家的技术领域相似关系 isTeam = "团队" if team else "" similar = '%.2f' % ((1 - record["weight"]) * 100) + "%" weight = "{engineer}{team} - {teacher}{team} " \ "<br> 技术相似度:{similar} ".format(engineer=record["e_name"], team=isTeam, teacher=record["t_name"], similar=similar, category=index_category) addLinks(links=links, source=e_id, target=t_id, weight=weight) result = { "com": nodes_com, "engineer": nodes_engineer, "teacher": nodes_teacher, "uni": nodes_uni } return public_service.returnResult(success=True, data={ "nodes": result, "links": links, "category": category_list })